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.
Related
I am developing an WPF application and tried to design something event driven using Prism's Event Aggregator.
Currently I am trying to implement something like event queue for Prism events.
To do that I want to subscribe related events and pass them to same method but Event Aggregator wants those methods to have same signature with the event.
Example events:
public class TestEvent1 : PubSubEvent<Class1>
{
}
public class TestEvent2 : PubSubEvent<Class2>
{
}
public class TestEvent3 : PubSubEvent<List<Class3>>
{
}
public class TestEvent3 : PubSubEvent<string>
{
}
Subscriptions:
_eventAggregator.GetEvent<TestEvent1>().Subscribe(OnTestEvent1, true);
_eventAggregator.GetEvent<TestEvent2>().Subscribe(OnTestEvent2, true);
_eventAggregator.GetEvent<TestEvent3>().Subscribe(OnTestEvent3, true);
Example callback method:
private void OnTestEvent1(Class1 object1)
{
// do something
}
Since I only receive data when event published, I tried something like this to use as event payload type, but it doesn't look right:
// Payload
public interface IMessage
{
public object Data { get; set; }
public Type Datatype { get; set; }
public PubSubEvent EventType { get; set; }
}
// Events
public class TestEvent1 : PubSubEvent<IMessage>
{
}
public class TestEvent2 : PubSubEvent<IMessage>
{
}
public class TestEvent3 : PubSubEvent<IMessage>
{
}
// Subscriptions
_eventAggregator.GetEvent<TestEvent1>().Subscribe(EventHandler, true);
_eventAggregator.GetEvent<TestEvent2>().Subscribe(EventHandler, true);
_eventAggregator.GetEvent<TestEvent3>().Subscribe(EventHandler, true);
// Callback
private void EventHandler(IMessage payload)
{
// do something
}
Is this viable and how can I improve or change my "generic" payload?
Extra information:
In my scenario I have multiple UDP servers that periodically receives new data, deserialize it to objects and publish events.
Related "managers" subscribed to those events and get triggered when new data received.
My goal is try to implement an event queue like system in my event receiving classes so it will be easier to deal with multithreading issues.
Here are some diagrams that may help me explain myself better:
My architecture:
My "event queue"
This is more of a code-review question, isn't it?
I would very much prefer strong typing, though, and I wouldn't want to build a queue around the event aggregator, that will always be tedious because you never know when new event types show up. Instead, I'd build my own event aggregator with queueing built in (starting from the existing one).
Also, I'd look into dataflow, for example, because the basic working mode of the event aggregator (fire and forget, one sender, multiple or no receivers) doesn't seem to work well with queueing. If you queue at the sender-side, to you wait for one receiver or all? Do you queue when there are no receivers or do you discard then? If you queue at the receiver-side, why bother at all? The receiver can implement the queue on its own.
When you publish an event with a reference to an object, consider these potential problems:
Any listener will be dependent on the type/assembly of the event parameter.
The referenced object will be held for some time. For how long? You don't know.
The referenced object could have been altered/disposed.
Listeners might handle the referenced object on a different thread.
After dealing with PubSubEvent<T> for several years now, I believe there is only one suitable pattern that successfully handles all cases. Publish your event with a unique identifier, e.g. a Guid.
public class MyItemAddedEvent : PubSubEvent<Guid> {}
Then inject a provider wherever you listen for this event:
public class SomeListener
{
private readonly IMyItemProvider myItemProvider;
[ImportingConstructor]
public SomeListener(IEventAggregator eventAggregator,
IMyItemProvider myItemProvider)
{
this.myItemProvider = myItemProvider;
eventAggregator.GetEvent<MyItemAddedEvent>().Subscribe(OnMyItemAdded, true);
}
private void OnMyItemAdded(Guid id)
{
var myItem = myItemProvider.Get(id);
// Do stuff
}
}
Now it is the responsibility of the provider class to deliver a valid and up-to-date object given a unique id.
I'd like to find how to separate my GUI and work code.
The contrived example code, below, is the smallest starting point that
I can think of that covers the idea.
The example uses a Windows Form as the source of commands and as display
(consumer) of results. I want the work code to be capable of getting commands from, say, a command line interface instead. The work code should not depend on knowledge of the Form. The Form should know little about the work code. I'd like to have several consumers "see" when the property in the work code changes value.
I'm guessing this means using events for communication, and perhaps Interfaces as well, but I'm open to anything.
There are a million different suggestions out there. I've read the design pattern books, and I have tried many, and have yet to find a set that is well enough explained that I can fully implement it.
I don't want a universal solution. I want one as simple as possible
to implement and maintain for small, personal projects. I'm not
designing for a large corporation.
Most solutions I've found will hint at what to do, but not cover
the specifics like where an event is declared, and how the other
piece of code finds out about the event's existence so it can either issue
the event or respond to the event. I always end up needing, somewhere, what amounts to a global variable to hook things together.
The closest match I can find, here, to my question is this: C# Windows Forms App: Separate GUI from Business Logic But the solution uses the form to create an instance of the worker and returns a value directly, rather than informing any interested observers. The provided solution tightly bound the two classes.
The closest solution I've found anywhere is this: https://www.codeproject.com/Articles/14660/WinForms-Model-View-Presenter
which does some really cool work with interfaces and reflection, but didn't seem too maintainable nor flexible.
The comment lines in the source code below show the desired interaction
points but without the implementation.
File #1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// tell an instance of JustCounts to increment by 10
}
// Here, allow JustCounts to cause a call to this (or something
// similar, perhaps a property) to inform this code that the TotalCount
// property has changed.
public void ShowNewTotalCount(int NewTotal)
{
Console.WriteLine("New Total Count = {0}", NewTotal);
}
}
File #2
class JustCounts
{
private int m_TotalCount = 100;
// Inform other classes when the following property changes value,
// preferably including the value in the notification.
public int TotalCount { get => m_TotalCount; }
// The code in File #1 needs to result in a call to this method
// along with the correct argument value.
public void AddThisMuch(int increment)
{
m_TotalCount += increment;
}
}
I'm basing this on the current version of .Net (4.6.2).
If we implement INotifyPropertyChanged then we have an event that we can listen to for property changes. A bit like listening for key presses, we can filter then for the specific property that we want.
public class JustCounts : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int m_totalCount = 100;
public int TotalCount
{
get { return m_totalCount; }
set
{
if (value != m_totalCount)
{
m_totalCount = value;
NotifyPropertyChanged();
}
}
}
}
There's no need to create a method to manipulate the TotalCount property as we're exposing it.
public class Form1 : Form
{
// justCounts is a reference to the object wherever it is coming from
justCounts.PropertyChanged += new PropertyChangedEventHandler(JustCountsChangedHandler);
private void JustCountsChangedHandler(object sender, PropertyChangingEventArgs e)
{
// process on event firing
Debug.WriteLine($"justCounts TotalCount changed value to {justCounts.TotalCount}");
}
// Example of where the handler will fire when called
private void button1_click(object sender, EventArgs e)
{
justCounts.TotalCount++;
}
}
In the code above, we've created an event in JustCounts to which listeners can subscribe.
Using the INotifyPropertyChanged interface, we fire the event each time TotalCount is changed.
In form 1 we create the handler to listen for property changes, and the handler then carries out any processing.
One note. You say
I'd like to have several consumers "see" when the property in the work
code changes value
so in order for this to work we have to assume that the work code can run independently of it's subscriber (something like a server). Otherwise, we'd have different instances for different subscribers.
You also mention interfaces, and they could be used but are not necessary in this instance.
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 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 ...