2013-06-30 28 views
0

如您在WPF應用程序中所瞭解的,如果您想要將某些特定類的屬性綁定到控件的屬性,則必須實現該類的接口INotifyPropertyChanged如何將普通類動態地轉換爲c#

現在考慮我們有很多正常的類沒有實現INotifyPropertyChanged。他們是非常簡單的類如下面的例子:

public class User : ModelBase 
{ 
    public int Id { get; set; } 
    public string UserName { get; set; } 
    public string Password { get; set; } 
// ... 
} 

例如我想將UserName綁定到一個TextBox,所以我應該寫另一個新User類,它實現INotifyPropertyChanged這樣的:

public class User : INotifyPropertyChanged 
{ 
    public string Password { get {return _Password}} 
          set {_Password=value;OnPropertyChanged("Password");} 

    // ... Id and UserName properties are implemented like Password too. 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
// ... 
} 

現在我的問題是,那裏是否存在或者你知道任何機制或技巧來簡化?

認爲我們有超過100個模型,也許他們會改變。

我在想一個辦法,像使用普通類做(編輯):

public class BindableClass<NormalClass> { ...adding ability to bind instructions using reflection... } 

NormalClass NormalInstance = new NormalClass(); 
     // simple class, does not implemented INotifyPropertyChanged 
     // so it doesn't support binding. 

BindableClass<NormalClass> BindableInstance = new BindableClass<NormalClass>(); 
     // Implemented INotifyPropertyChanged 
     // so it supports binding. 

當然,我不知道這是好辦法還是不行!這只是一個想法來澄清我的問題。

請不要告訴我,沒有辦法或不可能!有數百個模型!

謝謝。

+0

阿里,會不會使用MVVM和引入視圖模型層是一個更好的解決方案?您確定要在模型上使用這種(以UI爲中心)更改通知功能嗎? – Alan

+0

你不需要實現INotifyPropertyChanged來進行綁定。您只需要將INotifyPropertyChanged通知給用戶界面以通知更改。 – Paparazzi

+0

@Alan,我最後的選擇是它。但我會避免重複。考慮到ViewModels實現,我們應該再次定義模型類,並附帶一些額外的指令,例如INotifyPropertyChanged。 –

回答

0

將您的InNotifyPropertyChanged實現移至基類,讓視圖模型繼承該基類。

基類

public class BaseNotify 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

您的視圖模型類

public class User : BaseNotify 
{ 

    private string userName; 
    public string UserName 
    { 

     get { return userName; } 
     set 
     { 
      userName = value; 
      OnPropertyChanged("UserName"); 
     } 
    } 
} 
+0

謝謝,但請考慮在您的方法中,我們必須將屬性表單更改爲FullPrperties表單,並在set方法中調用OnPropertyChanged(「...」)。所以在你的想法中,我們在模型中有一些操作,我們不能這樣做。 –

+0

Wd不想操縱模型,因爲我們沒有訪問權限或許可在我們公司修改它。另一方面,我們希望增加系統的可重用性。 –

0

我在目前手頭沒有工作的IDE,但我認爲這可能工作(我不確定仿製藥)

助手

public class Bindable<T>: RealProxy, INotifyPropertyChanged 
{ 
    private T obj; 

    private Bindable(T obj) 
     : base(typeof(T)) 
    { 
     this.obj = obj; 
    } 

    // not sure if this compiles, 
    // make it a property in that case and the ctor public 
    public static T BuildProxy(T obj) 
    { 
     return (T) new Bindable<T>(obj).GetTransparentProxy(); 
    } 

    public override IMessage Invoke(IMessage msg) 
    { 
     var meth = msg.Properties["__MethodName"].ToString(); 
     var bf = BindingFlags.Public | BindingFlags.Instance ; 
     if (meth.StartsWith("set_")) 
     { 
      meth = meth.Substring(4); 
      bf |= BindingFlags.SetProperty; 
     } 
     if (meth.StartsWith("get_")) 
     { 
      bf |= BindingFlags.GetProperty; 
      // get the value... 
      meth = meth.Substring(4); 
     } 
     var args = new object[0]; 
     if (msg.Properties["__Args"] != null) 
     { 
      args = (object[]) msg.Properties["__Args"]; 
     } 
     var res = typeof (T).InvokeMember(meth, 
      bf 
      , null, obj, args); 
     if ((bf && BindingFlags.SetProperty) == BindingFlags.SetProperty) 
     { 
      OnPropertyChanged(meth); 
     } 
     return new ReturnMessage(res, null, 0, null, null); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

使用

User yourplainUser = GetFromBackEnd(); 
// if I've the generics wrong, sorry... 
var bindUser = Bindable<User>.BuildProxy(yourplainUser); 
// var bindUser = new Bindable<User>(yourplainUser).Proxy; 

您現在可以使用bindUser對象的WPF的形​​式,至少它支持INotifyPropertyChanged的,是你的應用程序更透明(和/或爲消費者)。

1

如果您無法修改源類,則可以調查新版本Unity中的「行爲注入」功能。 「行爲注入」功能允許您將類連接到BEHAVE,就像它從INotifyPropertyChanged繼承而不修改類本身一樣。

從昨天here有一個非常類似的話題,它給出了你開始的鏈接。 Unity團隊甚至會爲您提供噴油器的源代碼,以在POCO類上創建INotifyPropertyChanged。我已經使用它,可以證明它的工作原理。性能受到影響,但如果您不想修改源代碼類,但仍然享受WPF綁定的功能,這就是遊戲的一部分。

+0

這似乎是一個好方法。謝謝,我現在正在研究它。 –

+0

它適合你嗎? –

+0

我已閱讀http://msdn.microsoft.com/en-us/library/ff660851%28v=pandp.20%29.aspx#interception_behavior_custom,但實際上我沒有undrestand如何使用它。我可以問你給我一個例子嗎? –