I have created a test project as a POC for this problem.
I have a WPF app, that when we use interceptors around the view models, it's stopping the propagation of events. If I disable all interceptors, it works fine.
Here is the code:
MyInterceptor.cs
public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
}
}
IoCTestViewModel.cs
public interface IIoCTestViewModel : INotifyPropertyChanged
{
int Number { get; }
}
public class IoCTestViewModel : IIoCTestViewModel
{
public IoCTestViewModel()
{
var timer = new Timer(200);
timer.Elapsed += (a, b) => {
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Number"));
}
};
timer.Start();
}
public int Number
{
get
{
return new Random().Next(1, 100);
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
IoCTest.xaml.cs
public partial class IoCTest : UserControl
{
public IIoCTestViewModel ViewModel { get; set; }
public IoCTest(IIoCTestViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
}
App.xaml (fragment)
Container = new WindsorContainer();
Container.Register(Component.For<MyInterceptor>().ImplementedBy<MyInterceptor>());
Container.Register(Component.For<IIoCTestViewModel>().ImplementedBy<IoCTestViewModel>().Interceptors<MyInterceptor>());
Container.Register(Component.For<IoCPage>().ImplementedBy<IoCTest>()); //IoCTest is a usercontrol
OK. So once I get an instance of IoCTest and add it to a page, I don't see any changes, even though I am sending PropertyChanged every 200ms. If I remove the interceptor, everything works fine.
So how do I fix this?
The issue here is that because you declare your service to be IIoCTestViewModel, when you add an interceptor Windsor simply creates a dynamic proxy that delegates all calls to your implementation type. However, the interception is done using composition - one object delegating to another. Hence, when you raise your property changed event with a sender of this, it is a different object to the one that WPF thinks it is watching.
You should instead register your view model like this:
Container.Register(Component.For<IIoCTestViewModel,IoCTestViewModel>().ImplementedBy<IoCTestViewModel>().Interceptors<MyInterceptor>())
By specifying multiple services, one of which is actually your implementation class, Windsor will instead generate a class proxy - i.e. the interception will be done using inheritance, with the generated proxy inheriting from IoCTestViewModel. (This is known as type forwarding in Windsor). Now when you raise your event with a sender of this it correctly refers to the same instance that WPF is watching.
See here for a more detailed explanation of type forwarding and its implications for proxies
Related
I recently started learning C# to start doing a project of mine. I ran into a problem, where i have to Classes dependent on each other. I have a class called MQTT_Handler which handles everything related MQTT and a Winforms class. The problem is that I need both classes to work with each other. So to control the Form class from the MQTT_class I passed over the Form instance to the constructor of the MQTT_class and delegated some methods, which works so far.
Now I have the problem that I also want send some messages over MQTT from the Form class. There is my problem.
I start everything from Program.cs which looks like this:
static void Main()
{
ApplicationConfiguration.Initialize();
UI UIInstance = new UI();
MQTT_Handler mqtt_handler = new MQTT_Handler(UIInstance);
mqtt_handler.MQTT_Client();
Application.Run(UIInstance);
}
Now what I wanted to do is just passing the matt_handler instance over to UI. But doing that would obviously create a circular dependency. Is there any way of passing an instance to a class after it has been created?
This is my MQTT class:
class MQTT_Handler
{
private UI UIInstance;
// Constructor
public MQTT_Handler(UI formInstance)
{
UIInstance = formInstance;
DelegateMethod = new changeLabelDelegate(UIInstance.change_labelMethod);
MQTT_Client();
}
}
And UI:
public partial class UI : Form
{
public delegate void changeLabelDelegate(string text);
//Constructor
public UI()
{
InitializeComponent();
}
}
The most obvious solution (to me) is to make the UI dependent on the MQTT handler. This handler should not need any knowledge about the UI.
This can be accomplished in several ways. Two examples:
Make DelegateMethod a property of MQTT_Handler and give it a suitable value when UI is instantiated:
class MQTT_Handler
{
public Action<string> DelegateMethod {get;set;}
// Constructor
public MQTT_Handler()
{
DelegateMethod = (s) => {;};
MQTT_Client();
}
}
And UI:
public partial class UI : Form
{
private MQTT_Handler _handler;
//Constructor
public UI(MQTT_Handler handler)
{
InitializeComponent();
_handler = handler;
_handler.DelegateMethod = change_labelMethod;
}
}
The second examples uses an event in the `MQTT-Handler' to notify the UI that the label needs changing (this is something of a variation on the same theme as the first example):
class MQTT_Handler
{
private Action<string> DelegateMethod;
public event? Action<string> MqttValueChanged;
// Constructor
public MQTT_Handler()
{
DelegateMethod = (s) => MqttValueChanged?.Invoke(s);
MQTT_Client();
}
}
And UI:
public partial class UI : Form
{
private MQTT_Handler _handler;
//Constructor
public UI(MQTT_Handler handler)
{
InitializeComponent();
_handler = handler;
_handler.MqttValueChanged += change_labelMethod;
}
}
Note: this second example can obviously be optimised by removing DelegateMethod in MQTT_handler and invoking the event directly wherever you would call DelegateMethod.
I am playing around with using Akka.NET in a new WPF .NET Framework application I am currently working on.
Mostly the process of using actors in your application seems pretty self explanitory, however when it comes to actually utilising the actor output at the application view level I have gotten a bit stuck.
Specifically there appear to be two options on how you might handle receiving and processing events in your actor.
Create an actor with publically exposed event handlers. So maybe something like this:
public class DoActionActor : ReceiveActor
{
public event EventHandler<EventArgs> MessageReceived;
private readonly ActorSelection _doActionRemoteActor;
public DoActionActor(ActorSelection doActionRemoteActor)
{
this._doActionRemoteActor = doActionRemoteActor ?? throw new ArgumentNullException("doActionRemoteActor must be provided.");
this.Receive<GetAllStuffRequest>(this.HandleGetAllStuffRequestReceived);
this.Receive<GetAllStuffResponse>(this.HandleGetAllStuffResponseReceived);
}
public static Props Props(ActorSystem actorSystem, string doActionRemoteActorPath)
{
ActorSelection doActionRemoteActor = actorSystem.ActorSelection(doActionRemoteActorPath);
return Akka.Actor.Props.Create(() => new DoActionActor(doActionRemoteActor));
}
private void HandleGetAllStuffResponseReceived(GetAllTablesResponse obj)
{
this.MessageReceived?.Invoke(this, new EventArgs());
}
private void HandleGetAllStuffRequestReceived(GetAllTablesRequest obj)
{
this._doActionRemoteActor.Tell(obj, this.Sender);
}
}
So basically you can then create your view and invoke any calls by doing something like this _doActionActor.Tell(new GetStuffRequest()); and then handle the output through the event handler. This works well but seems to break the 'Actors 'everywhere' model' that Akka.NET encourages and I am not sure about the concurrency implications from such an approach.
The alternative appears to be to actually make it such that my ViewModels are actors themselves. So basically I have something that looks like this.
public abstract class BaseViewModel : ReceiveActor, IViewModel
{
public event PropertyChangedEventHandler PropertyChanged;
public abstract Props GetProps();
protected void RaisePropertyChanged(PropertyChangedEventArgs eventArgs)
{
this.PropertyChanged?.Invoke(this, eventArgs);
}
}
public class MainWindowViewModel : BaseViewModel
{
public MainWindowViewModel()
{
this.Receive<GetAllTablesResponse>(this.HandleGetAllTablesResponseReceived);
ActorManager.Instance.Table.Tell(new GetAllTablesRequest(1), this.Self);
}
public override Props GetProps()
{
return Akka.Actor.Props.Create(() => new MainWindowViewModel());
}
private void HandleGetAllTablesResponseReceived(GetAllTablesResponse obj)
{
}
}
This way I can handle actor events directly in actors themselves (which are actually my view models).
The problem I run into when trying to do this is correctly configuring my Ioc (Castle Windsor) to correctly build Akka.NET instances.
So I have some code to create the Akka.NET object that looks like this
Classes.FromThisAssembly()
.BasedOn<BaseViewModel>()
.Configure(config => config.UsingFactoryMethod((kernel, componentModel, context) =>
{
var props = Props.Create(context.RequestedType);
var result = ActorManager.Instance.System.ActorOf(props, context.RequestedType.Name);
return result;
}))
This works great at actually creating an instance of IActorRef BUT unfortunately I cannot cast the actor reference back to the actual object I need (in this case BaseViewModel).
So if I try to do this return (BaseViewModel)result; I get an invalid cast exception. Which obviously makes sense because I am getting an IActorRef object not a BaseViewModel.
So in conclusion I am hoping to get two questions answered.
What is the best way to deal with Akka.NET actors in MVVM applications, specifically when it comes to handling messages received and handling displaying the output.
Is there a way to correctly configure my Ioc system to both create an IActorRef instance and add it to the system BUT return an instance of the actual parent actor object concrete implementation of BaseViewModel?
Below is the current solution that I am using in the hope someone might propose something a bit better.
Basically I have abandoned my attempt at making my views actors and currently settled on using an interface to communicate between the ViewModel and Actor.
The current solution looks like this:
public class MainWindowViewModel : BaseViewModel, ITableResponseHandler
{
public void HandleResponse(IEnumerable<Entity> allEntities) { }
}
public interface ITableResponseHandler
{
void HandleResponse(IEnumerable<Entity> allEntities);
}
public class MyActor : ReceiveActor
{
public MyActor(ITableResponseHandler viewModel)
{
this.Receive<GetAllEntitiesResponse>(this.HandleGetAllEntitiesResponseReceived);
}
private void HandleGetAllEntitiesResponseReceived(GetAllTablesResponse obj)
{
this._ViewModel.HandleTablesResponse(obj.Result);
}
}
While I don't feel this is ideal it basically lets me avoid all the extra complexity of trying to make my view models themselves actors while sufficently decoupling the actor from the view.
I hope someone else has faced this problem and might be able to provide some insight at a better solution for handling Akka.NET output in a MVVM application.
Quite some time ago, I noticed that the Windows Forms editor of Visual Studio does not support events which contain generic type parameters. For example, an event like
public event EventHandler<ListEventArgs<int>> MyStrangeEvent { add { ... } remove { ... } }
where
public class ListEventArgs<T> : EventArgs { List<T> args; }
does not even show up in the event list in the property manager of Visual Studio. Now, this is a somewhat artificial example that could easily be modified to work in Visual Studio by rewriting the classes and their events. However, I am currently working on a project where I cannot change some classes for compatibility reasons. The only thing I can do is to change the events of my user control. The events of this control currently look like this:
public event EventHandler<Plane<GDISurface>.DrawingErrorEventArgs> DrawingError { add { _Plane.DrawingError += value; } remove { _Plane.DrawingError -= value; } }
Note that the underlying Plane class (represented by the _Plane instance which is a protected field) cannot be changed. Its DrawingError event and its EventArgs type are declared in the Plane class like this:
public class Plane<T> where T : ISurface
{
...
public event EventHandler<DrawingErrorEventArgs> DrawingError = null;
...
public class DrawingErrorEventArgs : EventArgs { ... /* Uses T */ ... }
}
Of course, the Windows Forms editor of Visual Studio does not show any of the events of my user control. I have been looking for a number of workarounds to get them shown again, but have not been able to find a workaround that actually works. Here are some things that I tried:
Created a MyPlane class which inherits from Plane and used that instead: public event EventHandler<MyPlane.DrawingErrorEventArgs> DrawingError .... For reasons unknown to me, the events still don't show up in the editor. Perhaps this is due to the parameters of the event, some of which still are generic. Find a minimal working example below.
Created a helper class which defines implicit conversion operators between EventHandler<Plane<GDISurface>.DrawingErrorEventArgs> and EventHandler<GDIPlane.DrawingErrorEventArgs> where GDIPlane is just a dummy class which inherits from Plane<GDISurface>. This does work to some extent, but duplicates event calls since the conversion creates new event handlers which are passed down to _Plane which cannot be removed/unregistered properly.
Tried to inherit from EventHandler<Plane<GDISurface>.DrawingErrorEventArgs>, which obviously does not work since EventHandler<T> is sealed.
Are there any other ways to make my events visible again in the Windows Forms editor?
Best regards
Andreas
EDIT: Minimal working example for 1:
public interface ISurface { }
public class GDISurface : ISurface { }
public class Plane<T> where T : ISurface
{
public event EventHandler<DrawingErrorEventArgs> DrawingError = null;
public class DrawingErrorEventArgs : EventArgs { T stuff; }
}
public class TestControl : UserControl
{
public class GDIPlane : Plane<GDISurface> { }
GDIPlane _Plane = null;
public event EventHandler<GDIPlane.DrawingErrorEventArgs> DrawingError { add { _Plane.DrawingError += value; } remove { _Plane.DrawingError -= value; } }
}
DrawingError does not show up in the list of events in the property manager when clicking on a TestControl instance.
EDIT2: This is the original problem (without any workarounds) where the DrawingError event does of TestControl does not show up either:
public interface ISurface { }
public class GDISurface : ISurface { }
public class Plane<T> where T : ISurface
{
public event EventHandler<DrawingErrorEventArgs> DrawingError = null;
public class DrawingErrorEventArgs : EventArgs { T stuff; }
}
public class TestControl : UserControl
{
Plane<GDISurface> _Plane = null;
public event EventHandler<Plane<GDISurface>.DrawingErrorEventArgs> DrawingError { add { _Plane.DrawingError += value; } remove { _Plane.DrawingError -= value; } }
}
This is behavior specific to Visual Studio, and the cause is rooted in the fact that EventHandler<> does not specify covariance on its 'TEventArgs' (it would impose seemingly silly restrictions) and the tools do not perform enough introspection of your code to suss out an appropriate type (even though you've left a trail of type data in constructing the control.) Thus, it seems as though VS does not support generic event properties. You may consider filing a feature request on Microsoft Connect, I wouldn't suggest filing it as a bug as they may label it "by design" and close it.
As a general rule, if you need generic type parameters on your events and you need design time support for them (which are different implementation concerns), you're looking at wrapping them in a presentation-specific facade (e.g. "extra layer of code to facilitate design-time needs".)
Personally, I would reduce the generic typing you have in play now, it seems a bit excessive and if you don't understand covariance/contravariance in generic types it might put you in a tight spot at some point, such as now.
However, to work around your problem:
Consider using a custom event args class which could transport data in a non-generic property, and also use a non-generic EventHandler event/property. Understanding the 'type' of the event is then shifted away from generic type parameters and made the responsibility of your non-generic event args instead. If the 'class' of the event args is insufficient, you can add a property to convey the event type (or data type) so that receiving code can properly interpret it (assuming, of course, that it does not already know by some other means.):
public class DataEventArgs : EventArgs
{
//public string EventTypeOrPurpose { get; set; }
public object Data { get; set; }
}
This is most often only used to ferry data through an event chain, and it is usually implemented as follows:
public class DataEventArgs<T> : EventArgs
{
public T Data { get; set; }
}
Unfortunately, this also has a covariance problem, to resolve it you would actually want something more like this:
public interface IDataArgs<out T>
{
T Data { get; }
}
public class DataEventArgs<T> : EventArgs, IDataArgs<T>
{
public DataEventArgs<T>(T data)
{
_data = data;
}
private T _data;
public T Data { get { return _data; } }
}
Even so, these generic versions still don't work around Visual Studio's limitations, this is merely more proper alternative forms of what you already have shown us.
UPDATE: As requested, here is what a "purpose built facade" might look like in the most basic sense. Note that the usercontrol functions as a facade layer in this case as the eventhandler it exposes delegates to the underlying object model. There is no direct access to underlying object model from the user control (from consumer/designer perspective.)
Please note the reference tracking for event handlers is not necessary unless you dispose of these user controls throughout the lifetime of the app (it is only done to ensure proper delegate removal based on the delegate provided, which is wrapped in a closure/delegate, as you see below.)
Also worth noting I did not test-run this code beyond verifying that the designer shows DrawingError in the property grid when dropped onto a form.
namespace SampleCase3
{
public interface ISurface { }
public class GDISurface : ISurface { }
public class Plane<T> where T : ISurface
{
public event EventHandler<DrawingErrorEventArgs> DrawingError;
public class DrawingErrorEventArgs : EventArgs { T stuff; }
}
public class TestControl : UserControl
{
private Plane<GDISurface> _Plane = new Plane<GDISurface>(); // requires initialization for my own testing
public TestControl()
{
}
// i am adding this map *only* so that the removal of an event handler can be done properly
private Dictionary<EventHandler, EventHandler<Plane<GDISurface>.DrawingErrorEventArgs>> _cleanupMap = new Dictionary<EventHandler, EventHandler<Plane<GDISurface>.DrawingErrorEventArgs>>();
public event EventHandler DrawingError
{
add
{
var nonGenericHandler = value;
var genericHandler = (EventHandler<Plane<GDISurface>.DrawingErrorEventArgs>)delegate(object sender, Plane<GDISurface>.DrawingErrorEventArgs e)
{
nonGenericHandler(sender, e);
};
_Plane.DrawingError += genericHandler;
_cleanupMap[nonGenericHandler] = genericHandler;
}
remove
{
var nonGenericHandler = value;
var genericHandler = default(EventHandler<Plane<GDISurface>.DrawingErrorEventArgs>);
if (_cleanupMap.TryGetValue(nonGenericHandler, out genericHandler))
{
_Plane.DrawingError -= genericHandler;
_cleanupMap.Remove(nonGenericHandler);
}
}
}
}
}
To complement the above, here is what a non-generic event handler would now look like:
private void testControl1_DrawingError(object sender, EventArgs e)
{
var genericDrawingErrorEventArgs = e as Plane<GDISurface>.DrawingErrorEventArgs;
if (genericDrawingErrorEventArgs != null)
{
// TODO:
}
}
Note that the consumer here has to have knowledge of the type for e to perform conversion. The use of the as operator will bypass ancestry checks under the assumption that the conversion should succeed.
Something like this is as close as you're going to get. Yes it is ugly by most of our standards, but if you absolutely 'need' design-time support on top of these components and you cannot change Plane<T> (which would be more appropriate) then this, or something close to this, is the only viable workaround.
HTH
I have a WCF service that uses Simple Injector for dependency injection. I want to wire up some event handlers in the container bootstrapper. I have created an interface IStatusChangeNotification:
public interface IStatusChangeNotification
{
event EventHandler<int> JobStatusChange;
}
My CommandHandler implements IStatusChangeNotification and there are two event handler classes EmailNotification and MmrNotification, each defining a Notify() method. Then in my bootstrap code I have the following:
container.Register<EmailNotification>();
container.Register<MmrNotification>();
container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>),
Assembly.GetExecutingAssembly());
container.RegisterInitializer<IStatusChangeNotification>(scn =>
{
scn.JobStatusChange += container.GetInstance<EmailNotification>().Notify;
scn.JobStatusChange += container.GetInstance<MmrNotification>().Notify;
});
This works and the notifications are received. My question is whether this is the correct/best approach for wiring up event handlers? How do I remove the handlers at the end of the request and will failing to remove them result in a memory leak?
Although your approach might work, I think this part of your system design might deserve the same amount of attention as your command handlers do. The most common reason for command handlers to trigger events, is to publishing events that describe some business related action. So instead of using .NET events, model those domain events the same way as you model your commands:
// Abstractions
public interface IEventHandler<TEvent> where TEvent : IDomainEvent {
void Handle(TEvent e);
}
public interface IEventPublisher {
void Publish<TEvent>(TEvent e) where TEvent : IDomainEvent;
}
// Events
public class JobStatusChanged : IDomainEvent {
public readonly int JobId;
public JobStatusChanged(int jobId) {
this.JobId = jobId;
}
}
// Container-specific Event Publisher implementation
public class SimpleInjectorEventPublisher : IEventPublisher {
private readonly Container container;
public SimpleInjectorEventPublisher(Container container) {
this.container = container;
}
public void Publish<TEvent>(TEvent e) {
var handlers = container.GetAllInstances<IEventHandler<TEvent>>();
foreach (var handler in handlers) {
hanlder.Handle(e);
}
}
}
With the previous infrastructure, you can create the following event and command handlers:
// Event Handlers
public class EmailNotificationJobStatusChangedHandler
: IEventHandler<JobStatusChanged> {
public void Handle(JobStatusChanged e) {
// TODO: Implementation
}
}
public class MmrNotificationJobStatusChangedHandler
: IEventHandler<JobStatusChanged> {
public void Handle(JobStatusChanged e) {
// TODO: Implementation
}
}
// Command Handler that publishes
public class ChangeJobStatusCommandHandler : ICommandHandler<ChangeJobStatus> {
private readonly IEventPublisher publisher;
public ChangeJobStatusCommandHandler(IEventPublisher publisher) {
this.publisher = publisher;
}
public void Handle(ChangeJobStatus command) {
// change job status
this.publisher.Publish(new JobStatusChanged(command.JobId));
}
}
Now you can register your command handlers and event handlers as follows:
container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>),
Assembly.GetExecutingAssembly());
// This registers a collection of eventhandlers with RegisterAll,
// since there can be multiple implementations for the same event.
container.RegisterManyForOpenGeneric(typeof(IEventHandler<>),
container.RegisterAll,
Assembly.GetExecutingAssembly());
This removes the need to register each event handler class seperately, since they are simply implementations of IEventHandler<JobStatusChanged> and can all be batch-registered in one line of code. There's also no need to use RegisterInitializer to hook any events using custom defined interfaces.
Other advantages of this are:
The dependency between a command handler and the IEventPublisher interface makes it very clear that this command is publishing events.
The design is much more scalable, since its less likely for the composition root to have to change when new commands and events are added to the system.
It does your domain much good, since each event gets its own entity in the system.
It will be much easier to change the way events are processed, since that's now an implementation detail of the SimpleInjectorEventProcessor. For instance, you can deside to run them in parallel, run them in their own transaction, process them later (by storing them in an event store).
in a service class I have a method at which end I want to raise an event that can be listened by other two services.
This is how I'm trying to do it. But my problem is that the null check for the handler is always true.
Inside the IProfileService file I define the delegate and the actual interface
public delegate void PersonDetailsUpdated(Person person, bool personDetailsWereUpdated);
public interface IProfileService
{
void UpdateContactDetails(Person person);
event PersonDetailsUpdated PersonDetailsUpdatedEvent;
}
And this is the instance of that interface
public class ProfileService : IProfileService
{
// ... Dealing with dependency injection
public event PersonDetailsUpdated PersonDetailsUpdatedEvent;
public void UpdateContactDetails(Person person)
{
//... Doing stuff
//We raise an event
var handler = PersonDetailsUpdatedEvent;
if (handler != null)
{
handler(person, personDetailsWereUpdated);
}
}
}
}
Now in the other two services I do this (I only put the code of one of them)
internal class CustomerSmsService : ICustomerSmsService
{
private readonly IPersonDAL _personDal;
// ... Other dependencies...
public CustomerSmsService(IPersonDAL personDal, /* ... the other dependencies */ IProfileService profileService)
{
_personDal = personDal;
//... Again the other dependencies
profileService.PersonDetailsUpdatedEvent += (SendPhoneValidationCode);
}
//... Other methods
// What I understand is the so called Listener
public void SendPhoneValidationCode(Person person, bool personDetailsWereUpdated)
{
//Stuff
}
}
Maybe the answer is obvious but haven't worked with events before and I'm finding it impossible to figure out or to find an example that is clear enough for me although there's quite a bunch of them. But they seem to have followed another approach.
Thanks