Using Serial Port Class Library in Prism MVVM Application - c#

I inherited a WPF/Prism/Unity MVVM application and I need to link in a Class Library that communicates externally over a serial port. The serial port library publishes Events for errors and messages.
I'm new to Prism, but I've used Unity some years back. The Prism application (lets call it PrismApp) is a base PrismApplication, with two modules: main and settings. My serial port library (lets call it LibSerial) wraps the base communications protocol and publishes three events: ConnectionEventReceived, ErrorEvent and MessageReceived. LibSerial has functions for Connect, StartSession and Send.
My questions are:
Where do I instantiate my LibSerial? Do I create a Model for it or can I instantiate LibSerial in my base PrismApplication?
How do I publish events to my ViewModels? I assume I would consume the LibSerial Events somewhere and use and EventAggregator to push various EventArgs up into the viewmodels?
How would I call my LibSerial start/startsession/send functions from within PrismApp? Would that be a DeleagateCommand in a ViewModel that calls a pubsub.publish?
Thanks Everyone!

Where do I instantiate my LibSerial?
Register it in your bootstrapper and let the container instantiate it. Override the RegisterTypes method of the PrismApplication class in your App.xaml.cs and register the LibSerial type:
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<ILibSerial, LibSerial>();
}
You can then inject your view models with an ILibSerial (which in this case is an interface that the LibSerial class implements) and hook up its events and access its members as usual:
public class ViewModel
{
public ViewModel(ILibSerial libSerial)
{
libSeriel.MessageReceived += ...;
}
}
The container will take care of the instantiation and provided that you register the type using the RegisterSingleton method in the bootstrapper, there will only be a single instance created and shared across all view models.

Related

.NET Core 3.1 - Scoped service - Event handler invokes multiple times

I have created application in .net core 3.1, In which there are one singleton interface and its implementation class, which is receiving the TCP/IP socket message. There is one event handler in the class, which will be invoked once messages received on the socket.
public Class IncomingMessageHandler : IIncomingMessageHandler
{
public event EventHandler<string> OnMessageReceived;
private void InvokeMessageRecived(object sender, string message)
{
this.OnMessageReceived?.Invoke(this, message);
}
}
There is one another service TransactionService class which is having dependency injected for the interface IIncomingMessageHandler and subscribe to OnMessageReceived.
public TransactionService(IIncomingMessageHandler incomingMessageHandler)
{
this.incomingMessageHandler = incomingMessageHandler;
this.incomingMessageHandler.OnMessageReceived += this.IncomingMessageHandler_OnMessageReceived;
}
From this class, I am initiating the transaction and once a transaction started I will receive the messages into IncomingMessageHandler and OnMessageReceived invokes, Messages I am storing into the List for further processing.
Now TransactionService is the Scoped service class and for each API request new object will be created, Now If there are multiple requests are made, for each TransactionService would subscribe to OnMessageReceived and it invokes multiple time because there are multiple objects initiated and override the List of messages.
I can't register TransactionService as singleton due to some other limitations.
Is there any other way through which OnMessageReceived gets invoked only for the specific service object?
I have tried to un-subscribe the OnMessageReceived, but still, this issue will occur for multiple API requests at the same time.
Since you are binding to an event and not unbinding when finished, it causes a bit of a memory leak - the instances of TransactionService live on in other references and can't be GC'd. You should have TransactionService implement IDisposable and unbind it in the Dispose method. That removes the reference from the event in IncomingMessageHandler and you won't have duplicate calls.
Aside: I tried something very similar and I actually found using Reactive Extensions made for a much better pattern overall.

Connectivity service interface in common library code

I am working on a project that has a WPF and a mobile app, and there is also a .net standard library which has all the service and data layer which is shared between the two projects. I need to add a IConnectivityService Interface in the this common library project so that, before making a call to the server I can check if there is a connection available, and I also have an event handler in this interface that gets called when there is a change in connectivity.
public interface IConnectivityService
{
bool IsConnected { get; }
event EventHandler<ConnectivityChangedEventArgs> ConnectivityChanged;
}
The event handler for the Xamarin side do look like the above.
public interface IConnectivityService
{
bool IsConnected { get; }
event EventHandler ConnectivityChanged;
}
And for WPF it need to be this way.
Note: ConnectivityChangedEventArgs is a xamarin implementation and I would want to avoid from the shared code
Whats the best way to handle this? I ideally would like to have this as a shared code, so that I can use it in my service layer

C# WPF Prism - Share a same object between different modules(project)

