Published Event not being subscribed or Published - c#

When I am trying to publish an events from SimpleFreeDrawModifier class to FieldSettingViewModel class, Subscriber class not able to get subscribe the events or vice versa.
Publishing Events Code:
public SimpleFreeDrawModifier(RegionManager regionManager, EventAggregator eventAggragator) // Constructor
{
_regionManager = regionManager;
_eventAggragator = eventAggragator;
CorodinatesMapDictionary =new Dictionary<object, object>();
}
private void AppendPoint(Point mousePoint)
{
// On Mouse-down, append another point
if (_dataSeries != null)
{
CorodinatesMapDictionary.Clear();
_dataSeries.Append((double)XAxis.GetDataValue(mousePoint.X), (double)YAxis.GetDataValue(mousePoint.Y));
GlobalVar.XCoordinate=(double)_dataSeries.XValues[0];
GlobalVar.YCoordinate=(double)_dataSeries.YValues[0];
CorodinatesMapDictionary.Add("X", GlobalVar.XCoordinate);
CorodinatesMapDictionary.Add("Y", GlobalVar.YCoordinate);
var calc = Math.Abs(GlobalVar.XCoordinate) * 1.0913;
if (GlobalVar.YCoordinate < 0)
{
if (GlobalVar.YCoordinate >= -(calc))
{
_eventAggragator.GetEvent<MapCoOrdinateChangedEvents>().Publish();
}
}
else
{
if(Math.Abs(GlobalVar.XCoordinate) <=25 && GlobalVar.YCoordinate <=25)
{
_eventAggragator.GetEvent<MapCoOrdinateChangedEvents>().Publish();
}
}
}
}
Subscribing Events Code
public FieldSettingViewModel(RegionManager regionManager,IEventAggregator eventAggragator)
{
_regionManager = regionManager;
_eventAggragator = eventAggragator;
ClearCommand = new DelegateCommand(Clear);
ApplyFieldSettingCommand = new DelegateCommand(ApplyFieldSetting, canApplyFieldSetting);
ScanAreaDataSeries = new XyDataSeries<double, double>();
GetScanSeriesData();
_eventAggragator.GetEvent<MapCoOrdinateChangedEvents>().Subscribe(MapValue);
}
private void MapValue()
{
//throw new NotImplementedException();
}
Could you please provide any suggestions?

Correct me if I'm wrong but it looks like instantiation of SimpleFreeDrawModifier and FieldSettingViewModel is achieved through dependency injection.
Are you sure that an instance of FieldSettingViewModel has been created and the it's receiving the same instance of IEventAggregator?
This minimal example without DI works
using System.Drawing;
using Prism.Events;
var eventAggregator = new EventAggregator();
var pub = new Publisher(eventAggregator);
var sub = new Subscriber(eventAggregator);
pub.AppendPoint(new Point());
public class Publisher
{
private IEventAggregator _eventAggregator;
public Publisher(IEventAggregator eventAggregator) // Constructor
{
_eventAggregator = eventAggregator;
}
public void AppendPoint(Point mousePoint)
{
_eventAggregator.GetEvent<MapCoOrdinateChangedEvents>().Publish();
}
}
public class Subscriber
{
private IEventAggregator _eventAggregator;
public Subscriber(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<MapCoOrdinateChangedEvents>().Subscribe(MapValue);
}
private void MapValue()
{
Console.WriteLine("Map value called");
}
}
internal class MapCoOrdinateChangedEvents : PubSubEvent
{
}
Check the DI lifetime of your EventAggregator is Singleton and not Transient, also try putting a breakpoint in the constructor of FieldSettingViewModel to ensure it is run.
If it's not being run and you're registering it for DI like services.AddSingleton<FieldSettingViewModel>(), try instead using services.AddSingleton<FieldSettingViewModel>(new FieldSettingViewModel()) to ensure there is one instantiated.

The constructor of SimpleFreeDrawModifier use EventAggregator instead of the interface IEventAggregator therefore as precised by hwoodiwiss they are not using the same instance even if it has been registered as singleton.
It already happenned to me and it took me quite some time to see the missing I

