I am using a class that I cannot edit, it has a property (a boolean) of which it would be nice to be informed when it changes, I can't edit the properties get or set as I am importing the class from a .dll (which I don't have the code for).
How do I create an event/function that is fired when the property is changed?
Additional
It is only changed within its own class, directly to the underlying private variable.
E.g.
private bool m_MyValue = false;
public bool MyValue
{
get { return m_MyValue; }
}
private void SomeFunction()
{
m_MyValue = true;
}
You can't, basically... not without using something like the debugger API to inject code at execution time and modifying the IL of the original library (and I'm not recommending either of those solutions; aside from anything else it may violate the licence of the library).
Basically if a property doesn't support notification, it doesn't support notification. You should look for a different way of approaching your problem. (Would polling work, for example?)
You cant do this directly [as Jon Skeet said], unless it's virtual, you're in a position to intercept all instance creations of the class and there are no changes to a backing field that influences the real 'value' of the propget.
The only way to brute force this is to use Mono.Cecil or MS CCI to instrument the prop setter a la this DimeCast on Cecil. (Or PostSharp)
However this wouldn't trap internal changes to the backing field (if there even is one). (Which is why wrapping probably wont work).
UPDATE: Given your update that you're definitely trying to trap the underlying field change, the only way to do that is to use PS / CCI / Cecil and analyse the flow to intercept all field updates. In short, not very feasible.
Arguably, the only real way to do this is to create some kind of "watcher" component, running in a separate thread, whose job is to read the property at intervals and raise an event when the property's value changes. Of course this solution sails in the murky waters of threading and synchronization.
On the assumption that your application is single-threaded in respect to this object, your cleanest solution is to make method calls to this object via a proxy object. It would have the job of checking the before and after state of the property and raising an event in the case it has changed.
Here's a simple example of what I'm talking about:
public class SomeProxy
{
public SomeProxy(ExternalObject obj)
{
_obj = obj;
}
public event EventArgs PropertyChanged;
private bool _lastValue;
private ExternalObject _obj;
protected virtual void OnPropertyChanged()
{
if(PropertyChanged != null)
PropertyChanged();
}
protected virtual void PreMethodCall()
{
_lastValue = _obj.SomeProperty;
}
protected virtual void PostMethodCall()
{
if(_lastValue != _obj.SomeProperty)
OnPropertyChanged();
}
// Proxy method.
public SomeMethod(int arg)
{
PreMethodCall();
_obj.SomeMethod(arg); // Call actual method.
PostMethodCall();
}
}
Obviously you can build this proxy pattern into a suitable object - you just have to be aware that all calls have to go through the proxy for the event to be raised when you expect it to be.
As previously mentioned, the most direct method (and that which requires the least change to code) is to use an AOP library such as PostSharp.
However, a solution can be achieved using traditional C#/.NET by using the dependency property pattern, used throughtout WPF to great effect. I suggest to read up on this, and consider implementing such a system (or at least a simplified version of it) for your project, if appropiate.
You will need to create a class that wraps the class in the dll, within the setter property just raise an event there using the normal methods.
Could you inherit from the class and hide the property? Something like this...
class MyClass : BaseClass
{
// hide base property.
public new bool MyProperty
{
get
{
return base.MyProperty;
}
set
{
base.MyProperty = value;
RaiseMyPropertyChangedEvent();
}
}
}
I think Alex' idea of a wrapper is good, however, given that the most important thing to you is that you know that the value is changed before use, you could simply move the notification to the getter, circumventing the worries of internal value change. That way you get something similar to polling, yet reliable:
class MyClass : BaseClass
{
//local value
private bool local;
//first access yet?
private bool accessed = false;
// Override base property.
public new bool MyProperty
{
get
{
if(!accessed)
{
// modify first-get case according to your taste, e.g.
local = base.MyProperty;
accessed = true;
RaiseMyPropertyChangedBeforeUseEvent();
}
else
{
if(local != base.MyProperty)
{
local = base.MyProperty;
RaiseMyPropertyChangedBeforeUseEvent();
}
}
return local;
}
set
{
base.MyProperty = value;
}
}
}
You can try to inherit it and use it's child instead of it.
Override the "set" of the property so it raises the event.
EDIT: ... only if property is virtual in the parent class ...
Related
Let me just preface this by saying that I know this is probably a newbie quesion, I tried searching for it and I can't find a proper anwser for it (probbably asking it wrong).
So usually when I want to use another value outisde of its class, I just make it public and access it lik.
Yet often I see other code use private values in their class and then make separate functions for getting and setting the value like so:
private bool fooBar;
public void SetFooBar(bool boolean)
{
fooBar = boolean;
}
public bool GetFooBar()
{
return fooBar;
}
Excuse my ignorance but what exactly is the point of it? They both do essentially the same thing (by my newbie logic atleast). I know that private variables are useful in that it ensures you can't break the functionality of a program by modifying them elsewhere in the code, but you're modifying them elsewhere in the code anyway, so what gives? Why do I see people do this?
Because directly modifying the state of an object is a no-no in OOP
Because you can't put fields into an interface (and once you get far enough, you usually end up accessing most other objects through interfaces)
Because it allows additional logic (like raising events) when another object wants to interact with the field
Because certain things (like WPF bindings) only work with properties, not fields
Because you may want to change how the value is retrieved/stored (not just in-memory) later
(Note that in C# you usually do this as a property, not methods, like public bool Foo {get; set;})
This allows you to change the way the value is stored regardless of how external users access it.
Using Getter and Setter functions, you could request the data from a local cache or pull it from a database.
C# supports Getter Setter functionality implementations using a property style accessor.
private bool _fooBar
public bool FooBar
{
get { return _fooBar; }
set { _fooBar = value; }
}
As BradleyDotNET mentioned in the comments, you can write these in a way that resembles lambdas starting with C# 7.0
private bool _fooBar
public bool FooBar
{
get => _fooBar;
set => _fooBar = value;
}
As BradleyDotNET mentioned you can write this exact implementation as
public bool FooBar { get; set; }
Which will act the same way.
You can also expand upon this by making the value only public to get, but only settable in the class.
public bool FooBar { get; protected set; }
I am working on a project with over 30 properties that are constantly being updated using data binding. The way i'm fetching the new values sent by the server is with event aggregator, which updates the properties. So far, here's how I got it working
Event Class
public class Zone1TempEvent : PubSubEvent<int>
{
}
Property
private int _zone1Temp;
public int Zone1Temp
{
get { return _zone1Temp; }
set { SetProperty(ref _zone1Temp, value); }
}
Subscribe
eventAggregator.GetEvent<Zone1TempEvent>().Subscribe(tempZone1Update);
Method
private void tempZone1Update(int value) { Zone1Temp = value; }
Publish
private void checkResponsability(ItemValueCallback itemValue)
{
switch ((string)itemValue.ClientHandle)
{
case "Zone1_Temp":
int Zone1Temp = Int32.Parse((string)itemValue.Value);
_eventAggregator.GetEvent<Zone1TempEvent>().Publish(Zone1Temp);
break;
}
}
However, I can't imagine doing this 30 times. I am looking for an alternative. I would like to avoid having to create a class for each event, as well as a method for each property. Is it possible to have one generic class called UpdatePropertyEvent, and use this to do so.
Or maybe do something inspired by this thread with enums?
Mixing enums with event classes in an event aggregator
Thanks
Instead of using the EventAggregator, your service can implement IPropertyChanged (and the models returned from the service can, depending on your scenario ). This way you have to react to just one event.
Also, you could just publish a single event that carries the two string values, like class ServerUpdatedEvent : PubSubEvent<PropertyValuePair> and do the parsing and distributing
to properties in the view model.
Example:
// ...service...
private void checkResponsability(ItemValueCallback itemValue)
{
_eventAggregator.GetEvent<ServerUpdatedEvent>().Publish(new PropertyValuePair((string)itemValue.ClientHandle,(string)itemValue.Value);
}
// ...view model or intermediate service...
private void OnServerUpdate(PropertyValuePair data)
{
switch (data.Property)
{
case "Zone1_Temp": Zone1Temp = int.Parse(data.Value); break;
}
}
If your properties can be named like the events or you put attributes on them, you can use reflection to find the property for an incoming event. Reflection is slow, though, so that if you have lots of events, you might need some type of caching.
Something like this could work for you, too.
I have a ViewModel like this
Public class AboutPageViewModel
{
public AboutPageViewModel()
{
AppName = Settings.MyAppName;
}
private string _appName;
public string AppName
{
get{return _appName;}
set{_appName = value; RaisePropertyChanged("AppName");}
}
}
Now in a static class
public static class Settings
{
public static string MyAppName{get;set;} = "LOL"
}
How do I notify the ViewModel everytime MyAppName is changed, and update it to the Binded UI?
Thanks!
As you define it in your question, Settings isn't a static class (ah, I see in comments that was a typo, and it's static in your code). It should not be static. PropertyChanged notifications on a static class are theoretically possible but it's not worth your time to mess with, and there's no need to bother.
Have Settings implement INotifyPropertyChanged, just like your viewmodel. When MyAppName changes, Settings should raise PropertyChanged, just as AboutPageViewModel does when its own AppName property changes.
Now give Settings a static property called Instance:
public static Settings Instance { get; private set; }
static Settings()
{
Instance = new Settings();
}
And handle its PropertyChanged event in AboutPageViewModel:
public AboutPageViewModel()
{
AppName = Settings.Instance.MyAppName;
Settings.Instance.PropertyChanged += (s,e) =>
{
// If you're in C#6:
//if (e.PropertyName == nameof(Settings.MyAppName))
if (e.PropertyName == "MyAppName")
{
AppName = Settings.Instance.MyAppName;
}
}
}
Option Number Two
Arguably a better option; I've done it this way more than once.
In comments, #MikeEason makes the very good point that this could also be done with a custom *Changed event such as MyAppNameChanged, which has two advantages: It lets you go back to a static class, and it lets you skip the check on the property name, which is extra code and also a "magic string". Working with INotifyPropertyChanged we get a little bit numb to the danger of magic strings, but they are in fact bad. If you're in C#6, you can and absolutely should use the nameof() operator, but not all of us are in C#6 just yet. My main responsibility at work is an application that we're hoping to migrate to C#6 this summer.
public static event EventHandler<String> MyAppNameChanged;
private static String _myAppName = "";
public static String MyAppName {
get { return _myAppName; }
set {
if (_myAppName != value)
{
_myAppName = value;
// C#6 again. Note (thanks OP!) you can't pass this for sender
// in a static property.
MyAppNameChanged?.Invoke(null, value);
}
}
}
The drawback of this is that, well, this class is called Settings, not Setting. Maybe it's got a dozen properties changing here and there. That gets to be a real thicket of distinct property-changed events ("so what?" you may ask -- and you may have a point). My tendency is to stick with PropertyChanged if there's a whole sheaf of them, and to add an event if the class has only one or two important properties that somebody needs to keep an eye on. Either way is annoying in my view; try both and you'll eventually settle on a preference.
You don't need to store value in ViewModel if you already have it somewhere (I assume what you are not going to change it in ViewModel itself):
public class AboutPageViewModel : INotifyPropertyChanged
{
public string AppName => Settings.MyAppName;
}
And as for View to know when this property is changed you need 2 things: 1) there should be a way to inform ViewModel when value is changed 2) rise PropertyChanged(nameof(AppName)) (notice INotifyPropertyChanged).
Several possibilities to make it:
Settings should rise event when MyAppName value is changed, ViewModel subscribe to it and rises PropertyChanged;
Store initial value, check periodically if value is changed;
Use another type which implement INotifyPropertyChanged, bind to that type property instead, this will update view automatically if that type rises PropertyChanged.
You have to implement INotifyPropertyChanged interface on Settings class!
then use the same piece of code like this:
private string _myAppName;
public string MyAppName
{
get{return _myAppName;}
set{_appName = value; RaisePropertyChanged("MyAppName");}
}
I want to add more functionality to a project I have that makes use a number of classes packaged in the NET Framework. These same classes provide a number of properties which can be quite useful adapting the functionality of my project, however one thing that these classes lack is Events.
If each property had a appropriate event that would fire whenever the value of such property changed, I could then assign a event handler that would act based on those properties value.
I made a sample case bellow to illustrate my goal in the most simpler way I could think off.
Sample case:
The System.Net.Sockets.Socket class (Socket on MSDN Docs) has a property
named Connected that basically returns true if the socket is
connected to a specified end point otherwise returns false.
What I would like to accomplish is simple. I would like to keep this
property under "watch" and when the value of it changes, fire a event.
Doing that to one of my own classes it would be simple although a bit tiresome using the INotifyPropertyChanged interface, simply because always that my code changed the value of the property I would have to fire the event manually. Unfortunately, to best of my knowledge, not even this kind of procedure can be applied to the existing Socket class distributed within NET Framework.
Well, this question is becoming quite extensive, sorry, but I hope it gave an insight to my goal.
Now simply putting it, I want to watch the Connected property of the Socket class and when the value of it changes, fire an event. And if it would be possible to also use such approach to watch variables as well properties, it would be awesome, not just for me, but for everyone who stumbles across this question on SO.
A simple and lightweight approach is preferred of course, but most of all, I want to understand how it can be done, so in the future I can apply it in mass scale to other classes.
I realize I'm asking a lot. Many thanks.
Any questions just ask.
I implemented a basic class that should get you started. I'm sure a fully functional, production-ready, thread-safe class would require a bit more work, plus you need to implement your own strategy for when to poll for value changes.
public class TargettedObserver<T>
{
private static readonly EqualityComparer<T> EqualityComparer = EqualityComparer<T>.Default;
private Func<T> ValueTarget;
private T OldValue;
public event ObservedValueChangedEventHandler<T> ValueChanged;
public TargettedObserver(Func<T> valueTarget)
{
this.ValueTarget = valueTarget;
OldValue = ObtainCurrentValue();
}
public bool CheckValue()
{
T oldValue = OldValue;
T newValue = ObtainCurrentValue();
bool hasValueChanged = CompareValues(oldValue, newValue);
if (hasValueChanged)
{
OldValue = newValue;
NotifyValueChanged(oldValue, newValue);
}
return hasValueChanged;
}
private void NotifyValueChanged(T oldValue, T newValue)
{
var valueChangedEvent = ValueChanged;
if (valueChangedEvent != null)
valueChangedEvent(this, new ObservedValueChangedEventArgs<T>(oldValue, newValue));
}
private static bool CompareValues(T oldValue, T newValue)
{
return !EqualityComparer.Equals(oldValue, newValue);
}
private T ObtainCurrentValue()
{
return ValueTarget();
}
}
And the event handling:
public class ObservedValueChangedEventArgs<T> : EventArgs
{
public T OldValue { get; private set; }
public T NewValue { get; private set; }
public ObservedValueChangedEventArgs(T oldValue, T newValue)
{
this.OldValue = oldValue;
this.NewValue = newValue;
}
}
public delegate void ObservedValueChangedEventHandler<T>(TargettedObserver<T> observer, ObservedValueChangedEventArgs<T> eventArgs);
Usage looks something like this:
public class TestClass
{
private Socket MySocket;
private static TargettedObserver<bool> SocketConnectedObserver;
public void Main()
{
MySocket = new Socket();
SocketConnectedObserver = new TargettedObserver<bool>(() => MySocket.Connected);
SocketConnectedObserver.ValueChanged += ReportSocketConnectedStateChanged;
PerformSocketConnection();
MainThread.Invoke(PollSocketValue);
}
private void PollSocketValue()
{
SocketConnectedObserver.CheckValue();
MainThread.Invoke(PollSocketValue);
}
private void ReportSocketConnectedStateChanged(TargettedObserver<bool> observer, ObservedValueChangedEventArgs<bool> eventArgs)
{
Console.WriteLine("Socket connection state changed! OldValue: " + eventArgs.OldValue + ", NewValue: " + eventArgs.NewValue);
}
}
Notice the constructor takes a simple lambda expression that can evaluate the value you're wanting to observe.
Also note that MainThread.Invoke is just a pseudocode to show it polling for a change on every main thread loop. I'm sure there are nicer strategies (background thread with a timer interval) for example that could be implemented in a nice, reusable way. Still more work to be done in terms of deregistering the observer. Could probably make some nice factory methods or lambda delegates so you don't need to keep the TargettedObserver instance floating around and reduce the amount of wiring/manual code. But at least this should be a start.
What your looking for is an implementation of the Observer Pattern. Something like this Observable<T> implementation might work.
See also the IObserver<T> Interface in .NET 4:
The IObserver<T> and IObservable<T> interfaces provide a generalized
mechanism for push-based notification. The IObservable<T> interface represents the class that
sends notifications (the provider); the IObserver<T> interface
represents the class that receives them (the observer). T represents
the class that provides the notification information.
I have two simple questions, based on the fact that I am extending an existing class...
1) I am implementing some custom properties, and I would like that whenever their values change a specific (parameterless) function be called. Of course, if there was no need to call the function I could use the traditional { get; set; } syntax with no need for an additional variable. However, and even if the only thing I modify in the set accessor is the call to the other function, I must declare a private variable so that I can specify the get and set accessors myself... Isn't there a simpler way to do this without declaring so many variables? Isn't there something like a gerenal "property change" event?
2) Since I am overriding a .NET user control, I would like to change the category under which some of the base properties appear. At the moment, and just to use the [Category("")] syntax, I must declare those properties as new and implement get and set referring to the base classe's properties. Isn't there a simple way to do this?
Maybe you should look into the INotifyPropertyChanged interface. Below is some example code that uses it. I use this interface to accomplish data binding in WPF. You could handle the event, discover the property that changed and act accordingly. You could even raise the event on another thread (PropertyChanged.BeginInvoke()) if you wanted the setter to be asynchronous...
using System;
using System.ComponentModel;
public class Foo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
C# doesn't support this natively, but you can go AOP via Interceptors in Windsor, which will give you a hit in runtime or use something like PostSharp to generate code for the calls to the events. PostSharp will inject the IL code after the assemblies are created, so it shouldn't give as big as performance hit as Windsor during runtime.
It is a good idea to read a bit more about AOP as well.
If you are trying to capture events off of properties accessed without a lot of duplicated coding while maintaining a seperation of concerns then you could look into Aspect Oriented Programming techniques using frameworks such as Castle, but beware that this is a complicated topic that includes hard choices about the architecture of your application.
1) No there isn't a property change event. If you're insistent on not creating extra variables you could go the AOP route. You should be satisfied without AOP unless there are countless properties you're dealing with, in which case you could opt for code-generation (maybe write a python/ruby script to generate code or use a common code generator)
2) I don't think you can change properties pre-runtime (in Visual Studio) without code generation.
Maybe I'm off here but what about something like this for #1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace EraseMe2
{
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.MyProperty = 100;
t.MyProperty = 500;
}
}
class Test
{
public int set(ref int prop, int val)
{
prop = val;
Console.WriteLine(String.Format("{0} changed to {1}", prop.GetType().Name, val.ToString()));
return val;
}
private int _myProperty;
public int MyProperty
{
get { return _myProperty; }
set
{
_myProperty = set(ref _myProperty, value);
}
}
}
}