I have multiple modules(each module in a different project) in my prism project. And I would like to share a same object between each module.
For example, let say I have Order class and I would like to access this Order object in my modules.
Currently, I implemented an interface and registered it with container in my Prism project.
public interface ICommonService{
Order GetData();
}
public class CommonService : ICommonService{
public Order MyOrder{ get; set; }
public Order GetData(){
return MyOrder;
}
public void SetData(Order order){
MyOrder = order;
}
}
I am using it in every module where it need MyOrder.
Is this a correct way of sharing a same object between modules?
Also, my View Models classes contains several Manager classes.
Should only View Model classes use ICommonService or can my Manager classes also use it?
I am trying to write clean and manageable code.
Thank you.
Is this a correct way of sharing a same object between modules?
Yes.
Should only View Model classes use ICommonService or can my Manager classes also use it?
The manager classes are fine to use the service.
Notes:
You should include a means of notifying other consumers of ICommonService when MyOrder changes. Examples: implement INotifyPropertyChanged or publish a MyOrderChanged event through the event aggregator
Normally, anyone who can access a service (read: knows the interface), should be allowed to do so. It's better to restrict the accessibility of the interface (by putting it in a separate assembly) than restricting accessibility of the service (by documentation), because the former is enforced by the compiler.
You can use Event Aggregation
The Prism Library provides an event mechanism that enables communications between loosely coupled components in the application. This mechanism, based on the event aggregator service, allows publishers and subscribers to communicate through events and still do not have a direct reference to each other.
Link Communicating Between Loosely Coupled Components
Prism
Sample
When you define your module, you should specify an dependencies in the constructor for that module. For example:
public class SomeModule : IModule
{
public SomeModule(ICommonService commonService)
{
// commonService will be shared object
}
}
In your Bootstrapper, when you add the module to the catalog, it will look through the DI container to look up the type. If you have it set to global reference, it will use the same object for all references to ICommonService.
class Bootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
RegisterTypeIfMissing(typeof(ICommonService),
typeof(CommonService), true); // true for register as singleton
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog module_catalog = (ModuleCatalog)this.ModuleCatalog;
module_catalog.AddModule(typeof(SomeModule));
}
}

Updating MainWindow Property from separate MVVM Module

