I have a class which facilitates the discovery of HID devices, when a device is detected an event is raised and subsequently detected by another class which will be ultimately responsible for the creation of an object to represent the HID device. The creation class raises an event of its own with the newly created HID object.
With this in mind I have a couple of design queries:
1)
I have done some research into the "best practices" with regards to the creation of an unknown number or type of object at runtime for which the Abstract Factory design pattern features frequently in the results. Does the Abstract Factory design pattern fit the scenario I have, or is there something else I should be doing?
2)
The HidFinder class raises an event to notify those interested (mostly the HidCreator class) that a device has been discovered. The HidCreator class then raises an event containing the newly created HID device. This seems like the correct method, however, confirmation either way would be appreciated.
Below is a dumbed down example of the code in question.
public class HidFinder
{
public event EventHandler<HidFoundArgs> HidFoundHandler;
private void DeviceAdded(object sender, EventArrivedEventArgs e)
{
OnHidFoundHandler(new HidFoundArgs());
}
protected virtual void OnHidFoundHandler(HidFoundArgs e)
{
EventHandler<HidFoundArgs> handler = this.HidFoundHandler;
if (handler != null)
{
handler(this, e);
}
}
}
public class HidCreator
{
private readonly HidFinder hidFinder;
public event EventHandler<IHidDevice> HidDeviceCreatedHandler;
public HidCreator(HidFinder hidFinder)
{
this.hidFinder = hidFinder;
this.hidFinder.HidFoundHandler += HidFinderOnHidFoundHandler;
}
private void HidFinderOnHidFoundHandler(object sender, HidFoundArgs hidFoundArgs)
{
// Create a new HID
var newHidDevice = Factory.CreateMethod();
OnHidDeviceCreatedHandler(newHidDevice);
}
protected virtual void OnHidDeviceCreatedHandler(IHidDevice e)
{
EventHandler<IHidDevice> handler = this.HidDeviceCreatedHandler;
if (handler != null)
{
handler(this, e);
}
}
}
It generally looks as good design, but I would make two changes:
Factory seems like some global object, it would be better to use Dependency Injection, for better unit testing for example.
Change Factory.CreateMethod to use parameters, as we don't know what exact implementation of IHidDevice will be created and if we won't need some additional info from HidFoundArgs
Code after changes:
public class HidCreator
{
private readonly HidFinder hidFinder;
private readonly IHidDeviceFactory factory;
public event EventHandler<IHidDevice> HidDeviceCreatedHandler;
public HidCreator(IHidDeviceFactory factory, HidFinder hidFinder)
{
this.factory = factory;
this.hidFinder = hidFinder;
this.hidFinder.HidFoundHandler += HidFinderOnHidFoundHandler;
}
private void HidFinderOnHidFoundHandler(object sender, HidFoundArgs hidFoundArgs)
{
// Create a new HID
var newHidDevice = factory.Create(HidFoundArgs.ToCreationParameters(hidFoundArgs));
OnHidDeviceCreatedHandler(newHidDevice);
}
protected virtual void OnHidDeviceCreatedHandler(IHidDevice e)
{
EventHandler<IHidDevice> handler = this.HidDeviceCreatedHandler;
if (handler != null)
{
handler(this, e);
}
}
}
public interface IHidDeviceFactory
{
IHidDevice Create(HidCreationParameters parameters);
...
}
public class HidCreationParameters
{
...
}
public class HidFoundArgs
{
public static HidCreationParameters ToCreationParameters(HidFoundArgs args)
{
...
}
}
Related
I'm building a MVVM application in which a ToBeListened class has a couple of properties, PropertyA and PropertyB, and I want to listen to them.
public class ToBeListened : INotifyPropertyChanged
{
private double _propertyA;
private string _propertyB;
/*Here I'm omitting the update part where NotifyPropertyChanged gets called*/
public double PropertyA{get; set; }
public double PropertyB{get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Those two properties are listened by a Listener class, so I've implemented an EventHandler in it, that listens to a ToBeListened object.
public class Listener
{
private ToBeListened toBeListenedObject;
public Listener()
{
toBeListenedObject = new ToBeListened();
toBeListenedObject.PropertyChanged += newPropertyChangedEventHandler(PropertyListener_PropertyChanged);
}
private void PropertyListener_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch(e.PropertyName)
{
case "PropertyA":
{
/*...DO SOMETHING...*/
}
case "PropertyB":
{
/*...Do something else...*/
}
}
The thing is, I don't really like this solution I've found. A switch-case isn't polymorphism-friendly, so
is there a better way to do this? Maybe something that uses overloading? (Like private void PropertyListener_PropertyChanged(double sender, PropertyChangedEventArgs e)
most of all, is it right to code a ViewModel like this?
I like Josh Smith's PropertyObserver, which you can get at http://mvvmfoundation.codeplex.com/ (some documentation from Josh at https://joshsmithonwpf.wordpress.com/2009/07/11/one-way-to-avoid-messy-propertychanged-event-handling/). It's a nice class that encapsulates the plumbing logic you're talking about, so you can focus on just handling changes to certain properties. So in your case, you could write code like:
var observer = new PropertyObserver<ToBeListened>(toBeListenedObject)
.RegisterHandler(tbl => tbl.PropertyA, tbl => HandlePropertyA(tbl))
.RegisterHandler(tbl => tbl.PropertyB, tbl => HandlePropertyB(tbl));
You can start using it by installing the MVVM Foundation nuget package into your solution. The ID is MvvmFoundation.Wpf.
In the past I've used a little class derived from Dictionary<string, Action> for this purpose. It was something like this:
public class PropertyChangedHandler : Dictionary<string, Action>
{
public PropertyChangedHandler(INotifyPropertyChanged source)
{
source.PropertyChanged += Source_PropertyChanged;
}
private void Source_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Action toDo;
if (TryGetValue(e.PropertyName, out toDo))
{
toDo();
}
}
}
Then your listener looks like this:
public class Listener
{
private ToBeListened toBeListenedObject = new ToBeListened();
PropertyChangedHandler handler;
public Listener()
{
handler = new PropertyChangedHandler(toBeListenedObject)
{
{ "PropertyA", DoA },
{ "PropertyB", DoB }
};
}
private void DoB()
{
}
private void DoA()
{
}
}
This is just an example to give you an idea - it can be expanded for more complex purposes, of course.
i think MVVM Light framework (or library?) has what you need. Take a look at their ObservableObject class http://www.mvvmlight.net/help/SL5/html/d457231f-6af7-601d-fa1f-1fe7c9f60c57.htm
Basically what it does, is making your object observable.
I'm currently writing an application in which I deserialize relatively large objects (which can also grow in size, depending on what the user adds to them). I don't want to load all of them into RAM since that might cause problems when there are many of them.
Anyway, I want to handle events raised by the loaded instance of that class if there is one which is already my problem.
How can I subscribe an event handler to an object that is still null?
I think of something like "if there is an object and it raises that event handle it with that method".
Here is some sample code and the only approach I could think of though I already thought it couldn't work..
public class MyClassA
{
public event EventHandler PropertyChanged;
private string someProperty
public string SomeProperty
{
set
{
someProperty = value;
PropertyChanged?.Invoke(this, EventArgs.Empty);
}
}
public static MyClassA Load(string path)
{
/*...*/
}
}
public class MyClassB
{
public MyClassA InstanceOfA { get; private set; }
public MyClassB
{
//InstanceOfA.PropertyChanged += MyEventHandler; Not working, NullReference
}
// Handle InstanceOfA.PropertyChanged here...
public void MyEventHandler(object sender, EventArgs e)
{
/*...*/
}
}
Of course you cannot subscribe an event handler to an object that is still null,but you can subscribe when you assign a non null value to it.
Just use a property and a backing field:
public class MyClassB
{
private MyClassA myVar;
public MyClassA InstanceOfA
{
get { return myVar; }
private set
{
myVar = value;
if (myVar != null)
myVar.PropertyChanged += MyEventHandler;
}
}
public void MyEventHandler(object sender, EventArgs e)
{
}
}
I have run into a bit of a design issue with my code.
I have a object that creates a child object (the child could then create another child, etc), and both objects subscribe to the same event.
But, I only want the most child object to receive the event.
Overview of what my project is:
I am creating a IVR system. When a user calls into the system, the user will have X menu choices. Based on what the user chooses they will have a sub menu of choices, and so on and so on. I am using State Machines for this. Every State Machine needs to "listen" for when the user presses a number on their phone. But only the current State Machine needs to process the entered number. Each State Machine can create a new State Machine to represent the sub menu.
Here is some sample code:
Base class:
public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
public event DoSomething myEvent;
private IObject foo;
public Base ()
{
foo = new myObjectA(this);
}
public void SomeAction()
{
((myObjectA)foo).CreateChild();
}
public void EventFired()
{
if (myEvent != null)
{
myEvent(this, new EventArgs());
}
}
}
ObjectA:
class myObjectA : IObject
{
private Base theCallingObject;
private IObject child;
public myObjectA (Base _base)
{
theCallingObject = _base;
theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
}
public void CreateChild()
{
child = new myObjectB(theCallingObject);
}
void theCallingObject_myEvent(object sender, EventArgs data)
{
// Handle event
MessageBox.Show("myObjectA");
}
}
ObjectB:
class myObjectB : IObject
{
private Base theCallingObject;
public myObjectB (Base _base)
{
theCallingObject = _base;
theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
}
void theCallingObject_myEvent(object sender, EventArgs data)
{
// Handle event
MessageBox.Show("myObjectB");
}
}
Now when I do this:
Base blah = new Base();
blah.SomeAction();
blah.EventFired();
I get message boxes for both A and B.
I need to implement Base so that only myObjectB gets the event.
I will have hundreds of myObject's so I need a implementation at the Base level and NOT the myObject level. Plus, handling it at the myObject level would still require the event to be fired causing performance issues if there are hundreds of objects.
One solution I have considered is when myObjectA creates the child, unsubscribe from the event, then resubscribe when we get back to the myObjectA level. However I feel something better could be done.
Anyone have any ideas?
Edit: Using payo's input I have come up with this:
public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
private IObject foo;
private List<DoSomething> _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage.Insert(0, value);
}
remove
{
_myEventStorage.Remove(value);
}
}
public Base ()
{
_myEventStorage = new List<DoSomething>();
foo = new myObjectA(this);
}
public void SomeAction()
{
((myObjectA)foo).CreateChild();
}
public void EventFired()
{
_myEventStorage[0].Invoke(this, new EventArgs());
}
}
you would need to explicitly implement myEvent (add/remove) handlers and track the "farthest" independently of the registered observers. then you can send the notification to that single instance.
For events, each subscriber is queued up (put at end of list), a FIFO model. You want the most-child object to 'own' the event, not just subscribe and be part of some abstract list of other unknown objects.
I would provide a new model that represents what you are trying to do. This might be what Jason recommended: (he posted his answer as I was typing this out)
public class Base
{
private DoSomething _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage = value;
}
remove
{
_myEventStorage -= value;
}
}
...
public void EventFired()
{
if (_myEventStorage != null)
{
_myEventStorage(this, new ChainEventArgs());
}
}
}
This calls last ONLY. Another option (to add to this custom add/remove) would be to provide a derived EventArgs:
public class ChainEventArgs : EventArgs
{
public bool Handled { get; set; }
}
public delegate void DoSomething(object sender, ChainEventArgs data);
...
public event DoSomething myEvent
{
add
{
var temp = _myEventStorage;
_myEventStorage = null;
_myEventStorage += value;
_myEventStorage += temp; // now all are called, but FILO
}
remove
{
_myEventStorage -= value;
}
}
At this point, you can either check Handled on each IObject
void theCallingObject_myEvent(object sender, ChainEventArgs data)
{
if (data.Handled)
return;
if (I_want_to_block_parents)
data.Handled = true;
// else leave it false
}
Or, add some complexity to your Base class and stop calling up the chain (let's the children have no need to check Handled). I'll show the solution with a List<> of delegates, but some MulticaseDelegate casts and calls could do the same. I just feel the List<> code might be more readable/maintainable.
public class Base
{
private List<DoSomething> _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage.Insert(0, value);
}
remove
{
_myEventStorage.Remove(value);
}
}
...
public void EventFired()
{
var args = new ChainEventArgs();
foreach (var handler in _myEventStorage)
{
handler(this, args);
if (args.Handled)
break;
}
}
}
I would like to create a dynamic proxy for binding WinForms controls to objects changed by a different (non-GUI) thread. Such a proxy would intercept the PropertyChanged event and dispatch it using the proper SynchronizationContext.
That way I could use a helper class to do the job, without having to implement the synchronization manually every time (if (control.InvokeRequired) etc.).
Is there a way to do that using LinFu, Castle or a similar library?
[Edit]
Data source is not necessarily a list. It can be any business object, e.g.:
interface IConnection : INotifyPropertyChanged
{
ConnectionStatus Status { get; }
}
I could create a wrapper which could do the job, and it would look something like this:
public class ConnectionWrapper : IConnection
{
private readonly SynchronizationContext _ctx;
private readonly IConnection _actual;
public ConnectionWrapper(IConnection actual)
{
_ctx = SynchronizationContext.Current;
_actual= actual;
_actual.PropertyChanged +=
new PropertyChangedEventHandler(actual_PropertyChanged);
}
// we have to do 2 things:
// 1. wrap each property manually
// 2. handle the source event and fire it on the GUI thread
private void PropertyChanged(object sender, PropertyChangedEvArgs e)
{
// we will send the same event args to the GUI thread
_ctx.Send(delegate { this.PropertyChanged(sender, e); }, null);
}
public ConnectionStatus Status
{ get { return _instance.Status; } }
public event PropertyChangedEventHandler PropertyChanged;
}
(there may be some errors in this code, I am making it up)
What I would like to do is to have a dynamic proxy (Reflection.Emit) one liner for this, e.g.
IConnection syncConnection
= new SyncPropertyChangedProxy<IConnection>(actualConnection);
and I wanted to know if something like this was possible using existing dynamic proxy implementations.
A more general question would be: How to intercept an event when creating a dynamic proxy? Intercepting (overriding) properties is explained well in all implementations.
[Edit2]
The reason (I think) I need a proxy is that the stack trace looks like this:
at PropertyManager.OnCurrentChanged(System.EventArgs e)
at BindToObject.PropValueChanged(object sender, EventArgs e)
at PropertyDescriptor.OnValueChanged(object component, EventArgs e)
at ReflectPropertyDescriptor.OnValueChanged(object component, EventArgs e)
at ReflectPropertyDescriptor.OnINotifyPropertyChanged(object component,
PropertyChangedEventArgs e)
at MyObject.OnPropertyChanged(string propertyName)
You can see that BindToObject.PropValueChanged does not pass the sender instance to the PropertyManager, and Reflector shows that sender object is not referenced anywhere. In other words, when the PropertyChanged event is triggered, component will use reflection to access the property of the original (bound) data source.
If I wrapped my object in a class containing only the event (as Sam proposed), such wrapper class would not contain any properties which could be accessed through Reflection.
Here's a class that will wrap a INotifyPropertyChanged, forward the PropertyChanged event through SynchronizationContext.Current, and forward the property.
This solution should work, but with some time it could be improved to use a lambda expression instead of a property name. That would allow getting rid the reflection, provide typed access to the property. The complication with this is you need to also get the expression tree from the lambda to pull out the property name so you can use it in the OnSourcePropertyChanged method. I saw a post about pulling a property name from a lambda expression tree but I couldn't find it just now.
To use this class, you'd want to change your binding like this:
Bindings.Add("TargetProperty", new SyncBindingWrapper<PropertyType>(source, "SourceProperty"), "Value");
And here's SyncBindingWrapper:
using System.ComponentModel;
using System.Reflection;
using System.Threading;
public class SyncBindingWrapper<T> : INotifyPropertyChanged
{
private readonly INotifyPropertyChanged _source;
private readonly PropertyInfo _property;
public event PropertyChangedEventHandler PropertyChanged;
public T Value
{
get
{
return (T)_property.GetValue(_source, null);
}
}
public SyncBindingWrapper(INotifyPropertyChanged source, string propertyName)
{
_source = source;
_property = source.GetType().GetProperty(propertyName);
source.PropertyChanged += OnSourcePropertyChanged;
}
private void OnSourcePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != _property.Name)
{
return;
}
PropertyChangedEventHandler propertyChanged = PropertyChanged;
if (propertyChanged == null)
{
return;
}
SynchronizationContext.Current.Send(state => propertyChanged(this, e), null);
}
}
I have come across the same problems and Samuel's solution didn't work for me, so I placed the synchronization context initialization in the constructor, and the "Value" property name should be passed instead of the original property. This worked for me:
public class SyncBindingWrapper: INotifyPropertyChanged
{
private readonly INotifyPropertyChanged _source;
private readonly PropertyInfo _property;
public event PropertyChangedEventHandler PropertyChanged;
private readonly SynchronizationContext _context;
public object Value
{
get
{
return _property.GetValue(_source, null);
}
}
public SyncBindingWrapper(INotifyPropertyChanged source, string propertyName)
{
_context = SynchronizationContext.Current;
_source = source;
_property = source.GetType().GetProperty(propertyName);
source.PropertyChanged += OnSourcePropertyChanged;
}
private void OnSourcePropertyChanged(object sender, PropertyChangedEventArgs e)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null && e.PropertyName == _property.Name)
{
_context.Send(state => propertyChanged(this, new PropertyChangedEventArgs("Value")), null);
}
}
}
Usage:
_textBox1.DataBindings.Add("Text", new SyncBindingWrapper(someObject, "SomeProperty"), "Value");
Without relying on the SynchrnoisationConext you can rely on ISynchronizeInvoke
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
foreach (EventHandler h in handler.GetInvocationList())
{
var synch = h.Target as ISynchronizeInvoke;
if (synch != null && synch.InvokeRequired)
synch.Invoke(h, new object[] { this, e });
else
h(this, e);
}
}
}
basically:
public delegate void RecvCommandHandler (ChatApplication sender, byte[] content);
event RecvCommandHandler[] commands = new RecvCommandHandler[255];
I want to activate a different method/function for each command number, but I am really uncertain of the syntax. How am I supposed to do it?
I think I'll go with just an array of delegates for this one, but the question is still interesting.
You could create an array of a class with operator overloading to simulate the behavior you are interested in...
public delegate void EventDelegate(EventData kEvent);
public class EventElement
{
protected event EventDelegate eventdelegate;
public void Dispatch(EventData kEvent)
{
if (eventdelegate != null)
{
eventdelegate(kEvent);
}
}
public static EventElement operator +(EventElement kElement, EventDelegate kDelegate)
{
kElement.eventdelegate += kDelegate;
return kElement;
}
public static EventElement operator -(EventElement kElement, EventDelegate kDelegate)
{
kElement.eventdelegate -= kDelegate;
return kElement;
}
}
public EventElement[] commands = new EventElement[255];
commands[100] += OnWhatever;
commands[100].Dispatch(new EventData());
commands[100] -= OnWhatever;
There's really no concept of an array of events - it's like talking about an array of properties. Events are really just methods which let you subscribe and unsubscribe handlers. If you need to be able to do this by index, I suggest you just have a pair of methods. (AddCommandHandler(int, RecvCommandHandler) and RemoveCommandHandler(int, RecvCommandHandler)). That won't support the normal event handling syntactic sugar, of course, but I don't see that there's a lot of alternative.
The other option is to specify and index in the delegate prototype and have one event handler that "delegates" to the others, e.g.:
public delegate void RecvCommandHandler (int id, ChatApplication sender, byte[] content);
// ...
private RecvCommandHandler[] internalhandlers;
public void MyCommandHandler(int id, ChatApplication sender, byte[] content)
{
internalHandlers[id](id, sender, content);
}
I was just looking for the same answer, however my class is also event sender for WPF, so it should look as much as normal C#/WPF event sender class. So I simply added this:
To sender:
enum with properties name -- this is lame workaround for lack of nameof
one additional method to record requests
To receiver:
request event for given enum
The code, sender:
public enum Properties
{
NetworkFileName,
DatasetFileName,
LearningWatch
}
private string network_filename;
public string NetworkFileName
{
get { return network_filename; }
private set
{
if (network_filename != value)
{
network_filename = value;
OnPropertyChanged(Properties.NetworkFileName.ToString());
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public void OnChange(Properties prop, Action<object, PropertyChangedEventArgs> action)
{
PropertyChanged += new PropertyChangedEventHandler((obj, args) => { if (args.PropertyName == prop.ToString()) action(obj, args); });
}
And to the receiver:
private void OnNetworkLoaded(object sender, PropertyChangedEventArgs e)
{
SetTitle();
}
...
ExpManager.OnChange(ExperimentManager.Properties.DatasetFileName, OnDatasetLoaded);
It is still ugly, but at least:
I don't have to deal with "ifs" in receiver
I can easily create multiple event handlers
it is compatible with WPF
no magic strings (I hate those)
Disadvantage:
obsfuscation ruins this (but I have special class for that case, this project is just for me, so no problem here)