In my ViewmodelA I want to open a new window in ViewModelB, so i used the messenger class, but the probleme is that i need to reference ViewModelB inside the ViewModelA, so that ViewModelB can listen to the messages.
here is my implementation
in ViewModelA:
private void btnAddExecute()
{
// I need to instanciate ViewModelB otherwise it wont work/listen
ViewModelB vb= new ViewModelB();
Messenger.Default.Send(new NotificationMessage("ShowWindow"));
}
in ViewModelB i listen to the broadcasted messages in it's constructor.
is there anyway to decouple ViewmodelA from ViewmodelB ?
I don't exactly see where the coupling is occurring if you are using the messenger properly. There is no need to reference ViewModelB
Edit
Here is a way to do it without reference to an instance ViewModelB. It uses a singleton to register for messages and create ViewModelBs when it receives the notification message. I haven't tested this, it is just an idea. Make sure ViewModelBCreator is used at some point so that the static constructor is called.
public class ViewModelBCreator()
{
private static ViewModelBCreator instance;
static ViewModelBCreator() { instance = new ViewModelBCreator(); }
private ViewModelBCreator()
{
Messaging.Messenger.Default.Register<NotificationMessage>(this, true, NotificationMessageReceived);
}
private static void NotificationMessageReceived(NotificationMessage notification)
{
var vm = ViewModelB();
//Do stuff with the new ViewModelB
}
}
public class ViewModelB
{
public ViewModelB()
{
//etc . . .
}
}
public class ViewModelA
{
public void OpenTheWindow()
{
Messenger.Default.Send(new NotificationMessage("ShowWindow"));
}
}
Related
In my class I registered an Event from an external DLL, that will be raised when there are changes on variables from the external code.
public class Model
{
....
public void Connect
{
....
client.OnNotification += (s, e) =>
{
this.OnNotification(s,e);
}
}
}
And I have a ViewModel in which I want get notified when this event is raised in class Model.
public class ViewModel
{
...
// call method when Event in class Model is raised
public void DoSomething()
{
}
}
Any Ideas for a clean and easy way to do that?
Thank you.
Solution 1:
Pass in the client to the viewmodel's constructor and let the viewmodel subscribe to OnNotification() itself (pass in an interface if available)
Solution 2:
Make also the model implement INotifyPropertyChanged if you're using MVVM; pass in the interface into the viewmodel's constructor and subscribe to PropertyChanged.
If you're not using MVVM, you can use the same methodology by adding a custom ClientNotification event to the model, pass in the entire model into the viewmodels constructor, and subscribe to the event.
Solution 3:
Use a messaging system (aka message bus) such as Prism's Event Aggregator class or MVVM Light's Messenger class, or write your own.
EDIT: Here's an example using MVVM Light: (note: coding from memory, not tested)
Add a using reference to GalaSoft.MvvmLight.Messaging;
Create a small message class containing the properties you need. You can inherit from MVVM Light's MessageBase class if you want but its not necessary.
public class ClientNotificationMessage : MessageBase
{
public string SomeProperty { get; set;}
public int AnotherProperty { get; set;}
}
In you model's event handler, you send a message by:
client.OnNotification += (s, e) =>
{
var msg = new ClientNotificationMessage() { ... };
Messenger.Default.Send<ClientNotificationMessage>(msg);
}
In the viewmodel constructor, register to receive messages by:
Messenger.Default.Register<ClientNotificationMessage>(this, msg =>
{
// handle incoming ClientNotificationMessage
// if (msg.SomeProperty != ) ...
});
I'm sure there are other additional solutions that other ppl can add.
The solution is basic OOP design and it is not related to MVVM.
In C# you just don't pass events. You subscribe to events. Whenever something interesting happens in Model, fire en event. You can than subscribe to that event in ViewModel for example.
public class Model
{
public event EventHandler SomethingHappened; // e.g. you notification
}
public class ViewModel
{
public ViewModel(Model model)
{
model.SomethingHappend += SomethingHappend;
}
void Model_SomethingHappend(object sender, EventArgs e)
{
DoSomething();
}
void CleanUp()
{
/*
In order to prevent memoryleak:
If you subscribe to event of an object you have not created in this class
(Model.SomethingHappend in this case), you should also unsubscribe.
Otherwise model instance will keep reference to ViewModel instance.
*/
model.SomethingHappend -= SomethingHappend;
}
}
In your case, the event could be named NotificationRecieved instead of SomethingHappend
You should subscribe to the event directly in the object you want to "react" to the event.
The viewModel in this case. Define an EventHandler there and subscribe
I have following code in my caliburn micro application.
I'm using eventAggregator to send messages from one view model to another.
Consider following code:
public class ShellViewModel : Conductor<IWorkspace>.Collection.OneActive, IShell
{
...
}
public class ViewModelA
{
...
}
public class ViewModelB
{
ViewModelA messageSender{get;set};
...
}
Requirment:
I need to send message from ViewModelA to ViewModelB.
Problem:
There are multiple ViewModel instance are created and added to screen collection. I need to send the message only to a particular ViewModelB instance.
All other viewmodel instance should ignore the message.
Note:
In above code example I'm sending message from viewmodel object messageSender to enclosing class. So the message should be sent to the parent object's instance only.
Question
Is there any build in functionality available in caliburn micro
framework to handle this situation?
If not is there any technique to uniquely identify the viewmodel
instance to process the message?
I don't think Caliburn EventAggregator has this built in. PRISM EventAggregator allows a filter func to be passed in and MVVMLight Messenger uses a token object.
I guess in Caliburn you would need to include something in the message to allow the subscribers to decide whether they should process the message or not.
IHandle<T> is used on the class that needs to "Act" on the message, you publish using IEventAggregator, usually as an injection. remember to Subscribe and Unsubscribe according to Activate and Deactivate when it either goes inactive or gets closed. Only the class that is inheriting the IHandle<T> with its "unique" signature will respond to the broadcast. Now of course if you multiple IHandle<string>'s for example then all VM's will try to process the message that was sent, if they were wired up to do so.
//Handle<T> for any built-in type or something you create like MessageEvent etc.
public class ViewModelB : Screen, IHandle<string>
{
public ViewModelB(IEventAggregator events){
_event = events;
_events.Subscribe(this);
}
private void Handle(string t){
MessageBox.Show(t);
}
}
public class ViewModelA : Screen
{
private readonly IEventAggregator _event;
public ViewModelA(IEventAggregator events)
{
_event = events;
_event.Subscribe(this);
}
public void SomethingWasClicked()
{
_event.PublishOnUIThread("Hello, World!");
}
}
To elaborate on what mvermef said, you need to implement the IHandle<T> interface in the view models that will handle the specific messages. Since he chose a string for the message type, you'd have to parse the message in ViewModelB to handle it if other view models implemented the IHandle<string> interface. Going back to your example and making it more specific for ViewModelB, you could inherit from a base class that handles string-based messages.
public class StringMessageEventBase
{
private string _Message;
public StringMessageEventBase()
: this(null) { }
public StringMessageEventBase(string message)
{
_Message = message;
}
public string Message
{
get { return _Profile; }
set { _Profile = value; }
}
}
public class ViewModelBMessageEvent : StringMessageEventBase
{
public ViewModelBMessageEvent(string message)
: base(profile) {}
}
Now if you implement IHandle<ViewModelBMessageEvent> in your view model, ViewModelB, then only instances of ViewModelB will handle the message.
public class ViewModelB : IHandle<ViewModelBMessageEvent>
{
private readonly IEventAggregator _Aggregator;
public ViewModelB(IEventAggregator aggregator)
{
if (aggregator == null)
throw new ArgumentNullException("aggregator");
_Aggregator = aggregator;
_Aggregator.Subscribe(this);
}
public void Handle(ViewModelBMessageEvent message)
{
// do some thing with your message here
var msg = message.Message;
}
}
Using Prism4 and MEF I have created a shell and two modules(M1,M2).
I do want to open a serial port in M1 and by using an interface, with an datareceived event from the opened serial port, I want that M2 gets notified and receives the data from the serial port.
To be more specific, I use the MVVM pattern, therefore I would like to open the serial port within the M1's ViewModel, and inform the M2's ViewModel when data are received.
Unfortunately, I'm quite unsure how to use the interface within the PRISM workflow. I'm thankful for every help. I really need an example for this issue.
I added the code just to make my question clear.
Thanks in advance.
Module A.cs
[ModuleExport(typeof(ModuleA), InitializationMode = InitializationMode.OnDemand)]
public class ModuleA : IModule
{
[ImportingConstructor]
public ModuleB(IEventAggregator eventAggregator_)
{
EventAggregator = eventAggregator_;
}
[Import]
public IRegionManager RegionManager { get; set; }
public void Initialize()
{
this.RegionManager.RegisterViewWithRegion("RegionA", typeof(ZeroGrid1));
}
}
Module B.cs
[ModuleExport(typeof(ModuleB), InitializationMode = InitializationMode.OnDemand)]
public class ModuleB : IModule
{
[ImportingConstructor]
public ModuleB(IEventAggregator eventAggregator_)
{
EventAggregator = eventAggregator_;
}
[Import]
public IRegionManager RegionManager { get; set; }
public void Initialize()
{
this.RegionManager.RegisterViewWithRegion("RegionB", typeof(ZeroGrid2));
}
}
ZeroGrid1.xaml.cs (similar to ZeroGrid.xaml.cs)
[Export]
public partial class ZeroGrid1
{
[ImportingConstructor]
public ZeroGrid1(ZeroGridViewModel1 viewModel)
{
InitializeComponent();
this.DataContext = viewModel;
}
}
ModuleAViewModel.cs
[Export]
public class ModuleAViewModel: NotificationObject, IDataReciever
{
// OPEN SERIALPORT
//SEND SOMETHING SERIALPORT
//Maybe I also wanna get notification for datareceived here
}
ModuleBViewModel.cs
[Export]
public class ModuleBViewModel: NotificationObject, IDataReciever
{
//GET NOTIFIED WHEN DATARECEIVED FROM SERIALPORT AND RECEIVED DATA
}
IDataReceiver.cs
interface IDataReciever<TData>
{
event Action<TData> DataRecieved;
//some other methods, such as, for example:
//void Open();
//void Close();
}
Define a composite presentation event, by exporting a classed which derives from Prism's 'CompositePresentationEvent' where T is the type of the event's 'payload'.
[Export]
public class DataReceivedEvent : CompositePresentationEvent<object>
{}
Make your two ViewModels import that event:
[Export]
public class ModuleAViewModel: NotificationObject, IDataReciever
{
private DataReceivedEvent _dataReceivedEvent;
[ImportingConstructor]
public ModuleAViewModel(DataReceivedEvent dataReceivedEvent)
{
_dataReceivedEvent = dataReceivedEvent;
_dataReceivedEvent.Subscribe(OnDataReceived);
}
private void OnDataReceived(object payload)
{
// Handle received data here
}
// This method gets called somewhere withing this class
private void RaiseDataReceived(object payload)
{
_dataReceivedEvent.Publish(payload);
}
}
Do the same in ViewModelB and both will get notified if the event is raised anywhere in the application.
There is a QuickStart solution available in MSDN which describes how publishing the event from one module and subscribing to it from the other is performed. You can find the Event Aggregation QuickStart in the following Prism Guide Appendix:
Appendix G: QuickStarts - Event Aggregation QuickStart
For more information of how EventAggregator works you can refer to the following Prism Guide chapter:
Communicating Between Loosely Coupled Components
Regards.
Goal: Have a singleton publish events and allow any class to subscribe/listen to those events
Problem: I cannot figure out how to do this. The code below is illegal but it purveys what I'm trying to do
TransmitManager Class - Publisher
//Singleton
public sealed class TransmitManager
{
delegate void TransmitManagerEventHandler(object sender);
public static event TransmitManagerEventHandler OnTrafficSendingActive;
public static event TransmitManagerEventHandler OnTrafficSendingInactive;
private static TransmitManager instance = new TransmitManager();
//Singleton
private TransmitManager()
{
}
public static TransmitManager getInstance()
{
return instance;
}
public void Send()
{
//Invoke Event
if (OnTrafficSendingActive != null)
OnTrafficSendingActive(this);
//Code connects & sends data
//Invoke idle event
if (OnTrafficSendingInactive != null)
OnTrafficSendingInactive(this);
}
}
Test Class - Event Subscriber
public class Test
{
TrasnmitManager tm = TransmitManager.getInstance();
public Test()
{
//I can't do this below. What should my access level be to able to do this??
tm.OnTrafficSendingActive += new TransmitManagerEventHandler(sendActiveMethod);
}
public void sendActiveMethod(object sender)
{
//do stuff to notify Test class a "send" event happend
}
}
You shouldn't need to make the events static.
public event TransmitManagerEventHandler OnTrafficSendingActive;
public event TransmitManagerEventHandler OnTrafficSendingInactive;
Either your events have to be instance members or you have to address them as static.
TransmitManager.OnTrafficSendingActive +=...
OR
public event TransmitManagerEventHandler OnTrafficSendingActive;
...
TransmitManager.Instance.OnTrafficSendingActive+=...
Also: use EventHandler as your event delegate. Consider making a custom arguments class and pass the status to just one event instead of multiple events. This will let you pass status messages as well.
I'm learning to apply MVP to a simple WinForms app (only one form) in C# and encountered an issue while creating the main presenter in static void Main(). Is it a good idea to expose a View from the Presenter in order to supply it as a parameter to Application.Run()?
Currently, I've implemented an approach which allows me to not expose the View as a property of Presenter:
static void Main()
{
IView view = new View();
Model model = new Model();
Presenter presenter = new Presenter(view, model);
presenter.Start();
Application.Run();
}
The Start and Stop methods in Presenter:
public void Start()
{
view.Start();
}
public void Stop()
{
view.Stop();
}
The Start and Stop methods in View (a Windows Form):
public void Start()
{
this.Show();
}
public void Stop()
{
// only way to close a message loop called
// via Application.Run(); without a Form parameter
Application.Exit();
}
The Application.Exit() call seems like an inelegant way to close the Form (and the application). The other alternative would be to expose the View as a public property of the Presenter in order to call Application.Run() with a Form parameter.
static void Main()
{
IView view = new View();
Model model = new Model();
Presenter presenter = new Presenter(view, model);
Application.Run(presenter.View);
}
The Start and Stop methods in Presenter remain the same. An additional property is added to return the View as a Form:
public void Start()
{
view.Start();
}
public void Stop()
{
view.Stop();
}
// New property to return view as a Form for Application.Run(Form form);
public System.Windows.Form View
{
get { return view as Form(); }
}
The Start and Stop methods in View (a Windows Form) would then be written as below:
public void Start()
{
this.Show();
}
public void Stop()
{
this.Close();
}
Could anyone suggest which is the better approach and why? Or there even better ways to resolve this issue?
What about the following:
// view
public void StartApplication() // implements IView.StartApplication
{
Application.Run((Form)this);
}
// presenter
public void StartApplication()
{
view.StartApplication();
}
// main
static void Main()
{
IView view = new View();
Model model = new Model();
Presenter presenter = new Presenter(view, model);
presenter.StartApplication();
}
That way, you don't need to expose the view to the outside. In addition, the view and the presenter know that this view has been started as a "main form", which might be a useful piece of information.
I would go for the second approach.
You could also get rid of the extra property by simply casting view to form in the void Main, since you know it is a form anyway at that point (I see no reason to make it more generic than that since it just starts the winform app)
Application.Run(view as Form);
Things get a bit more complex if you allow more than one way to exit the application (e.g.: a menu item for exiting), or if you prevent closing of the application under certain conditions. In either case, the actual invocation of application closing should usually be invoked from presenter code rather than by simply closing the concrete view. This can be accomplished by using either the Application.Run() or Application.Run(ApplicationContext) overloads and exposing the application exit action via inversion of control.
The exact approach to registering and using the application exit action would depend on the IoC mechanism (e.g.: service locator and/or dependency injection) that you are using. Since you haven't mentioned what your current IoC approach might be, here's a sample that's independent of any particular IoC frameworks:
internal static class Program
{
[STAThread]
private static void Main()
{
ApplicationActions.ExitApplication = Application.Exit;
MainPresenter mainPresenter = new MainPresenter(new MainView(), new Model());
mainPresenter.Start();
Application.Run();
}
}
public static class ApplicationActions
{
public static Action ExitApplication { get; internal set; }
}
public class MainPresenter : Presenter
{
//...
public override void Stop()
{
base.Stop();
ApplicationActions.ExitApplication();
}
}
This basic approach could be adapted quite easily to your preferred IoC approach. For example, if you're using a service locator, you would probably want to consider removing at least the setter on the ApplicationActions.ExitApplication property, and storing the delegate in the service locator instead. If the ExitApplication getter were to remain, it would provide a simple façade to the service locator instance retriever. e.g.:
public static Action ExitApplication
{
get
{
return ServiceLocator.GetInstance<Action>("ExitApplication");
}
}
You could do it in a hundred ways to achieve the ultimate goal of separability of concerns. There is no hard and fast rule here, the basic idea is that presenter deals with presentation logic of the view, while the view has only the dumb knowledge of its own GUI specific classes and stuffs. Some ways I can think of (to broadly put):
1) View kick-starts things and let it decide its presenter. You start like, new View().Start();
// your reusable MVP framework project
public interface IPresenter<V>
{
V View { get; set; }
}
public interface IView<P>
{
P Presenter { get; }
}
public static class PresenterFactory
{
public static P Presenter<P>(this IView<P> view) where P : new()
{
var p = new P();
(p as dynamic).View = view;
return p;
}
}
// your presentation project
public interface IEmployeeView : IView<EmployeePresenter>
{
void OnSave(); // some view method
}
public class EmployeePresenter : IPresenter<IEmployeeView>
{
public IEmployeeView View { get; set; } // enforced
public void Save()
{
var employee = new EmployeeModel
{
Name = View.Bla // some UI element property on IEmployeeView interface
};
employee.Save();
}
}
// your view project
class EmployeeView : IEmployeeView
{
public EmployeePresenter Presenter { get; } // enforced
public EmployeeView()
{
Presenter = this.Presenter(); // type inference magic
}
public void OnSave()
{
Presenter.Save();
}
}
A variant of the above approach would be to enforce stronger generic constraint on view and presenter, but I dont think the complexity outweighs the benefits. Something like this:
// your reusable MVP framework project
public interface IPresenter<P, V> where P : IPresenter<P, V> where V : IView<P, V>
{
V View { get; set; }
}
public interface IView<P, V> where P : IPresenter<P, V> where V : IView<P, V>
{
P Presenter { get; }
}
public static class PresenterFactory
{
public static P Presenter<P, V>(this IView<P, V> view)
where P : IPresenter<P, V>, new() where V : IView<P, V>
{
return new P { View = (V)view };
}
}
// your presentation project
public interface IEmployeeView : IView<EmployeePresenter, IEmployeeView>
{
//...
}
public class EmployeePresenter : IPresenter<EmployeePresenter, IEmployeeView>
{
//...
}
Disadvantages
interacting between forms are less intuitive to me.
Steps involved:
implement IEmployeeView
instantiate presenter by calling PresenterFactory and passing this from the view constructor
ensure view events are wired to their corresponding presenter methods
start off, like new EmployeeView()....
2) Presenter kick-starts things and let it decide its view. You start like, new Presenter().Start();
In this approach presenter instantiates its own view (like approach 1) by means of some dependenchy injection or so, or view can be passed to presenter's constructor. E.g.
// your reusable MVP framework project
public abstract class IPresenter<V> // OK may be a better name here
{
protected V View { get; }
protected IPresenter()
{
View = ...; // dependenchy injection or some basic reflection, or pass in view to ctor
(View as dynamic).Presenter = this;
}
}
public interface IView<P>
{
P Presenter { get; set; }
}
// your presentation project
public interface IEmployeeView : IView<EmployeePresenter>
{
void OnSave(); // some view method
}
public class EmployeePresenter : IPresenter<IEmployeeView>
{
public void Save()
{
var employee = new EmployeeModel
{
Name = View.Bla // some UI element property on IEmployeedView interface
};
employee.Save();
}
}
// your view project
class EmployeeView : IEmployeeView
{
public EmployeePresenter Presenter { get; set; } // enforced
public void OnSave()
{
Presenter.Save();
}
}
Steps involved:
implement IEmployeeView
ensure view events are wired to their corresponding presenter methods
start off, like new EmployeePresenter(....
3) Event based, observer style
Here you could either encapsulate presenter in view (instantiate presenter in view) like approach 1 or encapsulate view in presenter (instantiate view in presenter) like approach 2 but in my experience latter will always be the cleaner design to work with. An e.g. of latter:
// your reusable MVP framework project
public abstract class IPresenter<V> where V : IView
{
protected V View { get; }
protected IPresenter()
{
View = ...; // dependenchy injection or some basic reflection, or pass in view to ctor
WireEvents();
}
protected abstract void WireEvents();
}
// your presentation project
public interface IEmployeeView : IView
{
// events helps in observing
event Action OnSave; // for e.g.
}
public class EmployeePresenter : IPresenter<IEmployeeView>
{
protected override void WireEvents()
{
View.OnSave += OnSave;
}
void OnSave()
{
var employee = new EmployeeModel
{
Name = View.Bla // some UI element property on IEmployeedView interface
};
employee.Save();
}
}
// your view project
class EmployeeView : IEmployeeView
{
public event Action OnSave;
void OnClicked(object sender, EventArgs e) // some event handler
{
OnSave();
}
}
// you kick off like new EmployeePresenter()....
Disadvantage:
You have to wire events on both view and presenter sides - double the work
Steps involved:
implement IEmployeeView
ensure iview events are called from view event handler methods
ensure iview event members are initialized from presenter
start off, like new EmployeePresenter()....
Limitations of language sometimes make design patterns more difficult. For e.g, had multiple inheritance been possible in C#, it was only a matter of having an abstract base view class with all the implementation details except UI specific components which could be then implemented by view class. No presenters, classic polymorphism and dead simple! Unfortunately this is not possible since most view classes in .NET (like Form of WinForms) already inherits from a super view class. So we have to implement an interface and go for composition. Also, C# doesnt let you have non-public members in an interface implementation, so we are forced to make all members specified in IEmployeeView public which breaks the natural encapsulation rules of the view class (i.e. other views in the view project can see details of EmployeeView irrelevant to them). Anyway, using power of C#'s extension methods a much simpler but very limited approach can be taken.
4) Extension method approach
This is just silly.
// your presentation project
public interface IEmployeeView
{
void OnSave(); // some view method
}
public static class EmployeePresenter // OK may need a better name
{
public void Save(this IEmployeeView view)
{
var employee = new EmployeeModel
{
Name = view.Bla // some UI element property on IEmployeedView interface
};
employee.Save();
}
}
// your view project
class EmployeeView : IEmployeeView
{
public void OnSave()
{
this.Save(); // that's it. power of extensions.
}
}
Disadvantages:
fairly unusable for anything remotely complex
Steps involved:
implement IEmployeeView
ensure this.... extension method is called from view events
kick off things by calling new View...
Of all 2 and 3 look better to me.