2013-06-30 21 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如何使用它。我可以问你给我一个例子吗? –