0

As you know in WPF applications if you want to bind some property of specific class to a control's property, you must implement INotifyPropertyChanged interface to that class.

Now consider that we have many normal classes which didn't implement INotifyPropertyChanged. they are very simple class as this example:

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

for example I want to bind the UserName to a TextBox, So i should write another new User class that implements INotifyPropertyChanged like this:

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));
       }
    }
//  ...
}

Now my question is that is there or you know any mechanism or trick to simplify that?

consider that we have more than 100 models and maybe they be changed.

I'm thinking about a way, something like using a generic class to do it (Edited):

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.

Of course i'm not sure that is it good approach or not! it is just an idea to clarify my question.

Please don't tell me there is no way or it's impossible! there is hundreds of models!!!

Thanks.

Ali Adlavaran
  • 3,697
  • 2
  • 23
  • 47
  • Ali, wouldn't using MVVM and introducing a view model layer be a better solution? Are you sure you want such (UI-centric) change notification functionality on your models? – Alan Jun 30 '13 at 12:32
  • You don't need to implement INotifyPropertyChanged to bind. You only need INotifyPropertyChanged for the UI to be notified of changes. – paparazzo Jun 30 '13 at 12:51
  • @Alan, My last option is it. but I would avoid the duplication. considering ViewModels implementation we should define model classes again with some additional instructions such as INotifyPropertyChanged. – Ali Adlavaran Jun 30 '13 at 12:51
  • Thank you @Blam. but as you know we should call OnPropertyChanged method on changing properties to be able to work, so the question is this: Where we call OnPropertyChanged ?! – Ali Adlavaran Jun 30 '13 at 12:56
  • Then fix you question. "if you want to bind some property of specific class to a control's property, you must implement INotifyPropertyChanged" – paparazzo Jun 30 '13 at 15:18
  • @Blam i told that, i want mechanism that converts every class to bind-able of that class. it's clear. – Ali Adlavaran Jun 30 '13 at 16:06
  • It is very clear your question makes a false statement. "if you want to bind some property of specific class to a control's property, you must implement INotifyPropertyChanged" – paparazzo Jun 30 '13 at 16:30
  • @Blam we know that if we want to bind some property of specific class to a control's property, we must implement INotifyPropertyChanged. but in question i want to do it for every class without implementing in the body of that class. i want to convert dynamically. – Ali Adlavaran Jun 30 '13 at 16:39
  • What part of binding does not require INotifyPropertyChanged is not clear? – paparazzo Jun 30 '13 at 18:54
  • @Blam consider that you have 100 classes which they didn't implement INotifyPropertyChanged. ok? No we want to add binding ability to them. so we have one choice: re-write all of them and implement INotifyPropertyChanged in all of them. But my question is that is there any way to implement it once and don't change or re-write them? – Ali Adlavaran Jun 30 '13 at 19:40
  • What part of your question makes a false statement is not clear? – paparazzo Jun 30 '13 at 20:49
  • i have been edited my question please take a look at it, i want a mechanism like that example. – Ali Adlavaran Jun 30 '13 at 20:56

3 Answers3

1

If you are unable to modify the source classes, you can investigate the 'Behavioural Injection' features in the new release of Unity. The 'Behavioural Injection' feature permits you to wire up a class to BEHAVE as though it inherits from INotifyPropertyChanged without modifying the class itself.

There is a very similar topic from yesterday here which gives the links to get you started. The Unity team even gives you the source for the injector to create INotifyPropertyChanged on a POCO class. I have used it and can attest that it works. There's a performance hit, but that's part of the game if you don't want to modify the source classes but still enjoy the features of WPF binding.

Community
  • 1
  • 1
Gayot Fow
  • 8,710
  • 1
  • 35
  • 48
  • I have read the http://msdn.microsoft.com/en-us/library/ff660851%28v=pandp.20%29.aspx#interception_behavior_custom , But actually I didn't undrestand how can use it. may i ask you give me an example? – Ali Adlavaran Jul 05 '13 at 17:05
  • When I was first learning it I wrote some console applications that implemented INPC on a POCO class before moving on to more sophisticated applications. Small apps to prove to myself that it works and that I understood the pipeline from end-to-end. But even the smallest one of those is too big for an SO answer. – Gayot Fow Jul 05 '13 at 17:17
0

Move your InNotifyPropertyChanged implementation to a base class and let your view models to inherit that base class.

Base Class

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

your View Model class

public class User : BaseNotify
{

    private string userName;
    public string UserName 
    { 

        get { return userName; }
        set
        {
            userName = value;
            OnPropertyChanged("UserName");
        }
    }
}
Phil
  • 6,561
  • 4
  • 44
  • 69
Kurubaran
  • 8,696
  • 5
  • 43
  • 65
  • thank you, but consider that in your approach we must change properties form to FullPrperties form and call OnPropertyChanged("...") in set methods. so in your idea we have some manipulation in our models that we can't do it. – Ali Adlavaran Jun 30 '13 at 12:01
  • Wd don't want to manipulate the models because of we don't have access or permissions to change it in our company.On the other hand we want to increase re-usability in our system. – Ali Adlavaran Jun 30 '13 at 12:07
0

I have no working IDE at hand currently but I think this might work (I'm unsure about the generics)

Helper

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

Usage

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

You can now use the bindUser object in your WPF form, at least it supports INotifyPropertyChanged and is further transparent for your app (and/or for the consumer).

rene
  • 41,474
  • 78
  • 114
  • 152