WinForms:在基类

时间:2016-04-29 11:44:15

标签: c# winforms data-binding

我已将我的代码简化为以下重现错误的简短示例。我正在尝试将派生类的值绑定到控件。派生类和绑定逻辑是:

bindingSource = new BindingSource();
numericUpDown1.DataBindings.Add("Value", bindingSource, nameof(SinglePoint.Val), false, DataSourceUpdateMode.OnPropertyChanged);
bindingSource.DataSource = new[] { new SinglePoint(100) };
[...]
public class SinglePoint : PointList
{
    public SinglePoint(int val) { points.Add(val); }
    public int Val
    {
        get { return points[0]; }
        set
        {
            if (value > 300) value = 300; //(*)
            points[0] = value;
        }
    }
}

因此,当在NumericUpDown上设置例如值500时,在离开之后我们应该看到300因为行(*)。如果基类未实现GetHashCode

,则此方法有效
public class PointList
{
    protected List<int> points = new List<int>();
    public PointList() { }
    // UNCOMMENT this and the binding will stop working properly
    //public override int GetHashCode()
    //{
    //    unchecked
    //    {
    //        int hashCode = 17;
    //        foreach (var item in points)
    //            hashCode += 13 * item.GetHashCode();

    //        return hashCode;
    //    }
    //}
}

但是,如果您尝试取消注释GetHashCode实施,则绑定将中断。这意味着在设置500并离开NumericUpDown之后,控件仍将显示500,但实际上基础值将为300.为什么会发生这种情况,如何在不关闭{{{{{ 1}}?

修改

正如你们中的一些人所指出的,GetHashCode不应该改变,因为它被绑定机制使用。这回复了我的问题的第一部分。但是,如何使我的PointList类满足其他rule如果两个相等(Equals(...)== true)那么它们必须为GetHashCode()返回相同的值”。如果我有两个具有相同列表(序列)点的GetHashCode个对象,我希望它们相等(因为我的代码中的其他逻辑),这应该意味着具有相同的哈希码。你会怎么做?

3 个答案:

答案 0 :(得分:3)

Thumb规则:

  

GetHashCode 返回的整数必须永远不会更改,而对象包含在依赖于哈希代码保持稳定的数据结构中

见Eric Lippert的文章here

GetHashCode中,您应该只使用只读或不可变字段;否则,该对象不能用于DictionaryHashtable和其他基于散列的集合。

答案 1 :(得分:3)

WinForms使用数据对象和数据成员的哈希码生成密钥,该密钥用于跟踪内部存储中的数据绑定对象。如果更改哈希计算以便在数据成员更改值时哈希更改,则先前生成的密钥不会随之更新,因此与当前密钥不同。这打破了数据绑定机制。

来源:http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/BindingContext.cs

答案 2 :(得分:0)

您应该使用base.GetHashCode()初始化哈希码,而不是将哈希码初始化为17。 int hashCode = base.GetHashCode(); //不是17