Related

Listening to raised event in .NET Core Web API service

I will keep it simple. I have two services in my ASP.NET Core WebAPI project.
ServiceA and ServiceB.
Service A is responsible for sending emails when Service B raises an event. Service B has an event handler and a delegate and the event is raised correctly. However, the problem is in Service A when trying to handle the event via += EventHandlingMethod();
The handler method EventHandlingMethod() is never called. I have placed a breakpoint inside the method but it never triggers, event after method EventRaised() has been called from Service B correctly.
Is it possible because Service A is set up in Startup.cs as services.AddTransient<IServiceA, ServiceA>();?
I have provided a simple example of publish-subscribe pattern. This is synchronous but if you are looking for an asynchronous version you can use channels or any other message broker such as RabbitMQ / NServiceBus etc.
public class PublishSubscribeMiddleMan: IPubSub
{
Dictionary<Type, List<ISubscriber>> pubSub = new Dictionary<Type, List<ISubscriber>>();
public void PublishEvent<Publisher>(Publisher publisher)
{
Type t = publisher.GetType();
if (pubSub.TryGetValue(t, out var subscribers))
{
subscribers.ForEach(subscriber => subscriber.EventHandlingMethod());
}
}
public void Subscribe<Publisher>(ISubscriber subscriber)
{
Type t = typeof(Publisher);
if (pubSub.TryGetValue(t, out var subscribers))
{
subscribers.Add(subscriber);
}
else pubSub.Add(t, new List<ISubscriber> { subscriber });
}
}
public interface ISubscriber
{
void EventHandlingMethod();
}
public interface IPubSub
{
void Subscribe<Publisher>(ISubscriber subscriber);
void PublishEvent<Publisher>(Publisher publisher);
}
public class ServiceA : IServiceA
{
private readonly IPubSub publishSubscribe;
public ServiceA(IPubSub publishSubscribe)
{
this.publishSubscribe = publishSubscribe;
}
public void RaiseEvent()
{
publishSubscribe.PublishEvent(this);
}
}
public interface IServiceA
{
void RaiseEvent();
}
public class ServiceB : ISubscriber
{
public ServiceB(IPubSub publishSubscribe)
{
publishSubscribe.Subscribe<ServiceA>(this);
}
public void EventHandlingMethod()
{
//throw new NotImplementedException();
}
}
You would need to register the PubSub inside ConfigureServices as shown:
services.AddScoped<IPubSub, PublishSubscribeMiddleMan>();
services.AddTransient<IServiceA, ServiceA>();

Creating ViewModels using MEF in a MVVM

