Элемент управления не обновляет немедленно привязанное свойство с INotifyPropertyChanged - PullRequest
18 голосов
/ 06 декабря 2011

У меня есть элементы управления, которые не обновляют соответствующие свойства своего связанного объекта, пока фокус не будет потерян.Есть похожие вопросы с принятыми ответами, ссылающимися на объявленный DataSourceUpdateMode.OnPropertyChange, который я делаю, но поведение сохраняется.Вот пример реализации.Я постараюсь быть тщательным, но кратким.Доступ к классу MyConfig осуществляется через свойство в классе Singleton, который я называю Configuration.

[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 до Bar в ComboBox, но если я не уберу фокус с ComboBox, ничего не изменится.У кого-нибудь есть идеи?

Ответы [ 2 ]

24 голосов
/ 06 декабря 2011

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();
        }
    }
}
2 голосов
/ 21 мая 2013

@ Николас Пясецкий заслуживает похвалы за то, что привел меня к моему решению, поэтому, если вы не можете прийти к решению на основе его ответа, пожалуйста, проголосуйте за его ответ.


Было три основных изменениячто я должен был сделать, чтобы это исправление работало в моей ситуации.

  • Я пытался получить доступ к свойству объекта, привязанного к свойству SelectedValue ComboBox.Поэтому мне пришлось включить имя свойства «SelectedValue» в предложение Linq where.

  • Если вы устанавливаете привязку данных через конструктор форм в Visual Studio, и просто задаете, чтоSelectedValue или SelectedItem привязаны к, режим обновления источника данных по умолчанию "OnValidation".Это можно увидеть, если перейти к настройкам «(Дополнительно)» для привязки данных в ComboBox.Таким образом, вы должны также включить этот режим обновления источника данных, если вы используете его.

  • В моем случае мне также пришлось вызвать событие OnSelectionChangeCommitted после перебирая привязки и делая вызовы Write / ReadValue.Поскольку я подписывался на событие SelectionChangeCommitted объекта ComboBox в форме, вызывая base.OnSelectionChangeCommit перед циклическим просмотром привязок и заставляя их обновляться, свойство связанного объекта по-прежнему не устанавливалось.

Итак, вот моя версия ответа @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
...