[英]Two-way databinding in .NET does not work, even with INotifyPropertyChanged objects
我正在使用Windows Forms應用程序,它當然涉及到對象的數據綁定。
從我收集的數據來看,雙向數據綁定無法與.NET即用。
我的問題是我找不到實現它的一致信息:
根據“ .NET WinForms概述”,我必須為每個屬性創建一個名為<propertyName> Changed的事件,並在關聯屬性的設置器中觸發它。
根據在線資源(包括MSDN),我只需要在類中實現INotifyPropertyChanged,並在所有設置方法中觸發PropertyChanged事件,並傳入屬性名稱。
但是,假設我有一個簡單的UI,且文本框數據綁定到一個類的屬性(實現上述方法之一),如果我在代碼中設置了databound屬性的值,則使用這兩種方法,UI都不會反映更改。
那我在這里想念什么?
編輯
我應該提到的是,在相關類的聲明中並未實現INotifyPropertyChanged,而是通過動態代碼生成而實現的,該代碼大致等效於DynamicProxy。 我正在為該主題創建一個新問題,因為答案符合實際問題。
代碼生成工具正確地實現了另一個 InotifyPropertyChanged 編輯 ,我已經通過將代理對象的實例強制轉換為INotifyPropertyChanged來檢查了這一點,並注冊了該事件的處理程序,該事件的處理程序在屬性值更改時會引發。
數據綁定的UpdateMode IS設置為NotifyPropertyChanged,並且在關聯的控件上將CausesValidation設置為false。
所以偽代碼看起來像這樣:
class MyForm {
MyClass localObj;
BindingSource mySource = new BindingSource();
MyForm(MyClass obj) {
localObj = obj.CreateProxy() // Ensures localObj is a proxy instance
mySource.Datasource = localObj // After this, UI is updated accordingly
localObj.someProperty = "I changed the value" // Here, the NotifyPropertyChanged event does get fired, but the UI does not update. Hence my question...
Console.WriteLine(localObj.someProperty) // Output is 'I changed the value'
}
}
因此,要更新UI的唯一方法是在BindingSource上調用ResetBindings ...這違反了雙向綁定恕我直言的目的。
終於!!
問題來自設計器。 在設計時,我無法訪問業務對象代理的實類型,該實類型是由代理生成的運行時類型(它是功能性的,我對此部分毫無疑問)。 因此,設計人員使用業務對象的已知數據類型而不是代理的數據類型來初始化BindingSource(代理是從BO的類繼承的類)
因此,需要使用代理對象的運行時類型手動初始化數據源,以使雙向綁定正常工作。
工作版本如下(在偽C#中):
class MyForm {
Object localObj;
BindingSource mySource;
MyForm(MyClass obj) {
localObj = obj.CreateProxy() // Ensures localObj is a proxy instance
((ISupportInitialize) mySource).BeginInit()
mySource.Datasource = localObj.GetType()
((ISupportInitialize) mySource).EndInit()
mySource.Datasource = localObj // After this, UI is updated accordingly
localObj.someProperty = "I changed the value" // UI updates ! :)
}
}
謝謝大家的建議和幫助,您剛剛拯救了我。 我在這頭上撞在牆上!
實現INotifyPropertyChanged
就足夠了。 只需在屬性窗口->(DataBindings)->(Advanced)-> [...]對話框中將TextBoxes
框的Data Source Update Mode
從OnValidation
更改為OnPropertyChanged
。
UPDATE
這就是可以實現INotifyPropertyChanged
方式。 對您的所有財產都這樣做
private string _city;
public string City
{
get { return _city; }
set
{
if (_city != value) {
_city = value;
OnPropertyChanged("City");
}
}
}
您的班級需要實現接口
public class Address : INotifyPropertyChanged
{
// Your properties go here ...
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
我將檢查動態代碼生成是否在加載表單之前實際添加了INotifyChanged。 然后,我將檢查通過代碼更改的對象的公共屬性是否實際上與屏幕上當前顯示的對象相同 (是列表還是單個對象?)。 確保將數據綁定設置為OnPropertyChanged而不是OnValidation。 然后,我將檢查它是否以其他方式起作用:編輯數據綁定的文本框值,並在選擇另一個控件后查看對象是否獲得新值。 當使用這樣的代碼(偽代碼)更改屬性時,請小心。
ctor(MyClass objParm){
this.localobj = objParm;
bindingsource1.datasource = objParm; // or this.localobj
}
SomeMethod(){
this.localobj = new MyClass();
this.localobj.MyProperty = 'new value';
}
除非您更改為
SomeMethod(){
this.localobj = new MyClass();
this.localobj.MyProperty = 'new value';
bindingsource1.datasource = this.localobj
}
更新:
您說數據綁定不是開箱即用的,但我可以確保您可以做到。 看到您提供的代碼后,我懷疑它與動態代理生成/ CreateProxy()方法有關。 由於ResetBindings起作用,所以它可能與CreateProxy返回與MyClass不同的類這一事實有關。 數據綁定對於類型非常挑剔。 例如,如果您使用接口(例如數據源的列表),則數據綁定會給出錯誤,因為它們的類型不同。 這就是為什么您需要使用新的BindingList()作為數據源的原因。 僅提供一些背景信息,可能會為您指明正確的方向。 在您的情況下,元數據可能會由於動態代碼生成而發生變化,請參閱ResetBindings()上的msdn文檔。 作為測試,請嘗試以下操作:
mySource.Datasource = new BindingList<MyClass>(new List<MyClass>(){this.localobj});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.