This is going to be a bit lengthy, so hold on tight.
I have a project that uses Caliburn.Micro to implement MVVM pattern. For IoC, I am using MEF. All the ViewModels are marked with attribute [Export(typeof(IScreen))] . IScreen is defined in Caliburn.Micro.
In my BootStrapper file I have set up MEF like so:
private CompositionContainer container;
protected override void Configure()
{
//Set up MEF
container = new CompositionContainer(new AggregateCatalog``AssemblySource.Instance.Select``(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
var batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container);
container.Compose(batch);
//Other stuff
}
Now, I show the first ViewModel using
protected override void OnStartup(object sender, StartupEventArgs e) => DisplayRootViewFor<ViewModels.Main.MainViewModel>();
All that is fine and dandy. Now, the problem starts when I want to switch from one ViewModel to another.
An example of a ViewModel is :
[PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IScreen))]
sealed class SampleViewModel: ScreenVMwithUoW<IAddItemUoW>
{
[ImportingConstructor]
public SampleViewModel(IAddItemUoW uow, IEventAggregator eventAggregator) : base(uow, eventAggregator)
{
}
//bla bla bla
}
Let's say I want to open SampleViewModel and close my MainViewModel. How do I do it using MEF?
Here is what I am doing now:
[Export(typeof(IScreenFactory))]
class ScreenFactory : IScreenFactory
{
private Dictionary<Type, ExportFactory<IScreen>> _screenDictionary { get; set; }
private IEnumerable<ExportFactory<IScreen>> _screenfactoryCollection { get; set; }
private ExportLifetimeContext<IScreen> _currentScreenLifeTimeCtx { get; set; }
[ImportingConstructor]
public ScreenFactory([ImportMany(AllowRecomposition = true)] IEnumerable<ExportFactory<IScreen>> screenList)
{
_screenfactoryCollection = screenList;
_reportfactoryCollection = reportsList;
}
public IScreen GetScreen(Type t)
{
if (_screenDictionary == null)
{
PopulateScreenDictionary(_screenfactoryCollection);
}
_currentScreenLifeTimeCtx = _screenDictionary[t].CreateExport();
return _currentScreenLifeTimeCtx.Value;
}
private void PopulateScreenDictionary(IEnumerable<ExportFactory<IScreen>> screenfactories)
{
_screenDictionary = screenfactories.ToDictionary(c => c.CreateExport().Value.GetType(), c => c);
}
public void DisposeCurrentScreenContext()
{
_currentScreenLifeTimeCtx?.Dispose();
}
public void Dispose()
{
DisposeCurrentScreenContext();
}
}
Whenever I need a new instance of a ViewModel, I just do:
DeactivateItem(ActiveItem, true);
_vmFactory.DisposeCurrentScreenContext();
ActivateItem(_vmFactory.GetScreen(NextViewModelName));
This CANNOT be the normal way to do so. Also, this also adds a huge hit in performance, especially the startup time of the application, when the number of ViewModels increase to about 25-30.
I would also like to avoid the Service Locator Pattern, if possible. I am also open to using a proper IoC Container instead of MEF, but MEF allows me to add ViewModels with very little effort. Just adding the annotation [Export(typeof(IScreen))] does the job.

Using Prism 6 Event Aggregator between view models with an object as the payload

