C# 如何在c中动态地将普通类转换为可绑定类#

C# 如何在c中动态地将普通类转换为可绑定类#,c#,.net,wpf,data-binding,C#,.net,Wpf,Data Binding,正如您在WPF应用程序中所知道的,如果要将特定类的某些属性绑定到控件的属性,则必须对该类实现INotifyPropertyChanged接口 现在考虑我们有许多正常的类没有实现 NoTyFyPryTyType 。它们是非常简单的类,如本例所示: public class User : ModelBase { public int Id { get; set; } public string UserName { get; set; } public string

正如您在
WPF
应用程序中所知道的,如果要将特定类的某些属性绑定到控件的属性,则必须对该类实现
INotifyPropertyChanged
接口

现在考虑我们有许多正常的类没有实现<代码> NoTyFyPryTyType 。它们是非常简单的类,如本例所示:

    public class User : ModelBase
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
//  ...
}
例如,我想将
用户名
绑定到
文本框
,因此我应该编写另一个新的
用户
类,实现
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多个型号,可能需要更换

我在考虑一种方法,比如使用泛型类来完成(编辑的):

公共类BindableClass{…添加使用反射绑定指令的功能…}
NormalClass NormalInstance=新的NormalClass();
//简单类,未实现INotifyPropertyChanged
//所以它不支持绑定。
BindableClass BindableInstance=新的BindableClass();
//已实现INotifyPropertyChanged
//所以它支持绑定。
当然,我不确定这是不是一个好办法!这只是一个澄清我的问题的想法

请不要告诉我这是不可能的!有数百种型号


谢谢。

将InNotifyPropertyChanged实现移动到基类,并让视图模型继承该基类

基类

您的视图模型类


我目前手头没有可用的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));
       }
    } 
}
公共类可绑定:RealProxy,INotifyPropertyChanged
{
私人T obj;
私有可绑定(T obj)
:基础(类型(T))
{
this.obj=obj;
}
//不确定这是否可以编译,
//在这种情况下,将其作为财产,并将其公之于众
公共静态T构建代理(T obj)
{
return(T)new Bindable(obj).GetTransparentProxy();
}
公共覆盖IMessage调用(IMessage msg)
{
var meth=msg.Properties[“_MethodName”].ToString();
var bf=BindingFlags.Public | BindingFlags.Instance;
如果(方法开始使用(“设置”))
{
meth=meth.子字符串(4);
bf |=BindingFlags.SetProperty;
}
if(meth.StartsWith(“get_”))
{
bf |=BindingFlags.GetProperty;
//获取值。。。
meth=meth.子字符串(4);
}
var args=新对象[0];
if(msg.Properties[“\u Args”!=null)
{
args=(object[])msg.Properties[“_args”];
}
var res=typeof(T).InvokeMember(meth,
高炉
,null,obj,args);
if((bf&&BindingFlags.SetProperty)==BindingFlags.SetProperty)
{
不动产变更(meth);
}
返回新的返回消息(res,null,0,null,null);
}
公共事件属性更改事件处理程序属性更改;
私有void OnPropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的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;
User yourplanuser=GetFromBackEnd();
//如果我的泛型错了,对不起。。。
var bindUser=Bindable.BuildProxy(yourplanuser);
//var bindUser=newbindable(yourplaneuser).Proxy;

您现在可以在WPF表单中使用
bindUser
对象,至少它支持INotifyPropertyChanged,并且对您的应用程序(和/或消费者)更加透明。

如果您无法修改源类,您可以研究Unity新版本中的“行为注入”功能。“行为注入”功能允许您将类连接起来,使其行为如同从INotifyPropertyChanged继承一样,而无需修改类本身


昨天有一个非常类似的主题,它提供了一些链接让你开始学习。Unity团队甚至提供了注入器在POCO类上创建INotifyPropertyChanged的源代码。我使用过它,可以证明它是有效的。如果你不想修改源类,但仍然享受WPF绑定的特性,那么这是游戏的一部分。

谢谢,但是考虑到在你的方法中,我们必须将属性形式更改为完整形式,并调用set方法中的属性Type(“…”)。因此,在你的想法中,我们在模型中有一些操纵,我们无法做到。Wd不想操纵模型,因为我们在公司中没有更改模型的访问权限或权限。另一方面,我们希望提高系统的可重用性。阿里,使用MVVM和引入视图模型层不是更好的解决方案吗?是否确实要在模型上使用此类(以用户界面为中心的)更改通知功能?不需要实现INotifyPropertyChanged to bind。您只需更改INotifyPropertyChanged即可通知UI更改。@Alan,我的最后一个选项是更改。但我会避免重复。考虑到ViewModels的实现,我们应该用一些额外的说明重新定义模型类,例如INotifyPropertyChanged。谢谢@bum。但正如您所知,我们应该在更改属性时调用OnPropertyChanged方法以使其能够工作,所以问题是:我们在哪里调用OnPropertyChanged?!然后解决你的问题。“如果要将特定类的某些属性绑定到控件的属性,则必须实现INotifyPropertyChanged”我已经阅读了,但实际上我没有取消重新启动,并且如何使用它。我可以请你给我举个例子吗?当我第一次学习它时,我编写了一些控制台应用程序,这些应用程序在POCO类上实现了INPC,然后继续学习
public class User : BaseNotify
{

    private string userName;
    public string UserName 
    { 

        get { return userName; }
        set
        {
            userName = value;
            OnPropertyChanged("UserName");
        }
    }
}
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;