【问题标题】:How to have bindable properties of a UserControl which work with OnPropertyChanged如何拥有与 OnPropertyChanged 一起使用的 UserControl 的可绑定属性
【发布时间】:2011-09-29 03:52:49
【问题描述】:

我有一个带有一些公共属性的简单用户控件(WinForms)。当我使用这个控件时,我想将数据绑定到那些 DataSourceUpdateMode 设置为 OnPropertyChanged 的属性。数据源是一个实现 INotifyPropertyChanged 的​​类。

我知道需要针对属性创建绑定,我正在这样做。

我假设我的用户控件必须实现一个接口,或者属性需要用一些属性或类似的东西来装饰。但我的研究出现了空白。

这应该如何实现?目前,每当属性更改时,我通过在我的用户控件中调用 OnValidating() 来做到这一点,但这似乎不正确。

如果我在用户控件上将 CausesValidation 设置为 true,则可以进行验证,但这对我来说不是很有用。我需要在每个子属性发生变化时对其进行验证。

请注意,这是一种 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()。如果我不这样做,我必须等到焦点更改触发验证,这相当于“OnValidation”更新模式,而不是所需的“OnPropertyUpdate”验证模式。我只是不觉得在更改属性值后调用 OnValidating() 是正确的做法,即使它(有点)有效。

我是否认为调用 OnValidating() 是不是正确的方法?如果是这样,如何通知数据源 ControlProperty 更改?

【问题讨论】:

  • 至少对我来说,这个问题还不清楚......你到底想完成什么?什么(不)起作用?
  • 我觉得你的解释很清楚。就好像你在读我的心似的。我对接口/装饰器有相同的想法,然后考虑调用 OnValidating 方法并且不喜欢这个想法。我想这只是处理复杂主题的本质。我完全理解你想要做什么,因为我正在尝试做同样的事情!

标签: c# .net winforms data-binding user-controls


【解决方案1】:

实现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 实例以将控件属性绑定到源实例(Demo 的实例)上的属性 (DemoField)。

【讨论】:

  • 我已经这样做了,菲尔。正如我所说,“数据源是一个实现 INotifyPropertyChanged 的​​类。”
  • @Charles:不,你不是。 ControlProperty 不会引发 PropertyChanged 事件。
  • @six:Phil 不是在谈论用户控件,而是在谈论数据源类。您是说绑定的双方都必须实现 INotifyPropertyChanged?我认为这只是数据源方面的原因。
  • @Charles:好吧,如果ControlProperty 没有引发事件,怎么会有人知道它发生了变化?
  • 这就是我想知道的。绑定的双方都应该实现 INPC 确实是有道理的,但我所读到的似乎并没有暗示它。另外,我查看了一些现有的控件(按钮、文本框等),它们似乎没有实现 INPC,所以我对绑定如何与它们一起工作感到困惑。
【解决方案2】:

我想我已经弄清楚了。我不明白更改通知是如何从控件发送到绑定数据源的。

是的,调用 OnValidating() 是错误的方式。

根据我的拼凑,控件可以通过两种方式通知数据源属性已更改。

一种方法是让控件实现 INotifyPropertyChanged。我以前从未从控制端这样做过,我认为只有绑定的数据源端必须实现它。

当我在我的用户控件上实现 INotifyPropertyChanged 并在适当的时间引发 PropertyChanged 事件时,它起作用了。

第二种方法是让控件为每个属性引发特定的更改事件。事件必须遵循命名约定:<propertyname>Changed

例如对于我的例子,它会是

public event EventHandler ControlPropertyChanged

如果我的属性名为 Foo,则为 FooChanged

我没有注意到 MSDN documentation 的相关部分,它说:

更改通知发生在 绑定客户端和 数据源,您的绑定类型应该 要么:

实现 INotifyPropertyChanged 接口(首选)。

为每个人提供一个更改事件 绑定类型的属性。

第二种方式是所有现有 WinForms 控件的工作方式,所以我现在就是这样做的。我在我的数据源上使用 INotifyPropertyChanged,但我在我的控件上引发了 Changed 事件。这似乎是传统的方式。

【讨论】:

  • 我希望我能早点看到这个答案。我花了几个小时试图弄清楚为什么数据源没有从用户控件中更新。 +1。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 1970-01-01
  • 1970-01-01
  • 2012-05-23
  • 2017-12-24
相关资源
最近更新 更多