使用 GetBindingExpression().UpdateTarget() 强制更新所有 WPF 绑定控件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21094019/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Forcing all WPF bound controls to update with GetBindingExpression().UpdateTarget()
提问by bmt22033
I have a WPF application that includes ~50 controls that are bound to properties on my business object which implements INotifyPropertyChanged. Here's a quick snippet of my business object:
我有一个 WPF 应用程序,其中包含约 50 个控件,这些控件绑定到实现 INotifyPropertyChanged 的业务对象上的属性。这是我的业务对象的快速片段:
public class MyBusinessObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
// properties begin here
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
{
return;
}
_name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
// constructor, etc. not shown
}
I also have several validation rules that are used to validate the user input in these controls. I'm using command binding to prevent my user from saving the data if there are any validation errors. My application also includes a "Reset default values" button which, obviously, will reset the default value for all of the properties on my business object. This all works exactly as I'd like it to with one exception. If my user enters invalid data into one or more controls and then clicks the "Reset default values" button, the controls that contain invalid data don't always update as I'd expect. This happens because of the following code in my property setters:
我还有几个验证规则用于验证这些控件中的用户输入。如果出现任何验证错误,我正在使用命令绑定来防止我的用户保存数据。我的应用程序还包括一个“重置默认值”按钮,显然,它将重置我的业务对象上所有属性的默认值。除了一个例外,这一切都完全按照我的意愿工作。如果我的用户将无效数据输入到一个或多个控件中,然后单击“重置默认值”按钮,则包含无效数据的控件并不总是如我所愿地更新。这是因为我的属性设置器中有以下代码:
if (_name == value)
{
return;
}
This code exists to prevent unnecessary property changed notifications from occurring when the value entered by my user in the bound UI control is the same value that the property is already set to. As an example, I have an IntegerUpDown control in my UI (this control is part of the Extended WPF Toolkit from Xceed). The default value of the property that my control is bound to is 10. My user deletes the value from the control and my validation rule is triggered which results in a validation error and the UI is updated appropriately with an error adorner, etc. The value of the property that this control is mapped to hasn't been changed so it's still set to 10. Now my user clicks the "Reset default values" button which will result in the default value (10) for the property being reset. However, the value for the property is alreadyset to 10 so the short circuit logic in my setter will return instead of setting the property value.
当我的用户在绑定 UI 控件中输入的值与该属性已设置的值相同时,此代码可防止发生不必要的属性更改通知。例如,我的 UI 中有一个 IntegerUpDown 控件(该控件是 Xceed 的扩展 WPF 工具包的一部分)。我的控件绑定到的属性的默认值是 10。我的用户从控件中删除了该值,并触发了我的验证规则,这会导致验证错误,并且 UI 会使用错误装饰器等进行适当更新。该值此控件映射到的属性的未更改,因此它仍设置为 10。现在我的用户单击“重置默认值”按钮,这将导致重置属性的默认值 (10)。但是,该物业的价值是已经设置为 10,所以我的 setter 中的短路逻辑将返回而不是设置属性值。
So now, after my user clicks "Reset default values", I am also forcing an update on my binding target like this:
所以现在,在我的用户单击“重置默认值”后,我还强制更新我的绑定目标,如下所示:
this.myIntegerUpDown.GetBindingExpression(Xceed.Wpf.Toolkit.IntegerUpDown.ValueProperty).UpdateTarget();
This solves my problem but only for this particular control. Is there any easy way to do this for allof my bound controls without having to specify each one? Thanks.
这解决了我的问题,但仅针对此特定控件。有没有什么简单的方法可以为我的所有绑定控件执行此操作而无需指定每个控件?谢谢。
回答by Charles Mager
OnPropertyChanged(new PropertyChangedEventArgs(string.Empty));
OnPropertyChanged(new PropertyChangedEventArgs(string.Empty));
This is intended to imply that ALL properties on that object have changed.
这旨在暗示该对象上的所有属性都已更改。
回答by Matt
Could you do one of the following?
您可以执行以下操作之一吗?
1) Reset the DataContext- Either recreate it, or re-set the property
1)重置DataContext- 重新创建它,或重新设置属性
var context = this.DataContext;
this.DataContext = null;
this.DataContext = context;
2) Loop through all properties programmatically via reflection and manually call OnPropertyChangedwith the relevant property names.
2) 通过反射OnPropertyChanged以编程方式循环遍历所有属性,并使用相关属性名称手动调用。
var properties = typeof(ViewModel).GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(property.Name));
}
回答by 123 456 789 0
You've mentioned validation and reset values, and of course the obvious one is to persist it.
您已经提到了验证和重置值,当然显而易见的是要坚持它。
Why don't you implement IEditableObject Interfaceon your entity that has three signature methods. BeginEdit(), CancelEdit() and EndEdit()
为什么不在具有三个签名方法的实体上实现IEditableObject 接口。开始编辑()、取消编辑() 和结束编辑()
That way you can easily roll back your entity to the whatever you want, or validate it and lastly persist it. A good example is found here
这样您就可以轻松地将您的实体回滚到您想要的任何内容,或者对其进行验证并最终保留它。一个很好的例子在这里找到
Sample code
示例代码
public class Customer : IEditableObject
{
struct CustomerData
{
internal string id ;
internal string firstName ;
internal string lastName ;
}
private CustomersList parent;
private CustomerData custData;
private CustomerData backupData;
private bool inTxn = false;
// Implements IEditableObject
void IEditableObject.BeginEdit()
{
Console.WriteLine("Start BeginEdit");
if (!inTxn)
{
this.backupData = custData;
inTxn = true;
Console.WriteLine("BeginEdit - " + this.backupData.lastName);
}
Console.WriteLine("End BeginEdit");
}
void IEditableObject.CancelEdit()
{
Console.WriteLine("Start CancelEdit");
if (inTxn)
{
this.custData = backupData;
inTxn = false;
Console.WriteLine("CancelEdit - " + this.custData.lastName);
}
Console.WriteLine("End CancelEdit");
}
void IEditableObject.EndEdit()
{
Console.WriteLine("Start EndEdit" + this.custData.id + this.custData.lastName);
if (inTxn)
{
backupData = new CustomerData();
inTxn = false;
Console.WriteLine("Done EndEdit - " + this.custData.id + this.custData.lastName);
}
Console.WriteLine("End EndEdit");
}
public Customer(string ID) : base()
{
this.custData = new CustomerData();
this.custData.id = ID;
this.custData.firstName = "";
this.custData.lastName = "";
}
public string ID
{
get
{
return this.custData.id;
}
}
public string FirstName
{
get
{
return this.custData.firstName;
}
set
{
this.custData.firstName = value;
this.OnCustomerChanged();
}
}
public string LastName
{
get
{
return this.custData.lastName;
}
set
{
this.custData.lastName = value;
this.OnCustomerChanged();
}
}
internal CustomersList Parent
{
get
{
return parent;
}
set
{
parent = value ;
}
}
private void OnCustomerChanged()
{
if (!inTxn && Parent != null)
{
Parent.CustomerChanged(this);
}
}
public override string ToString()
{
StringWriter sb = new StringWriter();
sb.Write(this.FirstName);
sb.Write(" ");
sb.Write(this.LastName);
return sb.ToString();
}
}
回答by TylerD87
Wouldn't it be easier to just always call OnPropertyChanged regardless of whether its the same? How much of a performance boost does that give you?
无论是否相同,始终调用 OnPropertyChanged 不是更容易吗?这会给您带来多少性能提升?

