在名为Property的属性上进行数据绑定时,Windows窗体上出现故障

时间:2014-04-09 14:44:26

标签: c# winforms data-binding

我在Windows窗体中试验数据绑定,发现了一个我无法解释的故障。我在这里发布这个问题,希望社区中的某个人能够提出一个有意义的答案。

我尝试了一种巧妙的方法来绑定依赖于对其他值的操作的只读值,并在依赖值更改时自动更新它。

我创建了一个包含3个文本框的表单,我希望前2个的总和出现在第3个文本框中。

以下代码应该有效,但不是,至少不正确:

public class Model : INotifyPropertyChanged
{
    private int m_valueA;
    private int m_valueB;

    public int ValueA
    {
        get { return m_valueA; }
        set { m_valueA = value; RaisePropertyChanged("ValueA"); }
    }

    public int ValueB
    {
        get { return m_valueB; }
        set { m_valueB = value; RaisePropertyChanged("ValueB"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class DynamicBindingProperty<T> : INotifyPropertyChanged
{
    private Func<T> m_function;
    private HashSet<string> m_properties;

    public DynamicBindingProperty(Func<T> function, INotifyPropertyChanged container, IEnumerable<string> properties)
    {
        m_function = function;
        m_properties = new HashSet<string>(properties);
        container.PropertyChanged += DynamicBindingProperty_PropertyChanged;
    }

    public T Property { get { return m_function(); } }

    void DynamicBindingProperty_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (!m_properties.Contains(e.PropertyName)) return;
        if (PropertyChanged == null) return;
        PropertyChanged(this, new PropertyChangedEventArgs("Property"));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        InitializeDataBinding();
    }

    private void InitializeDataBinding()
    {
        Model model = new Model();
        DynamicBindingProperty<int> tmp = new DynamicBindingProperty<int>(() => model.ValueA + model.ValueB, model, new[] {"ValueA", "ValueB"});

        textBox1.DataBindings.Add("Text", model, "ValueA");
        textBox2.DataBindings.Add("Text", model, "ValueB");
        textBox3.DataBindings.Add("Text", tmp, "Property");

        tmp.PropertyChanged += (sender, args) => Console.WriteLine(args.PropertyName);
    }
}

经过一段时间的实验,我尝试将DynamicBindingProperty&lt; T&gt; .Property重命名为其他东西(例如DynamicProperty),一切按预期工作!。现在,我期望通过将Model.ValueA重命名为Property来打破某些东西,但它没有,并且仍然完美无缺。

这里发生了什么?

1 个答案:

答案 0 :(得分:2)

我做了一些调试,它看起来像一个bug(或要求“该属性不能被命名为Property”我不知道)。如果你替换

PropertyChanged(this, new PropertyChangedEventArgs("Property"));

PropertyChanged(this, new PropertyChangedEventArgs(null));

它仍然不起作用 - null或空字符串表示任何属性可能已更改。这表明问题不在于处理更改通知,而是未正确建立绑定。

如果您将第二个属性Property2添加到DynamicBindingProperty<T>并与Property相同并将其绑定到第四个文本框,那么两个文本框如果您使用空字符串null"Property2"执行更改通知,则会正确更新。如果您使用"Property" 执行更改通知,文本框将正确更新。这表明对Property的绑定没有完全破坏,并且更改通知也有些破坏。

可悲的是,我无法确定出错的确切位置,但如果你投入足够的时间逐步完成优化的框架源代码,你可能会想出来。属性名称为Property的案例与属性名称为Property2的案例之间的最早差异我可以确定何时处理更改通知位于内部类OnValueChanged()的{​​{1}}中。在一种情况下,在另一种情况下跳过基础实现被调用 - 至少如果调试器没有欺骗我,但在优化代码中很难说明。