I have tried to use MVVM Light messaging to communicate between different ViewModels, but with time it gets quite messy and hard to understand from where and where to all the messages are flying so I wanted to ask about other solution how to communicate between ViewModels using Interfaces. The provided code works well, but I am not sure if Interfaces are mended to be used this way..
So here I have defined interface and class that implements it:
public interface ISelectProject
{
event EventHandler<SelectedProjectEventArgs> MessageReceived;
void ProjectSelected(...);
}
public class SelectProject : ISelectProject
{
public event EventHandler<SelectedProjectEventArgs> MessageReceived;
public void ProjectSelected(..)
{
MessageReceived?.Invoke(this,new SelectedProjectEventArgs(...));
}
}
Afterward, I inject SelectProject class into these tree ViewModels using constructor injection(code not shown here).
Then in ViewModelA I invoke MessageReceived event and all the other ViewModels subscribe to the event.
public class ViewModelA : ViewModelBase
{
public ViewModelA(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.ProjectSelected;
}
}
public class ViewModelB : ViewModelBase
{
public ViewModelB(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.MessageReceived += (s, data) =>
{
...
};
}
}
public class ViewModelC : ViewModelBase
{
public ViewModelC(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.MessageReceived += (s, data) =>
{
...
};
}
}
My questions are:
1) Does this somehow violate MVVM practice?
2) Is it considered a good practice to communicate between ViewModels like this?
3) Does this solution introduce any risks, for example, memory leaks, etc?
Thank you!
1) Does this somehow violate MVVM pratice?
No. ISelectedProject is basically a shared service. A shared service is a class that provides functionality to several components in a decoupled way. Please refer to this link for more information and an example.
2) Is it considered a good practice to communicate between viewModels like this?
Yes, if you want to keep them decoupled from each other.
3) Does this solution introduces any risks, for example memory leaks, etc.
Using a shared service doesn't introduce any memory leaks by itself. But if your shared service exposes an event and a view model subcribes to this one without unsubscribing from it, the service will keep the view model alive.
Related
I'm making a media player program and I have the following interface:
public interface IMediaService
{
void Play();
}
Would it be more appropriate to inherit the interface in the view where the MediaElement control resides and access it directly in the implementation of the methods or rather have it in a separate class like this:
public class MediaPlayer : IMediaService
{
private MediaElement _mediaElement;
public MediaPlayer(MediaElement mediaElement)
{
_mediaElement = mediaElement;
}
public void Play()
{
_mediaElement.Play();
//...
}
}
vs inheriting it in the view:
public partial class MainWindow : IMediaService
{
public MainWindow()
{
InitializeComponent();
}
void IMediaService.Play()
{
Player.Play();
//..
}
}
I'm not using MVVM, but those methods might be used as bindings through commands.
The problem I see in the second approach is that my view class will get cluttered really fast.
I'm open to any alternative solutions that I haven't mentioned, this is just what I've come up with atm.
Would it be more appropriate to inherit the interface in the view where the MediaElement control resides and access it directly in the implementation of the methods or rather have it in a separate class like this:
It doesn't really matter as far as MVVM is concerned. There is no right or wrong really. It's depends on the developer's personal preference. If you don't want to pollute your view, you create a separate class. If you don't mind adding some methods to your view, you don't.
The benefit of using a seperate class is that you may reuse it for several different views/MediaElement.
But the view model only cares about the interface itself, i.e. it has no dependency upon the actual implementation of it.
I have a MEF container which contains hundreds of classes. What is a good way to pass messages between different classes?
I would prefer a solution that will work with any Dependency Injection (DI) container, including Unity, Castle Windsor, etc.
Note: This is a "share your knowledge, Q&A-style" entry.
Introducing the Event Publisher
This event publisher allows any class from the MEF container to send a message to any other class in the MEF container.
This code has been battle proven over a number of years, and has proven to be particularly useful when using WPF / MVVM.
It's a one-to-many subscription, so once the message is sent out, it is received by any listener that is observing messages of that custom type.
This example is for MEF, but it is also applicable to any other Dependency Injection (DI) container such as Unity, Castle Windsor, etc. If you convert EventPublisher to a singleton, you can use it with normal C# (i.e. not using a DI container). Let me know if you want me to post the code.
This code is nothing new: there are hundreds of other implementations of event publishers in the open source community, e.g. in MVVM Light. However, this example uses such a small amount of code that it's possible to see how it works under the hood, by single stepping in the debugger.
C# Usage
Add the boiler plate code to your project (see below).
Create your custom event type. This can be a class, a struct, or even an enum, e.g.:
public enum NavigationType
{
Unknown = 0,
MyOption1,
MyOption2
}
... then, I can import the eventPublisher into any class, like so:
[ImportingConstructor]
public BrokerOrderSearchResultViewModel(
IEventPublisher<NavigationType> eventPublisher,
)
{
_eventPublisher = eventPublisher;
...
... in the constructor, I can then subscribe to events of type NavigationType:
_eventPublisher.GetEvent<NavigationType>().Subscribe(o =>
{
Console.Write(o);
});
... and anywhere else, I can push events out, which will be received in the subscription:
_eventPublisher.Publish(NavigationType.MyOption1);
C# Boiler plate code
Add the Reactive Extensions (RX) NuGet package to your project.
Create this interface:
public interface IEventPublisher
{
IObservable<TEvent> GetEvent<TEvent>();
void Publish<TEvent>(TEvent sampleEvent);
}
public interface IEventPublisher<in T>
{
IObservable<TEvent> GetEvent<TEvent>() where TEvent : T;
void Publish<TEvent>(TEvent sampleEvent) where TEvent : T;
}
... with this implementation:
// NOTE: This class must be a singleton (there should only ever
// be one copy; this happens automatically in any dependency injection
// container). This class is the central dictionary that routes events
// of any incoming type, to all listeners for that same type.
[Export(typeof (IEventPublisher))]
public class EventPublisher : IEventPublisher
{
private readonly ConcurrentDictionary<Type, object> _subjects;
public EventPublisher()
{
_subjects = new ConcurrentDictionary<Type, object>();
}
public IObservable<TEvent> GetEvent<TEvent>()
{
return (ISubject<TEvent>)_subjects.GetOrAdd(typeof(TEvent), t => new Subject<TEvent>());
}
public void Publish<TEvent>(TEvent sampleEvent)
{
object subject;
if (_subjects.TryGetValue(typeof (TEvent), out subject))
{
((ISubject<TEvent>)subject).OnNext(sampleEvent);
}
// Could add a lock here to make it thread safe, but in practice,
// the Dependency Injection container sets everything up once on
// startup and it doesn't change from that point on, so it just
// works.
}
}
// NOTE: There can be many copies of this class, one for
// each type of message. This happens automatically in any
// dependency injection container because its a <T> class.
[Export(typeof (IEventPublisher<>))]
public class EventPublisher<T> : IEventPublisher<T>
{
private readonly IEventPublisher _eventPublisher;
[ImportingConstructor]
public EventPublisher(IEventPublisher eventPublisher)
{
_eventPublisher = eventPublisher;
}
public IObservable<TEvent> GetEvent<TEvent>() where TEvent : T
{
return _eventPublisher.GetEvent<TEvent>();
}
public void Publish<TEvent>(TEvent sampleEvent) where TEvent : T
{
_eventPublisher.Publish(sampleEvent);
}
}
Discussion
This code shows how simple it is to send an event from any class to any other class.
As shown, you need to create a new custom type in order to send a message. The type can be an enum, a struct, or a class. If the type is a class or a struct, it can contain any number of properties. If a message is sent out using a specific custom type, all subscribers listening to messages of that type will receive it. You can create many custom types, one for each flavour of event you need to communicate with.
Behind the scenes, all the code is doing is keeping a dictionary of your custom types. On a send, it looks up the appropriate subscribers in the dictionary, then sends the message using Reactive Extensions (RX). All subscribers listening to that type will then receive the message.
Sometimes, if there are too many events flying everywhere, it's difficult to see which classes are communicating with which other classes. In this case, it's simple: you can use "Find in Files" to find all classes that contain the string IEventPublisher<NavigationType>, which ends up listing all of the classes that are either sending or listening to an event of our custom type NavigationType.
Beware: this code is not a silver bullet. It is a bad code smell to rely on events too much, as the class hierarchy should be composed in such a way that classes should not be dependent on their parents. For more information, study the SOLID principles, in particular, the LSP. However, sometimes use of events are unavoidable, as we have no choice but to cross the class hierarchy.
Future Enhancements
Currently, this Event Publisher does not implement IDisposable. It should.
Use EventAggregator if you're not looking to do something overly elaborate.
http://blogs.msdn.com/b/gblock/archive/2009/02/23/event-aggregation-with-mef-with-and-without-eventaggregator.aspx
And a way to bring this into your project the MEFfy way:
https://msdn.microsoft.com/en-us/library/microsoft.practices.prism.mefextensions.events.mefeventaggregator(v=pandp.50).aspx
You could also write your own EventAggregator patter (per M. Fowler), but then you would have to take into consideration cleanly removing subscribed handlers, which will most likely lead you into the land of weak references and the horrors (or not) that lie there.
What alternative can one use to avoid exposing both events and an interface.
I have a class that has a determined life cycle: created, modified, ...
clients mainly GUIs need to hook up into the life cycle of that class so the simplest way to do it is to expose events, at the same time I need to move some responsibilities -that happen during the life cycle- out of the class so I came up with this solution:
Interface ILifeCycle
{
void OnCreated(...);
void OnModified(...);
// ...
}
classA
{
private ILifeCycle lifeCycle;
/// ...
public event EventHandler Created(object sender, EventArgs args);
public event EventHandler Modified(object sender, EventArgs args);
/// ...
protected void OnCreated()
{
lifeCycle.OnCreated(...);
if(Created!=null)
Created(this,EventArgs.Empty);
}
protected void OnModified()
{
lifeCycle.OnModified(...);
if(Modified!=null)
Modified(this,EventArgs.Empty);
}
/// ...
}
Doing this I can inject a Logger that implements ILifeCycle, and so move the logging responsibility to its own class,
but it feels like it's going to be a lot of repetition.
What clean alternatives would you recommend to achieve this?
In general Interface and Events/Delegates are used for two very different kinds of approach. Lets describe them each first -
Interface: The main purpose of interface is that it enforces some functionality to all implementations of that interface. And whenever you implement it in a subclass, you override the implementation of the super class. For example -
interface IA
{
void test();
}
class A : IA
{
public void test(){
}
}
class B : A
{
public void test(){
//you can only go up by calling base.test(), but cannot move down, because you do not know whether there is an implementation down the tree or not. So you cannot call it.
}
}
class C : B
{
public void test(){
//you can only go up by calling base.test(), but cannot move down, because you do not know whether there is an implementation down the tree or not. So you cannot call it.
}
}
As you can see, with interface you can only look back but cannot look forward and assume there will be any more implementations.
Events: Events are created for a different purpose. lets just say you want to give the developers some facility to rely on some activities and do some other activities based on that activities and changes, and most importantly they will be implement this in future. The events will not depend on your implementation, they will just subscribe to it and do something based on that. Whether they exists or not, your own implementation does not change or the behavior of your own code does not changes based on them. In other words, you can only move down the tree. The base class captured the event and then propagates them down the tree.
These are the usual uses of Interface and Events and they are meant to be used that way. But its not completely impossible to code such that it will entirely depend on interface and vice versa, i.e. code entirely dependent on events but that is not the way they are meant to be.
In This Case: In your case, I am thinking you are trying to achieve a modular system that will not depend on each other but again subscribe to events. There are other architectures and patterns for this, specially IOC containers will be a very helpful for you, that will entirely be interface dependent, you will not need events. Some .net IOC containers are AutoFac, Castle.Windsor, MEF
I myself, like MEF the most, here is a post on MEF that I wrote few years back, shows you how you can inject run-time handlers inside a container -
http://mahmudulislam.me/2012/04/20/1a-managed-extensibility-framework-introduction/
BTW, article is a bit old, I am working on updating this one.
Solution with IOC: I am giving a probable solution with MEF -
Interface ILifeCycle
{
void OnCreated(...);
void OnModified(...);
...
}
[Export(typeof(ILifeCycle))] //export our classes for injection
classB : ILifeCycle{
public void OnCreated(...)
{
....
}
public void OnModified(...){
}
}
[Export(typeof(ILifeCycle))] //export our classes for injection
classC : ILifeCycle{
public void OnCreated(...)
{
....
}
public void OnModified(...){
}
}
classA
{
[ImportMany] //get all exported classes for injection
private IList<ILifeCycle> _observers;
protecetd void OnCreated()
{
//use MEF to build composition and then do the following
foreach(var o in _observers){
o.OnCreated(...);
}
}
protecetd void OnModified()
{
//use MEF to build composition and then do the following
foreach(var o in _observers){
o.OnModified(...);
}
}
...
}
This is a very basic solution. But in your case you might wanna make use of asynchronous programming. Because there is very big difference between Events and Interfaces. By default, events handlers are call in a separate thread and thus it does not halt the caller, but interface implement will hang the caller until the method finishes. So make sure you use asynchronous programming to not block your main process.
Asynchronous Programming with Async and Await (C# and Visual Basic)
I'm not sure I understood you well but I think you worry about repetitions in different types implementing ILifeCycle. So, you can take advantage of inheritance:
abstract class LifeCycleBase
{
public void OnCreated(...)
{
.....
}
public void OnModified(...);
{
.....
}
...
}
class LifeCycleLoger : LifeCycleBase
{
public void OnCreated(...)
{
....
base.OnCreate();
}
....
}
Given a basic C# library, how do I implement functions of this library into my WPF application to handle appropriately the concepts of Binding and Commands?
I mean, need I write some own wrappers for these library classes in order to implement interfaces such as ICommand or should this be done directly in the library itself?
Some code to get my question more comprehensible:
From the library:
public class Item
{
public string Name { get; set; }
public void DoSomething() { throw new NotImplementedException; }
}
I want to implement the function DoSomething() in my XAML markup without any line of code in that .cs file since that is, from what I've read, the best practice.
(Assuming that an instance of Item is bound to the control)
<Button Command="{Binding DoSomething}"/>
Well, in order to do so, I need to implement the interface ICommand and create a command, but that is, as stated above, unclear to me since I'm using a library here.
Should I write my own Wrapper for the Item class of the API and implement the ICommand interface or is there any other way to archieve this? I've written the library by myself so changes are possible. I'm just not entirely sure about changing the library because if I do so, it is (possibly) bound to WPF.
Hi there if anything your ViewModel should handle any requests on your Model that's it's sole purpose, to get these things to work you need ICommand and if you want some more info here is link with a tutorial on RoutedCommands. If you have your Model and ViewModel defined then you can easily assign tasks to the particular Model through its VM.
P.S. I think you could treat your library as a Model and write a "wrapper" ViewModel to handle operations on it. HTH
UPDATE
Consider following:
class libClass
{
void method()
{
//do something here
}
}
code above would be your model and if you want it to be more readable you could do it this way
class libModel
{
private libClass _libClass;
public libClass LibClass { get; set; }
}
Note
You could implement INotfiyPropertyChanged in your Model to handle any changes if needed of course.
now in your VM how you use the Model
class ViewModel
{
private libModel _libModel;
public libModel LibModel { get; set; }
//after you set up your RoutedCommands
//I declare method within my VM to handle the RoutedCommands don't know
//if it works when you use Property Method
void VMMethod()
{
//use VM's property to invoke desired method from your lib
}
}
and voila! ready "wrapper" for your class with implementation in your VM.
Tip
If you want to know how to do the RoutedCommands here is a link to a tutorial.
I have a database that communicates with webservices with my Model (own thread) and exposes Data Objects. My UI application consists of different Views and ViewModels and Custom Controls. I'm using ServiceProvider (IServiceProvider) to access the Model and route the events to the UI thread.
Communication between the ViewModels is handeled by a Messenger.
Is this way to go?
I was also wondering what is the best way to strucutre the DataObjects
At the moment i have the DataObjects that have a hierarchy structure but does not support INotifyProperty though the children list are of type of ObservableCollection. I have no possiblity to implement notifypropertychange on the properties.
I was wondering the best way of making them MVVM friendly. Implementing a partial class and adding all the properties or commands that are necessary or wrapping all the DataObjects and keep the Model list and MVVM list in sync.
All thoughts and ideas are appreciated.
Strictly implementing MVVM means that you should create ViewModel classes that expose all the DataObjects (your Model) that will be used the View - the View should not be able to access the Model directly.
Following this, you will have full control over your ViewModel and you'll be able to implement INotifyPropertyChange events and synchronise the ViewModel with the Model on each change notification or upon specific actions.
I would agree with Bermo with a note that not many people do not strictly implement the pattern. May expose the Model objects directly and implement INotifyPropertyChanged in those objects. But below is the basic means you can use to implement what you have so far:
class PersonViewModel : INotifyPropertyChanged
{
Person p = new Person();
public string First
{
get { return p.First; }
set
{
p.First = value;
onPropertyChanged("First");
}
}
public string Last
{
get { return p.Last; }
set
{
p.Last = value;
onPropertyChanged("Last");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void onPropertyChanged(string propertyName)
{
if (PropertyChanged!=null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
}
}
#endregion
}
I personally created a ViewModel class to inherit from so that I could put my INotifyPropertyChanged code there and not have to put it in repeatedly. Then my implementations simply inherit from that base class.