Hi I'm hoping one of you could help me with some syntax.
So I'm following this example https://www.codeproject.com/Tips/591221/Simple-EventAggregator-in-WPF-PRISM on using Prism Event Aggregator to send messages from one ViewModel to another.
The following code works great when publishing a single string as the payload.
internal class OrderSelectedEvent_SS : PubSubEvent<string>
{
private static readonly EventAggregator _eventAggregator;
private static readonly OrderSelectedEvent_SS _event;
static OrderSelectedEvent_SS()
{
_eventAggregator = new EventAggregator();
_event = _eventAggregator.GetEvent<OrderSelectedEvent_SS>();
}
public static OrderSelectedEvent_SS Instance
{
get { return _event; }
}
}
Publisher (In ViewModel1):
OrderSelectedEvent_SS.Instance.Publish(_strCurrentOrder);
Subscriber (In ViewModel2:
OrderSelectedEvent_SS.Instance.Subscribe(OrderSelectedEventHandler_SS);
private void OrderSelectedEventHandler_SS(string strSelectedOrder)
{
CurrentOrder = strSelectedOrder;
}
What I'm trying to do is modify to accept an object (a class with multiple strings) as the payload.
Here's what I have so far:
internal class OrderSelectedEvent : PubSubEvent<object>
{
private static readonly EventAggregator _eventAggregator;
private static readonly OrderSelectedEvent _event;
static OrderSelectedEvent()
{
_eventAggregator = new EventAggregator();
_event = _eventAggregator.GetEvent<OrderSelectedEvent>();
}
public static OrderSelectedEvent Instance
{
get { return _event; }
}
public class OrderSelectedPayload
{
public string SelectedOrder { get; set; }
public string SelectedE32 { get; set; }
}
}
Publisher (In ViewModel1):
OrderSelectedEvent.OrderSelectedPayload ospl = new OrderSelectedEvent.OrderSelectedPayload();
ospl.SelectedOrder = _strCurrentOrder;
ospl.SelectedE32 = _strCurrentE32JobNumber;
OrderSelectedEvent.Instance.Publish(ospl);
Subscriber (In ViewModel2:
OrderSelectedEvent.Instance.Subscribe(OrderSelectedEventHandler);
I'm getting an error here on the subsriber: **ERROR: cannot convert from 'method group' to 'Action'**** and I can't seem to figure out what I need to do.
private void OrderSelectedEventHandler(OrderSelectedEvent.OrderSelectedPayload ospl)
{
CurrentOrder = ospl.SelectedOrder;
CurrentE32JobNumber = ospl.SelectedE32;
}
Thanks in advance for any guidance you can provide.
Your problem is simple: You are defining the event to pass an object as payload, then trying to use a specific class as payload instead. To fix this, change
internal class OrderSelectedEvent : PubSubEvent<object>
To:
internal class OrderSelectedEvent : PubSubEvent<OrderSelectedPayload>
Alternatively, you could change your handler signature to match the expected parameters of the event:
private void OrderSelectedEventHandler(OrderSelectedEvent.OrderSelectedPayload ospl)
To:
private void OrderSelectedEventHandler(object ospl)

Seemann's Dependency Injection, "Three Calls Pattern" vs Service Locator Anit-Pattern

I have created a WinForms MVC application using Dependency Injection (DI) and Ninject as the DI Container. The basic architecture is as follows
Program.cs (the main entry point of the WinForms application):
static class Program
{
[STAThread]
static void Main()
{
...
CompositionRoot.Initialize(new DependencyModule());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CompositionRoot.Resolve<ApplicationShellView>());
}
}
DependencyModule.cs
public class DependencyModule : NinjectModule
{
public override void Load()
{
Bind<IApplicationShellView>().To<ApplicationShellView>();
Bind<IDocumentController>().To<SpreadsheetController>();
Bind<ISpreadsheetView>().To<SpreadsheetView>();
}
}
CompositionRoot.cs
public class CompositionRoot
{
private static IKernel ninjectKernel;
public static void Initialize(INinjectModule module)
{
ninjectKernel = new StandardKernel(module);
}
public static T Resolve<T>()
{
return ninjectKernel.Get<T>();
}
public static IEnumerable<T> ResolveAll<T>()
{
return ninjectKernel.GetAll<T>();
}
}
ApplicationShellView.cs (the main form of the application)
public partial class ApplicationShellView : C1RibbonForm, IApplicationShellView
{
private ApplicationShellController controller;
public ApplicationShellView()
{
this.controller = new ApplicationShellController(this);
InitializeComponent();
}
public void InitializeView()
{
dockPanel.Extender.FloatWindowFactory = new CustomFloatWindowFactory();
dockPanel.Theme = vS2012LightTheme;
}
private void ribbonButtonTest_Click(object sender, EventArgs e)
{
controller.OpenNewSpreadsheet();
}
public DockPanel DockPanel
{
get { return dockPanel; }
}
}
where
public interface IApplicationShellView
{
void InitializeView();
DockPanel DockPanel { get; }
}
ApplicationShellController.cs
public class ApplicationShellController
{
private IApplicationShellView shellView;
public ApplicationShellController(IApplicationShellView view)
{
this.shellView = view;
}
public void OpenNewSpreadsheet(DockState dockState = DockState.Document)
{
SpreadsheetController controller = (SpreadsheetController)GetDocumentController("new.xlsx");
SpreadsheetView view = (SpreadsheetView)controller.New("new.xlsx");
view.Show(shellView.DockPanel, dockState);
}
private IDocumentController GetDocumentController(string path)
{
return CompositionRoot.ResolveAll<IDocumentController>()
.SingleOrDefault(provider => provider.Handles(path));
}
public IApplicationShellView ShellView { get { return shellView; } }
}
SpreadsheetController.cs
public class SpreadsheetController : IDocumentController
{
private ISpreadsheetView view;
public SpreadsheetController(ISpreadsheetView view)
{
this.view = view;
this.view.SetController(this);
}
public bool Handles(string path)
{
string extension = Path.GetExtension(path);
if (!String.IsNullOrEmpty(extension))
{
if (FileTypes.Any(ft => ft.FileExtension.CompareNoCase(extension)))
return true;
}
return false;
}
public void SetViewActive(bool isActive)
{
((SpreadsheetView)view).ShowIcon = isActive;
}
public IDocumentView New(string fileName)
{
// Opens a new file correctly.
}
public IDocumentView Open(string path)
{
// Opens an Excel file correctly.
}
public IEnumerable<DocumentFileType> FileTypes
{
get
{
return new List<DocumentFileType>()
{
new DocumentFileType("CSV", ".csv" ),
new DocumentFileType("Excel", ".xls"),
new DocumentFileType("Excel10", ".xlsx")
};
}
}
}
where the implemented interface is
public interface IDocumentController
{
bool Handles(string path);
void SetViewActive(bool isActive);
IDocumentView New(string fileName);
IDocumentView Open(string path);
IEnumerable<DocumentFileType> FileTypes { get; }
}
Now the view ascociated with this controller is
public partial class SpreadsheetView : DockContent, ISpreadsheetView
{
private IDocumentController controller;
public SpreadsheetView()
{
InitializeComponent();
}
private void SpreadsheetView_Activated(object sender, EventArgs e)
{
controller.SetViewActive(true);
}
private void SpreadsheetView_Deactivate(object sender, EventArgs e)
{
controller.SetViewActive(false);
}
public void SetController(IDocumentController controller)
{
this.controller = controller;
Log.Trace("SpreadsheetView.SetController(): Controller set successfully");
}
public string DisplayName
{
get { return Text; }
set { Text = value; }
}
public WorkbookView WorkbookView
{
get { return workbookView; }
set { workbookView = value; }
}
...
}
Finally the view interfaces are
public interface ISpreadsheetView : IDocumentView
{
WorkbookView WorkbookView { get; set; }
}
and
public interface IDocumentView
{
void SetController(IDocumentController controller);
string DisplayName { get; set; }
bool StatusBarVisible { get; set; }
}
Now for my questions. In Seemann's book "Dependency Injection in .NET" he talks about the "Three Calls Pattern" and this is what I have attempted to implement in the above. The code works, the shell view displays and via the MVC pattern my controllers correctly open views etc. However, I am confused as the above definately has the flavour of the "Service Locator Anti-Pattern". In chapter 3 of Seemann's book he states
The COMPOSITION ROOT pattern describes where you should use a DI CONTAINER. However,
it doesn’t state how to use it. The REGISTER RESOLVE RELEASE pattern addresses
this question [...] A DI CONTAINER should be used in three successive
phases called Register, Resolve, and Release.
In its pure form, the REGISTER RESOLVE RELEASE pattern states that you should only
make a single method call in each phase. Krzysztof Kozimic calls this the Three Calls Pattern.
Configuring a DI CONTAINER in a single method call requires more explanation. The
reason that registration of components should happen in a single method call is
because you should regard configuration of a DI CONTAINER as a single, atomic action.
Once configuration is completed, the container should be regarded as read-only.
This sounds like the dredded "Service locator", why is this not deemed service location?
In order to adjust my code to instead use Contstructor Injection, I changed my entry code to
[STAThread]
static void Main()
{
var kernel = new StandardKernel();
kernel.Bind(t => t.FromThisAssembly()
.SelectAllClasses()
.BindAllInterfaces());
FileLogHandler fileLogHandler = new FileLogHandler(Utils.GetLogFilePath());
Log.LogHandler = fileLogHandler;
Log.Trace("Program.Main(): Logging initialized");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(kernel.Get<ApplicationShellView>());
}
using Ninject.Extensions.Conventions, I then changed ApplicationShellController in order to correct my code to inject the IDocumentControllers via ctor injection:
public class ApplicationShellController
{
private IApplicationShellView shellView;
private IEnumerable<IDocumentController> controllers;
public ApplicationShellController(IApplicationShellView shellView, IEnumerable<IDocumentController> controllers)
{
this.shellView = shellView;
this.controllers = controllers;
Log.Trace("ApplicationShellController.Ctor(): Shell initialized successfully");
}
...
}
where
public class SpreadsheetController : IDocumentController
{
private ISpreadsheetView view;
public SpreadsheetController(ISpreadsheetView view)
{
this.view = view;
this.view.SetController(this);
}
...
}
but this leads to a circular dependency, how do I handle this?
Question Summary:
Why is my initial use of Ninject using "Thee Calls Pattern" and CompositionRoot.Resolve<T>() bad or different to the Service Locator Anti-Pattern?
How can I resolve the circular dependency issue above if I want to switch to pure ctor injection?
Thanks very much for your time.
At some point in the process, you have to use service location. However, the difference between DI and SL is that in SL, you are resolving your services at the point they are requested, whereas in DI you resolve them in some kind of factory (such as a controller factory) and then construct your objects and pass the reference in.
You should create some kind of infrastructure that dispatches your commands and uses a factory of some kind to locate the dependencies used by the created objects.
In this way, the rest of your code doesn't have dependency resolution, and you are following a DI pattern except at the construction point.

Pass data from class to Form through different class

Is there a better solution to send data from one class to another through different class? I have image in class ImageProccessing and I would like to send him to class MainForm.
MainForm.cs (GUI)
VideoProccessing.cs
ImageProccessing.cs
I have this pseudocode:
class MainForm : Form
{
VideoProccessing _video = new VideoProccessing();
}
class VideoProccessing
{
ImageProccessing _image = new ImageProccessing();
}
class ImageProccessing
{
Bitmap _bmp = null;
public void SomeBadassProcess()
{
_bmp = new Bitmap(); //How to send this to MainForm (GUI)
}
}
My solution:
class MainForm : Form
{
VideoProccessing _video = new VideoProccessing();
_video.SendAgain += (ShowImage);
private void ShowImage(Bitmap bmp)
{
SomePictureBox.Image = bmp;
}
}
class VideoProccessing
{
ImageProccessing _image = new ImageProccessing();
_image.Send += (ReceivedImage)
public delegate void SendAgainImage(Bitmap bmp);
public event SendAgainImage SendAgain;
private void ReceivedImage(Bitmap bmp)
{
SendAgain(bmp);
}
}
class ImageProccessing
{
Bitmap _bmp = null;
public delegate void SendImage(Bitmap bmp);
public event SendImage Send;
public void SomeBadassProcess()
{
_bmp = new Bitmap(); //How to send this to MainForm (GUI)
Send(_bmp);
}
}
If your VideoProcessing class has a dependency on the ImageProcessing class, however, you only wish to make your MainForm aware of VideoProcessing, then propagating your message in the manner that you are is probably acceptable. It does however create a strong coupling between your objects, which, you may or may not care about at this stage.
Another method could be to use some sort of message bus such as an EventAggregator or a Mediator. Both of these behavioural patterns are designed to decouple objects involved in the messaging process and provide a publish/subscribe mechanism.
As an example if you were to implement the EventAggregator your MainForm would be a subscriber, listening out for notifications sent from a publisher which in your scenario is the ImageProcessing class.
A contrived code example might look like the following:
public class MainForm : Form
{
private readonly EventAggregator eventAggregator;
private readonly VideoProcessing videoProcessing;
public MainForm()
{
this.eventAggregator = new EventAggregator();
this.eventAggregator.Subscribe<NewBitmapEvent>(HandleNewBitMap);
this.videoProcessing = new VideoProcessing(this.eventAggregator);
}
private void HandleNewBitmap(Bitmap args)
{
// Do something
}
}
public class VideoProcessing
{
private readonly EventAggregator eventAggregator;
private readonly ImageProcessing imageProcessing;
public VideoProcessing(EventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
this.imageProcessing = new ImageProcessing(this.eventAggregator);
}
}
public class ImageProcessing
{
private readonly EventAggregator eventAggregator;
public ImageProcessing(EventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
this.eventAggregator.Publish<NewBitmapEvent>(new Bitmap(...));
}
}
When the ImageProcessing class publishes a NewBitmapEvent, only the MainForm is notified as only it, and not the VideoProcessing class is subscribed to the event. Obviously if other classes were subscribed then they too would be notified when the event is published.

Categories

Resources