[英]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.