在的WinForms为什么会覆盖.GetHash code清除这些数据绑定值?定值、数据、WinForms、GetHash

2023-09-09 21:02:30 作者:厚底啤酒瓶

我们遇到了,我们遇到了问题,调试一个奇怪的错误。

We have run into a strange bug that we're having problems debugging.

我们有一个使用微软CAB,DevEx preSS组件和.Net 3.5 MDI工作区。

We have a MDI workspace that uses Microsoft CAB, DevExpress components, and .Net 3.5.

如果在工作区中的用户打开两个窗口,每个包含用户控件绑定到两个不同的数据模型,然后最小化他们两个,第一个窗口最小化是得到它的当第二个最小化绑定字段清除。

If users open two windows in the workspace that each contain a UserControl bound to two separate data models, then minimize both of them, the first window to minimize is getting it's bound fields cleared when the second one minimizes.

.Equals .GetHash code 数据模型的方法已经这样既覆盖数据模型被认为是相等的。如果我们改变所以他们是独一无二的,我们没有得到这种行为。

The .Equals and .GetHashCode methods of the data model have been overridden so that both data models are considered equal. If we change that so they are unique, we do not get this behavior.

下面是一些例子伪code显示问题

Here's some example pseudocode showing the problem

var a = new MyWindow();
a.DataModel = new SomeClass(123);
a.ShowInMdiWorkspace();

var b = new MyWindow();
b.DataModel = new SomeClass(123);
b.ShowInMdiWorksace();

a.Minimize();

// If SomeClass.GetHashCode() is overwritten to consider two objects  
// as equal based on the value passed in, then the data bindings for A
// get cleared on this call. If SomeClass.GetHashCode is unique, then 
// this problem does not happen.
b.Minimize();

下面的调用堆栈时,第二个窗口被最小化的:

Here's the Call Stack when the second window gets minimized:

在上面的堆栈跟踪的 EndEditSession()调用,它调用 EndEditSession 的第二个的窗口最小化,而由当时的堆栈跟踪获取过去 [外部code] 到的OnChange断点我已经设置,它被烧成在变革方法的第一的窗口。

At the EndEditSession() call in the stack trace above, it is calling EndEditSession for the second window minimized, while by the time the Stack Trace gets past the [External Code] to the OnChange breakpoint I have set, it is firing the change method in the first window.

EndEditSession()是自定义的东西,我们已经实现了它看起来像这样

EndEditSession() is something custom we have implemented which looks something like this

protected void EndEditSession()
{
    IBindingValue bv = null;

    if (_bindingValues == null)
        return;

    if (_data != null)
    {
        foreach (KeyValuePair<string, IBindingValue> kvp in _bindingValues)
        {
            bv = kvp.Value;
            if (bv.IsBindable)
                ((PropertyManager)bv.Component.BindingContext[_data]).EndCurrentEdit();
        }
    }

}

_bindingValues​​ 被填充当用户控件初始化其数据绑定。密钥字段绑定控件的名称,值字段是存储有控制本身,它的名称,绑定值和默认值的定义对象。 bv.Component 返回控件的绑定设置,这在我的测试的情况下是一个定制的DevEx preSS LookupEdit

_bindingValues gets populated when the UserControl initializes its data bindings. The key fields are the name of the bound control, and the value fields are a custom object which stores the control itself, its name, its bound value, and default value. bv.Component returns the control that the binding is set on, which in the case of my testing is a customized DevExpress LookupEdit

_data 包含了数据模型中的用户控件,我可以验证它被设置为实例第二个窗口。

_data contains the data model for the UserControl, and I can verify that it is set to the instance for the second window.

我最初的想法是,的BindingContext 被共享,错 PropertyManager中正在恢复,但我已经验证该 .BindingContext 两个窗体和控件是分开的。

My original thought was that the BindingContext was shared so the wrong PropertyManager was being returned, however I have verified that the .BindingContext for the two forms and controls are separate.

有没有可能有两个单独的副本用户控件绑定到数据模型将得到其绑定混了两个独立的情况下,当 GetHash code 方法已被重写,以使两个对象被视为相等?

Is it possible that having two separate copies of a UserControl bound to two separate instances of a data model would get its bindings mixed up when the GetHashCode method has been overridden so that the two objects are considered equal?

我不是很熟悉的WinForms的内部工作系统的结合,或者究竟如何CAB的MDI工作区被管理的。

I am not very familiar with the inner workings of the WinForms binding system, or with exactly how CAB's MDI workspace gets managed.

我的理论是当第一窗口最小化,它被卸载的控制,以节省存储器,则当所述第二窗口最小化内部哈希表,管理被错误地感到困惑和运行的更新才能从数据的绑定第一个最小化的窗口(也就是现在的空白),并更新其数据源。有很多孔的这一理论,但它是我唯一能想到的。

My theory is that when the first window minimizes, it is unloading the controls to save on memory, then when the second window minimizes the internal hash table that manages the bindings is incorrectly getting confused and running an update to take data from the first minimized window (which is now blank) and updating its datasource. There are plenty of holes in this theory, however its the only thing I can think of.

推荐答案

我不知道内部工作的WinForm控件,但似乎因为你所遇到的一个问题是覆盖等于你会更好的工作围绕。

I don't know the internal workings the WinForm widget, but it seems that since you've encountered an issue with overriding equals that you'd be better off working around.

如果您需要评估平等自己的目的:

这是一种方法是提供自己的方法来评估的平等,而不是改变默认的行为。

An approach is to provide your own method to evaluate equality, rather than changing the default behavior.

如果你的目的是要改变的是如何对待小部件的对象:

这是一种方法是使静态对象工厂为你的类。使用弱引用创建的工厂能保持所有对象的集合。弱引用让GC收集的对象。然后,工厂可以检查previously创建的对象的集合。如果找到匹配,则返回现有之一。如果没有,那么创建它。通过这种方式,而不是具有两个计算结果两个相等的(重写equals)你有两个引用是相等的(相同的内存)一个对象不同的对象。

An approach is to make a static object factory for your class. The factory could maintain a collection of all of the objects created using weak references. Weak references allow the GC to collect the objects. The factory can then check the collection of previously created objects. If a match is found then return the existing one. If not then create it. This way rather than having two different objects that evaluate two equal (override equals) you'd have a single object with two references that is equal (same memory).

这些其他方法将解决您的问题,我们希望之一。

Hopefully one of these other approaches will solve your problem.