[英]Prevent ValueChanged execution while ViewModel is being initialized
[英]How to prevent PropertyChanged from firing while controls are being initialized
這個問題已經引起了一段時間的麻煩,並且阻止了項目的進展。 考慮一個WPF XAML表單,其中包含綁定到ViewModel的控件。 (我正在使用Caliburn.Micro MVVM框架和Entity Framework來獲取數據)。 shell調用Initialize()
方法從數據庫加載表單的數據並設置PropertyChanged事件處理程序。 有一個IsDirty
標志,用於跟蹤表單中是否有更改的數據。 有一個“保存”按鈕綁定到IsDirty
屬性,以便在數據更改時啟用它。
// Sample code; forms have many controls....
// this is the property that the controls are bound to
public Entity BoundData { get; set; }
public void Initialize()
{
// this is an example line where I query the database from the Entity Framework ObjectContext...
BoundData = objectContext.DataTable.Where(entity => entity.ID == 1).SingleOrDefault();
// this is to cause the form bindings to retrieve data from the BoundData entity
NotifyOfPropertyChange("BoundData");
// wire up the PropertyChanged event handler
BoundData.PropertyChanged += BoundData_PropertyChanged;
IsDirty = false;
}
void BoundData_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
IsDirty = true;
}
// implementation of the IsDirty flag
public bool IsDirty
{
get
{
return _isDirty;
}
set
{
_isDirty = value;
NotifyOfPropertyChange("IsDirty");
}
}
問題是,由於在Initialize()
方法完成后從數據庫初始化表單,因此BoundData_PropertyChanged
了BoundData_PropertyChanged
事件處理程序。 因此, IsDirty
標志設置為true,並且啟用了“保存”按鈕,即使表單剛剛加載且用戶沒有更改任何內容。 我錯過了什么? 當然這是一個常見的問題,但我一直無法找到一個好的解決方案。 這是我的第一個MVVM項目,所以我完全有可能錯過一些基本概念。
更新:為了澄清,我認為問題是我需要能夠掛鈎一個事件或回調,當所有綁定都完成更新時將觸發,因此我可以連接PropertyChanged事件處理程序。
您可以做的一件事可能有幫助,就是設置觸發更改的屬性,如下所示:
public virtual bool Prop1
{
get
{
return _prop1;
}
set
{
if (_prop1 != value)
{
_prop1 = value;
NotifyOfPropertyChange("IsDirty");
}
}
這樣,只有在實際更改了值時才會觸發事件,而不僅僅是冗余設置。 這當然假設在您的情況下該值實際上沒有變化。
我建議你設計一個通用的方法調用。 就像ValueChanged
事件處理程序(自定義事件處理程序),它反過來調用BoundData_PropertyChanged。 這意味着,只要控件發生更改,就可以調用此ValueChanged方法/處理程序。
例如
void ValueChanged(object sender, EventArgs e)
{
BoundData_PropertyChanged();
}
textBox.TextChanged += new System.EventHandler(ValueChanged);
語法可能不准確,但你可以猜到我在這里提出的建議。
這個解決方案可能不是絕對可靠的,但它在我使用的有限測試用例中對我有用。
在第一次輸入時,EntityKey值將為null。 檢查一下。
/// <summary>
/// Log the invoice status change
/// </summary>
/// <param name="value">The value that the invoice status is changing to</param>
partial void OnInvoiceStatusValueChanging(string value)
{
var newStatus = ConvertInvoiceStatus(value);
if (this.EntityKey != null && InvoiceStatus != newStatus)
{
AddNewNote(string.Format("Invoice status changing from [{0}] to [{1}]", InvoiceStatus.GetDescription(), newStatus.GetDescription()));
}
}
/// <summary>
/// Log the invoice status change
/// </summary>
partial void OnInvoiceStatusValueChanged()
{
if (this.EntityKey != null)
AddNewNote(string.Format("Invoice status changed to [{0}]", InvoiceStatus.GetDescription()));
}
我知道這個問題很古老,但我遇到了同樣的問題,很難搞清楚。 我是WPF / MVVM的新手,可能不知道谷歌或者問的正確的事情。 這是我的解決方案。 希望它可以幫助某人。
我的IsDirty標志幾乎與原帖中的標志相同。 唯一的區別是我在視圖完成渲染時添加了一個命令將其重置為false。 當呈現/實例化View時 ,基本思想來自Notify ViewModel
在視圖中觸發Loaded事件:
<UserControl x:Class="MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding Path=OnLoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
然后在視圖模型中,在事件觸發時將IsDirty標志設置為false。
public ICommand OnLoadedCommand { get; private set; }
// Constructor
public MyUserControlViewModel()
{
OnLoadedCommand = new DelegateCommand(OnLoaded);
}
public void OnLoaded()
{
// Ignore any PropertyChanged events that fire
// before the UserControl is rendered.
IsDirty = false;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.