【问题标题】:Simple-bound .NET data binding not working简单绑定的 .NET 数据绑定不起作用
【发布时间】:2012-02-22 20:47:53
【问题描述】:

技术:.NET 4、C#、WinForms、Visual Studio 2010

我正在学习数据绑定,甚至无法让一个简单的示例按预期工作。我有一个带有我要绑定的标签的表单,它显示了当前的鼠标光标坐标。

public partial class Form1 : Form, INotifyPropertyChanged
{
    [Bindable(true)]
    private String cursorPosition;
    public String CursorPosition
    {
        get
        {
            return cursorPosition;
        }

        set
        {
            cursorPosition = value;
            NotifyPropertyChanged("CursorPosition");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        CursorPosition = "(" + Convert.ToString(e.X) + " , " + Convert.ToString(e.Y) + ")";
    }

    private void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    } 
}

从设计器中,我设置了标签的数据绑定以将 Text 属性绑定到 form1BindingSource - CursorPosition。我错过了什么?

编辑:更新了代码 sn-p。

【问题讨论】:

    标签: c# .net winforms data-binding


    【解决方案1】:

    在设计器中,我设置了标签的数据绑定以将 Text 属性绑定到 form1BindingSource - CursorPosition。我错过了什么?

    你设置了吗:

    form1BindingSource.DataSource = this;  // (or whatever the real data source is)
    

    例如在表单的构造函数中,InitializeComponent? 之后

    (假设您的 Form1 实例是数据源,并且您通过 BindingSource 将控件绑定到它。)


    一些更详细的建议:

    1. 选择表单本身作为数据源有点不寻常。恕我直言,最好将所有绑定到的属性分成一个单独的非 UI 数据对象。然后,您可以为 INotifyPropertyChanged 实现创建可重用的基类型。

    2. 正如@rfmodulator 在他的回答中所说,BindableAttribute 已附加到该字段:

      [Bindable(true)]
      private String cursorPosition;
      public String CursorPosition
      …
      

      您可能打算将其附加到属性:

      private String cursorPosition;
      [Bindable(true)]
      public String CursorPosition
      …
      
    3. 您的 setter 应该如下所示:

      set
      {
          if (!string.Equals(cursorPosition, value)      // +
          {                                              // +
              cursorPosition = value;
              NotifyPropertyChanged("CursorPosition");
          }                                              // +
      }
      

      也就是说,只有在属性值实际发生变化时才引发PropertyChanged 事件。

    4. 您可能希望将您的 NotifyPropertyChanged 方法更改为:

      private void NotifyPropertyChanged(String propertyName)
      {
          PropertyChangedEventHandler handler = PropertyChanged;          // +
          if (handler != null)                                            // ~
          {
              handler(this, new PropertyChangedEventArgs(propertyName));  // ~
          }
      }
      

      这是因为PropertyChanged 可以理论上null 检查和调用之间发生变化。您可以通过创建事件委托的本地副本来排除这种理论上的可能性。

      P.S.:确切地说,正如 Jeffrey Richter 在他的“通过 C# 的 CLR”一书中指出的那样,局部变量仍然不够:理想情况下,您应该将 Interlocked.CompareExchange(ref PropertyChanged, null, null) 分配给 handler(而不是PropertyChanged) 因为使用该方法会阻止 JIT 代码生成器优化局部变量 (IIRC)。

    【讨论】:

    • 谢谢!没有设置 DataSource 是我所缺少的,我不记得在任何文档中看到过它。我确实按照您的建议将非视图代码重构为适当的控制器。我同意你的新 setter 和 NotifyPropertyChanged 方法要好得多。
    【解决方案2】:

    我假设您希望触发 PropertyChanged 事件?您在 Mouse_Move 中设置支持变量的值,而不是属性的值。因此,不会调用对 NotifyPropertyChanged 的​​调用。

    【讨论】:

    • 好收获。我已更新代码以反映更改,但标签仍未更新。
    • 我会在调用 NotifyPropertyChanged 时检查 PropertyChanged 是否有值。
    • 不,它没有——它是空的。我不明白它在哪里初始化。我在 MSDN (msdn.microsoft.com/en-us/library/ms229614.aspx) 上找到的参考资料与我的代码相同。
    • 我想知道将表单本身作为数据对象是否会以某种方式将其丢弃。但我也注意到了这个页面的第三点,here。它表明对于每个更改的属性,您都需要一个“PropertyNameChanged”事件。所以——如果我解释正确的话——你还需要一个 CursorPositionChanged 事件。
    • @Ann L.:Winforms 数据绑定支持多种更改通知机制,即使它们混合在一起。 INotifyPropertyChanged PropertyNameChanged 就足够了。 @Noren,您实际上是否将.DataSource 设置为表单?看我的回答。
    【解决方案3】:

    您不应在 componentscontrolsforms 上实现 INotifyPropertyChanged,因为数据绑定将依赖 XXXChanged 事件范例来侦听更改通知。在内部,数据绑定使用property descriptors 来侦听更改事件。它们暗示该类如何检测PropertyDescriptor.SupportsChangeEvents property 文档中的更改。这与 winforms 数据绑定的历史有关。 XXXChanged 是在 .NET 2.0 之前进行数据绑定和更改通知的方式。 INotifyPropertyChanged 是在 2.0 中引入的,以支持 XXXChanged 模式。

    SupportsChangeEvents 属性指示此属性的值更改通知是否可能源自属性描述符外部,例如来自组件本身,或者通知是否仅源自对 SetValue 方法的直接调用。例如,组件可能实现了 INotifyPropertyChanged 接口,或者可能为此属性有一个显式的 nameChanged 事件。

    【讨论】:

      【解决方案4】:

      您正在字段上设置Bindable 属性,但调用NotifyPropertyChanged 并使用该属性作为参数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-03
        • 1970-01-01
        • 1970-01-01
        • 2015-11-06
        • 1970-01-01
        • 1970-01-01
        • 2013-07-07
        • 1970-01-01
        相关资源
        最近更新 更多