Как иметь связанные свойства UserControl, которые работают с OnPropertyChanged
У меня есть простой пользовательский контроль (WinForms) с некоторыми общедоступными свойствами. Когда я использую этот элемент управления, я хочу привязать данные к этим свойствам с помощью параметра DataSourceUpdateMode, установленного в OnPropertyChanged. Источник данных - это класс, который реализует INotifyPropertyChanged.
Я знаю о необходимости создания привязок к свойствам, и я это делаю.
Я предположил, что мой пользовательский контроль должен будет реализовать интерфейс, или свойства должны быть украшены каким-то атрибутом или что-то в этом роде. Но мои исследования стали пустым.
Как это должно быть достигнуто? На данный момент я делаю это, вызывая OnValidating() в моем usercontrol всякий раз, когда свойство изменяется, но это кажется неправильным.
Я могу получить подтверждение, если я установлю CausesValidation на true в usercontrol, но это не очень полезно для меня. Мне нужно проверить каждое дочернее свойство по мере его изменения.
Обратите внимание, что это ситуация WinForms.
РЕДАКТИРОВАТЬ: Очевидно, у меня нет таланта для объяснения, поэтому, надеюсь, это прояснит, что я делаю. Это сокращенный пример:
// I have a user control
public class MyControl : UserControl
{
// I'm binding to this property
public string ControlProperty { get; set; }
public void DoSomething()
{
// when the property value changes, the change should immediately be applied
// to the bound datasource
ControlProperty = "new value";
// This is how I make it work, but it seems wrong
OnValidating();
}
}
// the class being bound to the usercontrol
public class MyDataSource : INotifyPropertyChanged
{
private string sourceProperty;
public string SourceProperty
{
get { return sourceProperty; }
set
{
if (value != sourceProperty)
{
sourceProperty = value;
NotifyPropertyChanged("SourceProperty");
}
}
}
// boilerplate stuff
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public class MyForm : Form
{
private MyControl myControl;
public MyForm()
{
// create the datasource
var dataSource = new MyDataSource() { SourceProperty = "test" };
// bind a property of the datasource to a property of the usercontrol
myControl.DataBindings.Add("ControlProperty", dataSource, "SourceProperty",
false, DataSourceUpdateMode.OnPropertyChanged); // note the update mode
}
}
(Я пробовал это с использованием BindingSource, но результат был тот же.)
Теперь я хочу, чтобы при изменении значения MyControl.ControlProperty это изменение немедленно распространилось на источник данных (экземпляр MyDataSource). Для этого я вызываю OnValidating() в usercontrol после изменения свойства. Если я этого не делаю, мне нужно подождать, пока проверка не будет вызвана изменением фокуса, что эквивалентно режиму обновления OnValidation, а не желаемому режиму проверки OnPropertyUpdate. Мне просто не хочется называть OnValidating() после изменения значения свойства - это правильная вещь, даже если она (вид) работает.
Действительно ли я предполагаю, что вызов OnValidating() - это не правильный способ сделать это? Если да, то как я могу уведомить источник данных об изменении ControlProperty?
Ответы
Ответ 1
Думаю, я понял это. Я не понял, как уведомления об изменениях были отправлены из управления в связанный источник данных.
Да, вызов OnValidating() - неправильный путь.
Из того, что я собрал вместе, есть два способа, которыми элемент управления может уведомлять источник данных о том, что свойство изменилось.
Один из способов - реализовать элемент управления INotifyPropertyChanged. Я никогда не делал этого с контрольной стороны раньше, и я думал, что только сторона источника данных должна была его реализовать.
Когда я выполнил INotifyPropertyChanged в моем пользовательском элементе управления и поднял событие PropertyChanged в соответствующее время, он сработал.
Второй способ заключается в том, чтобы элемент управления мог поднять конкретное событие изменения для каждого свойства. Событие должно соответствовать соглашению об именах: <propertyname>Changed
например. для моего примера это будет
public event EventHandler ControlPropertyChanged
Если мое свойство было вызвано Foo, оно было бы FooChanged
.
Я не заметил заметную часть документации MSDN где говорится:
Для уведомления об изменении в привязка между связанным клиентом и источника данных, ваш связанный тип должен либо:
Внедрить INotifyPropertyChanged интерфейс (предпочтительный).
Предоставить событие изменения для каждого свойство связанного типа.
Этот второй способ заключается в том, как работают все существующие средства управления WinForms, так вот как я это делаю сейчас. Я использую INotifyPropertyChanged на моем источнике данных, но я поднимаю события Changed на свой контроль. Это кажется обычным способом.
Ответ 2
Реализация интерфейса INotifyPropertyChanged очень проста. Вот пример, который показывает объект с одним открытым полем...
public class Demo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
private string _demoField;
public string DemoField
{
get {return demoField; }
set
{
if (value != demoField)
{
demoField = value;
NotifyPropertyChanged("DemoField");
}
}
}
}
Затем вы создадите экземпляр Binding для привязки свойства управления к свойству (DemoField) в исходном экземпляре (экземпляр Demo).