2

Update: Sorry I wasn't clear about the question. I should've mentioned that:

  1. Suppose I can't change the Base, and..

  2. There are many properties in the Base. The sample code is simplified.


Here I have an object of this (base)class that is deserialized over the network.

public class Base
{
   public string Name { get; set; }
}

Now I wish to bind its properties on an WPF application so I implement INotifyPropertyChanged on a derived class.

public class Derived : Base, INotifyPropertyChanged
{
  private string _derivedName;

  public string DerivedName { 
    get { return _derivedName; }
    set
    { 
      _derivedName = value;
      RaisePropertyChanged("DerivedName");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  protected virtual void RaisePropertyChanged(string propertyName)
  {
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

Now my question is : How do I raise the property changed event when Base.Name is changed?

I know I can remove the inheritance and re-implement every base property and raise the event, but is there any better way?

Peter
  • 1,048
  • 10
  • 23
  • 3
    Not unless you can change the base class. – Blorgbeard Apr 30 '15 at 23:22
  • When you refer to Base.Name are you wanting to intercept changes to that one Base property (Name) or is it just representative of many properties that you want to intercept. – DWright Apr 30 '15 at 23:29
  • @DWright Thank you. I should have specifically said that I can't modify the base. And the base (as well as the derived) implements an interface named IData which contains many properties (Name is only one of them). – Peter Apr 30 '15 at 23:36
  • Peter, thanks, that clarifies. Will update my answer. – DWright Apr 30 '15 at 23:36
  • 2
    You can't. If you cannot modify Base and the property cannot be overridden then there is no way to change its behavior. Best you can do is create a wrapper class around Base and code consuming classes against that. – garryp Apr 30 '15 at 23:53
  • @garryp, I think you are right, but OP was asking for a way that would not involve re-implementing base properties. However, wrapping means re-implementing. – DWright May 01 '15 at 00:33
  • Peter...why did you state "1.Suppose I can't change the Base, and..", then mark the answer "Change base class to implement". Really???? – ΩmegaMan May 01 '15 at 13:10
  • @OmegaMan I guess what I want cannot be done(at least easily) without changing the base class. So I accept the denial of my supposition as the answer. After all, those answers guide away from the hard-work-low-pay direction. – Peter May 01 '15 at 13:48

3 Answers3

2

Change your code so Base implements the interface instead, and raise the event when Name is set:

public class Base : INotifyPropertyChanged
{
   private string _name;
   public string Name { get
   {
       return _name;
   }
   set{
       if(PropertyChanged != null)
           PropertyChanged(this, new PropertyChangedEventArgs("Some arg"));
       _name = value;
   }
}

   public event PropertyChangedEventHandler PropertyChanged;
}

"Derived" will inherit the interface implementation from Base, so just remove it from the class declaration:

public class Derived : Base
{
  private string _derivedName;

  public string DerivedName { 
    get { return _derivedName; }
    set
    { 
      _derivedName = value;
      RaisePropertyChanged("DerivedName");
    }
  }

  protected virtual void RaisePropertyChanged(string propertyName)
  {
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}
garryp
  • 5,508
  • 1
  • 29
  • 41
2

Create a new modifier to hide the base to the real world and report property change of Name such as:

public class Derived : Base, INotifyPropertyChanged
{ 
  public new string Name
  {
    get { return base.Name; }
    set { base.Name = value;
          RaisePropertyChanged("Name");
        }
  } 
}

See MSDN: new Modifier C# Reference as to why this works.

Update

I know I can remove the inheritance and re-implement every base property and raise the event, but is there any better way?

No...there is no way to implement a PropertyChange call on a setter in the base class after the fact without doing the modifier above.

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
  • +1 because I think it may be the best option given the constraints -- but it still may not be appropriate. The major caveat is that calls to "Name" on a reference to the base class will invoke `Base.Name`. – McGarnagle May 01 '15 at 00:19
  • @McGarnagle Think about it... even if the derived class **is being used**, *how* can one access the base when the compiler is **enforcing the modifier**? Remember binding is using reflection onto the object. If the new modifier is being enforced there is *no* way one can use the base. How would one even know there is a base class? – ΩmegaMan May 01 '15 at 00:23
  • You can always cast an instance of derived to the base. – McGarnagle May 01 '15 at 01:41
  • @McGarnagle Sure...but who is in charge of providing a list of instance objects for the binding? Yes it is possible, but not practical. :-) – ΩmegaMan May 01 '15 at 01:42
  • See https://dotnetfiddle.net/1G0bri. This is dangerous; if someone ever tries to work with the base class it will magically stop working (note that using this approach is NOT the same as using virtual which I think has been misunderstood). – garryp May 01 '15 at 08:15
  • @garryp Danger...a bit overblown. Let us look at the scenario presented. "If someone ever..." is the crux of that argument, (This is a WPF binding situation) so no one has bound to the base class because it doesn't have INotifyPropertyChange so why would they now? Even if they did the ultimate result would be the item on the screen would not change if there was a *dynamic* change. That is the danger specified. I will have to disagree on that. Also the fiddle example given did not implement it how I specified. I specified the base's storage. You created a non related strawman situation. – ΩmegaMan May 01 '15 at 12:35
  • Calling base does not affect the point I made which was any code written against Base rather than Derived will fail to raise the event, and do so silently and without warning. Any methods within base referring to Name will also call the underlying hidden property. As your solution requires Derived to be used it achieves nothing over just creating a new property with a different name, something which has the added benefit of being more explicit and removing the potential for confusion and misuse. – garryp May 01 '15 at 12:51
  • @garryp I simply produce a means to an ends. For someone in control of a Xaml display situation who can't modify a base class, this is an alternative. :-) – ΩmegaMan May 01 '15 at 12:58
  • OK we'll have to agree to disagree :) – garryp May 01 '15 at 13:03
  • @garryp Your points are valid. I would rather someone know the pros/cons of doing anything before an implementation. :-) As an aside, frankly my first inclination is to simply create a new property, but that answer was already given. Then, the user's choice of *modify the base class* frankly makes this problem moot. ha! – ΩmegaMan May 01 '15 at 13:08
1

I would choose a more pragmatic approach by wrapping the call to base class properties.

public class Derived : Base, INotifyPropertyChanged
{

  public string DerivedName { 
    get { return Name; }
    set
    { 
      Name = value;
      RaisePropertyChanged("DerivedName");
      RaisePropertyChanged("Name"); //probably you will not need this line
    }
  }
}
E-Bat
  • 4,792
  • 1
  • 33
  • 58