[英]Control not immediately updating bound property with INotifyPropertyChanged
我有控件在焦点丢失之前不更新绑定对象的相应属性。 关于正在声明的DataSourceUpdateMode.OnPropertyChange
引用的答案也有类似的问题,我这样做,但行为仍然存在。 这是一个示例实现。 我会尽量彻底,但要简洁。 MyConfig
类是通过我调用Configuration
的Singleton类中的属性访问的。
[Serializable]
public class MyConfig : INotifyPropertyChanged
{
public enum MyEnum
{
Foo,
Bar
}
public MyConfig()
{
MyProperty = MyEnum.Foo;
}
private MyEnum _MyProperty;
public MyEnum MyProperty
{
get { return _MyProperty; }
set { if (value != _MyProperty) { _MyProperty = value; OnPropertyChanged("MyProperty"); } }
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
throw new ArgumentNullException(propertyName);
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public partial class ConfigForm : Form
{
public ConfigForm()
{
InitializeComponent();
MyComboBox.Items.AddRange(Enum.GetNames(typeof(MyConfig.MyEnum)));
}
private void ConfigForm_Load(object sender, EventArgs e)
{
MyComboBox.DataSource = Enum.GetValues(typeof(MyConfig.MyEnum));
MyComboBox.DataBindings.Add("SelectedItem", Configuration.Instance.MyConfig, "MyProperty", false, DataSourceUpdateMode.OnPropertyChanged);
}
}
鉴于以下简要实施,我不确定我可以忽视什么以确保立即改变财产。 我可以改变,在这种情况下,从Foo
到ComboBox中的Bar
,但除非我从ComboBox中删除焦点,否则没有任何变化。 有没有人有任何想法?
关于OnPropertyChanged
,WinForms ComboBox
很OnPropertyChanged
。 这里是一些旧项目的代码,我曾经以OnPropertyChanged
的方式运行我对SelectedItem
属性的期望。 这适用于我的具体实例,但我通常很难让这种情况有时起作用。 祝好运!
/// <summary>
/// A modification of the standard <see cref="ComboBox"/> in which a data binding
/// on the SelectedItem property with the update mode set to DataSourceUpdateMode.OnPropertyChanged
/// actually updates when a selection is made in the combobox.
/// </summary>
public class BindableComboBox : ComboBox
{
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.ComboBox.SelectionChangeCommitted"/> event.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnSelectionChangeCommitted(EventArgs e)
{
base.OnSelectionChangeCommitted(e);
var bindings = this.DataBindings
.Cast<Binding>()
.Where(x =>
x.PropertyName == "SelectedItem" &&
x.DataSourceUpdateMode == DataSourceUpdateMode.OnPropertyChanged);
foreach (var binding in bindings)
{
// Force the binding to update from the new SelectedItem
binding.WriteValue();
// Force the Textbox to update from the binding
binding.ReadValue();
}
}
}
@Nicholas Piasecki因为引导我找到我的解决方案而值得称赞,除非你根据他的回答找不到解决方案,否则请投票给他答案。
在我的情况下,我必须为此修复程序进行三项主要更改。
我试图访问绑定到ComboBox的SelectedValue属性的对象的属性。 因此,我必须在Linq where子句中包含“SelectedValue”属性名称。
如果您通过Visual Studio中的表单设计器设置数据绑定,并只是设置SelectedValue或SelectedItem绑定的内容,则默认数据源更新模式为“OnValidation”。 如果您转到ComboBox上的数据绑定的“(高级)”设置,则可以看到此信息。 因此,您必须包含该数据源更新模式,如果您正在使用它。
在我的情况下,我还必须在循环绑定并执行Write / ReadValue调用之后引发OnSelectionChangeCommitted事件。 由于我在表单上订阅了ComboBox的SelectionChangeCommitted事件,因此在循环绑定并强制它们更新之前调用base.OnSelectionChangeCommitted导致绑定对象的属性仍未设置。
所以,这是我的@Nicholas Piasecki的答案(也转换为VB.NET):
''' <summary>
''' Raises the <see cref="E:System.Windows.Forms.ComboBox.SelectionChangeCommitted"/> event _after_ forcing any data bindings to be updated.
''' </summary>
''' <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
Protected Overrides Sub OnSelectionChangeCommitted(e As EventArgs)
Dim bindings As List(Of Binding) = ( _
From x In Me.DataBindings.Cast(Of Binding)()
Where (x.PropertyName = "SelectedItem" OrElse x.PropertyName = "SelectedValue" OrElse x.PropertyName = "SelectedIndex") AndAlso
(x.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged OrElse x.DataSourceUpdateMode = DataSourceUpdateMode.OnValidation)
).ToList()
For Each b As Binding In bindings
' Force the binding to update from the new SelectedItem
b.WriteValue()
' Force the Textbox to update from the binding
b.ReadValue()
Next
MyBase.OnSelectionChangeCommitted(e)
End Sub
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.