I am looking to implement a "JQuery" style spinner in a WPF application. As this spinner will be triggered from some separate PRISM modules and I want the spinner to cover the whole application window I need to get access to a property in the MainWindow.
I have a property in the MainWindow but I am not able to see it from the other modules.
I have tried Application.Current.MainWindow but no luck.
I have also tried using the Application.Current.Properties[] but I do not know how to trigger a OnPropertyChanged event.
Can someone point me in the right direction please.
Update:
Here are some screenshots and a better description of what I want to do.
Ok, here is an example of my issue. I have an application that contains the following:
WPFApp
WPFApp.Module1
WPFApp.Module2
WPFApp.Module3
WPFApp.Module4
The WPFApp MainWindow contains 2 regions, a Menu region (on the left hand side) and a Content region.
Each module contains 2 views:
A menu view, which is loaded into the MainWindow Menu region
A content view, which is loaded into the MainWindow Content region
In each of the Module content views I want to perform a task that will take a few seconds and while the task is being performed I want to show a “Ajax Style” spinner that will cover the whole application window.
To have used the spinner class detailed here: WPF Spinner via MVVM & Attached Properties
I have been able to use this by adding the AsyncNotifier.Trigger (detailed in the link above) to each of the modules content view, see below.
My problem is:
If I want the spinner to cover the whole application window then I need to add the AsyncNotifier.Trigger to the MainWindow. I also need to expose a property from the MainWindow responsible for showing the spinner and be able to access this from each of the modules.
Any ideas on how to do this?
Update:
Ok, I think I might be getting a bit further but still a little bit stuck on how everything fits together.
I have created my Interface and put it into my Infrastructure module so every other module can access it.
I am using the following piece of code to load my modules from my AggregateModuleCatalog class.
/// <summary>
/// this.Catalogs is a readonly collection of IModuleCatalog
/// Initializes the catalog, which may load and validate the modules.
/// </summary>
public void Initialize()
{
foreach (var catalog in this.Catalogs)
{
catalog.Initialize();
}
}
My problem is that I am unsure of where I should put the SpinnerViewModel? Should it be in my Main project.
Also, where should I pass in the singleton using Constructor injection?
I would look at implementing the mediator pattern here. This is already present in Prism in the form of the EventAggregator
Basically, it sounds like you want to publish control messages of a certain type to any subscribers - in this case you have:
Subscribers
MainWindow
Publishers
Module 1
Module 2
Module 3
The modules should publish a message to signal that they want to 'busy' the MainWindow whilst work is being done/module is being loaded etc
The key thing is that they should not be aware of the MainWindow in any way. This keeps the solution decoupled, MVVM friendly, reusable and easily maintained. This method uses dependency injection, which is usually a good idea :)
In order for this to work, the modules need to take a dependency on the EventAggregator service (there is an IEventAggregator interface in PRISM which is your service interface) and should then publish messages to it
First you need an event which will serve as the message class. Obviously this needs to be visible from both the publisher and subscriber, so may need to sit in an external reference. This needs to inherit from CompositeWpfEvent and you should provide a generic argument for the message payload.
public class BusyUserInterfaceEvent : CompositeWpfEvent<bool>
{
}
(I suppose you could just directly use CompositeWpfEvent<bool> for this which may work equally as well but is not specific enough if you decide to include more event types which use bool as payloads)
Then you need to publish events of the above type from your module
public class Module1
{
private IEventAggregator _eventAggregator;
public Module1(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
public DoSomeWork()
{
// Busy the UI by publishing the above event
_eventAggregator.GetEvent<BusyUserInterfaceEvent>().Publish(true);
}
public FinishDoingSomeWork()
{
// Unbusy the UI by publishing the above event with 'false'
_eventAggregator.GetEvent<BusyUserInterfaceEvent>().Publish(false);
}
}
The MainWindow should also take a dependency on the EventAggregator service and should subscribe to any messages of a certain type. If work is to be done on the UI thread (as it is in this case) you should subscribe using ThreadOption.UIThread
public class MainWindow
{
private IEventAggregator _eventAggregator;
public MainWindow(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
// Subscribe to any messages of the defined type on the UI thread
// The BusyUserInterface method will handle the event
_eventAggregator.GetEvent<BusyUserInterfaceEvent>().Subscribe(BusyUserInterface, ThreadOption.UIThread);
}
public BusyUserInterface(bool busy)
{
// Toggle the UI - pseudocode here!
TickerActive = busy;
}
}
Whilst I have used this pattern in a couple of frameworks successfully before, I admit that I haven't used PRISM so the above code might not be quite right, however, the docs seem concise:
http://msdn.microsoft.com/en-us/library/ff921122.aspx
Using this pattern decouples any components, so it's easy to stop the MainWindow from subscribing to the events and to move the subscriber to a parent component if needs be without touching the implementation of the publishers.
This means you could swap the MainWindow for a completely different window and load your modules in during some part of your application lifecycle, and as long as it was subscribing to these event types it would still busy/unbusy based on the message publishing from the modules. It's a very flexible solution.
PRISMs implementation also provides subscription filtering so you can selectively listen for events.
Additionally, since you are aggregating events there's a lot you can do with this to allow inter-module communication. The only challenge you have is making sure everyone is aware of the message types, which is why an external dependency may be needed to hold the message types
Am I missing something? Should this be as easy as this?
App.xaml.cs
public partial class App
{
public static Window MainWindow {get;set;}
}
MainWindow.xaml.cs
public MainWindow()
{
App.MainWindow = this;
InitializeComponent();
}
public void Spinner(bool show)
{
// Your code here
}
Now in MVVM, the idea would be the same, just don't do it in code behind. You could create a singleton (Singleton has a static instance) for the spinner to bind to and then any module can mess with the singleton property.
If you like Dependency Injection, create an interface, create an object that implements that interface, have the Spinner bind to that object. Then inject that object as the interface into the modules when they are loaded.
Here is a singleton ViewModel that implements an interface. Your Prism projects need to know only about the interface. But your code that loads your Prism modules should know about both the interface and the singleton. Then when the Prism Modules are loaded, the singleton would be passed in (feel free to use whichever injection method is easiest: constructor injection, method injection, or property injection).
using System.ComponentModel;
namespace ExampleCode
{
/// <summary>
/// Interface for managing a spinner
/// </summary>
public interface IManageASpinner
{
bool IsVisible {get;set;}
// Add any other properties or methods you might need.
}
/// <summary>
/// A singleton spinner ViewModel for the main window spiner
/// </summary>
public class SpinnerViewModel : INotifyPropertyChanged, IManageASpinner
{ #region Singleton and Constructor
/// <summary>
/// Singleton instance
/// </summary>
public static SpinnerViewModel Instance
{
get { return _Instance ?? (_Instance = new SpinnerViewModel()); }
} private static SpinnerViewModel _Instance;
/// <summary>
/// Private constructor to prevent multiple instances
/// </summary>
private SpinnerViewModel()
{
}
#endregion
#region Properties
/// <summary>
/// Is the spinner visible or not?
/// Xaml Binding: {Binding Source={x:Static svm:SpinnerViewModel.Instance}, Path=IsVisible}
/// </summary>
public bool IsVisible
{
get { return _IsVisible; }
set
{
_IsVisible = value;
OnPropertyChanged("IsVisible");
}
} private bool _IsVisible;
// Add any other properties you might want to include
// such as IsSpinning, etc..
#endregion
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
}
Hope you can connect the dots from here.
Added Feb 12
Maybe use Method injection? I am not sure you can though.Can you edit the IModuleCatalog interface or the Catalog class? If not, skip this and go to the next idea.
foreach (var catalog in this.Catalogs)
{
catalog.Initialize(SpinnerViewModel.Instance);
}
Maybe your Catalogs should implement a second interface and use property injection instead of constructor injection.
public interface IHaveASpinner
{
public IManageASpinner Spinner {get;set;}
}
Now, have all your catalogs that implement IModuleCatalog also implement IHaveASpinner.
Then have your code do this:
foreach (var catalog in this.Catalogs)
{
catalog.Initialize();
var needSpinner = catalog as IHaveASpinner;
if (needSpinner != null)
{
needSpinner.Spinner = SpinnerViewModel.Instance;
}
}
Where I should put the SpinnerViewModel?
I would suggest your main project. It depends on your design. Do all the modules already reference your main project? If so, then put it in your main project. If not, then perhaps there is a project the main project and all the modules already reference? You could even create a separate project/dll specific for your spinner, but only if you have to as that might be overboard unless you have a strict design with rules for what can reference what.
You shouldn't need a VM just for the spinner. What I do is have the spinner itself (animation, icon, whatever) in my main window's view, and have the main window VM implement the following interface:
public interface IApplicationBusyIndicator
{
bool IsBusy { get; set; }
}
Using your favourite IoC container (I use Castle), I just inject IApplicationBusyIndicator into other VMs. Whenever one of these starts some long-running task it just sets IsBusy to true (then back to false when it's finished). The busy indicator in the main window view has its Visibility property bound to the main window VMs IsBusy property (using a boolean-to-visibility converter of course).
If, in your scenario, there is some architectural constraint preventing VMs in other modules from being injected with an instance of the main window VM, then you could use Prism's event aggregator to publish a message to say "application busy", and have the main window VM subscribe to the event, and show the busy indicator.
If you are looking to create more of some "visual" style / interface of a spinner, I suggest looking into creating your own subclass spinner (if you need special functionality behind it), and then create your own customized style for its look / behavior. Then when you put the spinner on the forms, just use a spinner of the class/style you designate and they should function for you well.
Here is one of my own learning about styles, but simple label
Another link where I helped someone walking through creating their own custom class/style which MIGHT be what you are trying to globally implement.
And a link to template / style defaults to learn from

Use WCF to broadcast/notify different object?

Just... doing some practices.
Structure:
A Client WPF App and a Server WPF App, both of them Self Host a WCF service.
Client WPF contains a View, which contains the ListBox
What I want to do:
Server WPF will create channels to the Client's WCF and constantly Send Message.
Client's WCF will receive the message and boardcast to any classes that subscribe it. (Or maybe I will say the classes that observe it).
In this case, the Client's View should receive message and put into the listbox.
Problems:
So the problem is how do I let the View observe the WCF? Or get notify by the WCF?
The Client's WCF is created by using ServiceHost myHost = new ServiceHost(typeof(MyClient));
How can I let the WCF have reference to my Client's View and do the notification?
Throught:
Somehow hardcoding the Client's WCF to have the View reference internally (this...doesn't make sense)
Observer Pattern? Make a static Subject class tht's implement Client's WCF Interface.
In the Client's will routers all the methods calls to Subject class. The View will also implement Client's WCF Interface and attaches to Subject class. Finally Subject class will routers calls to all the Views....
Something like this:
public class ClientServiceObserver : IClient
{
static List<IClient> _observers = new List<IClient>();
public static void Attach(IClient client)
{
_observers.Add(client);
}
public static void Detach(IClient client)
{
_observers.Remove(client);
}
public void SendCallbackMessage(string message)
{
foreach (IClient client in _observers)
{
client.SendCallbackMessage(message);
}
}
}
3.Everything similar to option 2, but instead of router all calls everywhere, might as well let WCF just notify Subject class there is update, then View will just get notify and create channel to Server to get it own data.....
All above options doens't really sounds good... and option 2 I don't even know if that's Observer Patterns anymore....
I wonder what will be the best practice to do it?
Please look EventAggregator pattern to achieve what you are trying. EvenAggregator implementation are available in
MVVM Light
Microsoft PRISM
Caliburn.Micro
See example for using EventAggregator here
You do not need to use the complete framework mentioned here, you can pull out the EventAggregator class and use it.

Categories

Resources