2014-06-11 18 views
14

我們遇到了一個奇怪的問題,我們在調試時遇到問題。爲什麼覆蓋.GetHashCode在WinForms中清除這些數據綁定值?

我們有一個使用Microsoft CAB,DevExpress組件和.Net 3.5的MDI工作區。

如果用戶在工作區中打開兩個窗口,其中每個窗口都包含綁定到兩個單獨數據模型的UserControl,那麼將它們兩者最小化,第一個窗口最小化是在第二個窗口最小化時清除綁定字段。

.Equals.GetHashCode數據模型的方法已被覆蓋,因此兩個數據模型都被認爲是相等的。如果我們改變它,所以它們是獨一無二的,我們不會得到這種行爲。

這裏的顯示問題

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(); 

這裏的調用堆棧當第二窗口被最小化一些示例僞代碼:

enter image description here

在上面的堆棧跟蹤EndEditSession()調用,它是調用EndEditSession第二個窗口最小化,而在堆棧跟蹤超過[External Code] t o我已經設置了OnChange斷點,它正在觸發第一個窗口中的更改方法。

EndEditSession()是定製的東西我們實施這看起來是這樣的

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返回它在我的測試的情況下是一個定製的DevExpress LookupEdit

_data包含了UserControl數據模型的綁定設置,控制,我可以驗證它被設置爲實例,以使第二窗口。

我最初的想法是共享BindingContext,所以錯誤的PropertyManager正在返回,但是我已驗證兩個窗體和控件的.BindingContext是分開的。

UserControl的兩個單獨副本綁定到兩個單獨的數據模型實例時,如果GetHashCode方法被覆蓋以使兩個對象被認爲是相等的,它可能會將其綁定混合起來嗎?

我對WinForms綁定系統的內部工作原理不熟悉,或者完全不瞭解CAB的MDI工作空間如何管理。

我的理論是,當第一個窗口最小化時,它將卸載控件以節省內存,然後當第二個窗口最小化管理綁定的內部哈希表時,會錯誤地混淆並運行更新以從中獲取數據第一個最小化窗口(現在是空白)並更新其數據源。這個理論有很多漏洞,但它是我能想到的唯一的東西。

回答

0

BindingContext對象未與其他任何其他BindingContext共享其字段和屬性,因爲其字段和屬性不是靜態的。

但是,有可能有一個BindingContext對象的幾個控件。

在第一種情況下,如果幾個控件具有相同的父項並且沒有它們自己的BindingContext則該控件的BindingContext屬性將返回Control.Parent(.Parent...).BindingContext對象。

在第二種情況下,有可能是這樣的:

var bindingContext = new BindingContext(); 
var a = new SomeControl(); 
var b = new SomeControl(); 
a.BindingContext = bindingContext; 
b.BindingContext = bindingContext; 

在第三種情況下BindingContext可以以這樣的方式被覆蓋。

我不知道什麼是你的情況怎麼回事,所以我只能建議初始化數據綁定之前做這樣的事情:

var a = new SomeControl(); 
var b = new SomeControl(); 
a.BindingContext = new BindingContext(); 
b.BindingContext = new BindingContext(); 


如果這沒有解決您的問題,那麼你需要檢查您的_bindingValues對象的填充。在填充此對象期間,可能會填充錯誤的值。

+0

這是我的第一個想法,但同樣的問題仍然發生時,分配每個控件它是自己的'BindingContext' – Rachel

+2

@Rachel你可以提供一個示例項目?似乎沒有足夠的關於你問題的信息。我認爲這個問題不是用'BindingContext'。問題可能出現在你的'_bindingValues'對象中。 – nempoBu4

+0

我實際上無法在示例項目中重現這一點,我認爲這是因爲我沒有在我的示例中使用smartparts創建完整的MDI工作區。我正在使用的示例代碼只是一個帶有TabControl的表單,一個自定義對象以及帶有自定義綁定代碼的自定義UserControl。我今天再試一次,看看我是否可以在更大的示例項目中重現問題。 – Rachel

1

我不知道內部工作在WinForm控件,但似乎因爲你所遇到的問題與覆蓋等於說你會關閉更好的工作圍繞

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

的方法是提供自己的方法來評估平等,而不是改變默認的行爲。

如果你的目的是要改變小部件如何處理的對象:

的一個方法是使靜態對象工廠類。工廠可以維護使用弱引用創建的所有對象的集合。弱引用允許GC收集對象。工廠然後可以檢查先前創建的對象的集合。如果找到匹配,則返回現有匹配。如果沒有,然後創建它。這種方式,而不是有兩個不同的對象,評估兩個相等(覆蓋等於),你會有一個單一的對象與兩個引用相同(相同的內存)。

希望其中一種方法可以解決您的問題。