Calling method of UserControl from ViewModel with Caliburn.Micro - c#

I'm writing a ViewModel-first MVVM application using Caliburn.Micro
My View contains a 3rd party UserControl that implements a Method I want/need to call from the associated ViewModel. How do I do that while still upholding the MVVM principles?
There exists an old thread here on SO where a similar question is asked in a more specific context. I would appreciate it if someone could flesh-out the approaches suggested there a bit.
Approach one suggests that the View could subscribe to an IEventAggregator message. But wouldn't I have to use the code behind file to do that? (I thought that was a big no no in MVVM)
Regarding approach two, I have no idea how to do that. And regarding approach three, thats what I tried first but somehow I didn't quite get it to work.

Let me clarify your understanding:
Yes code in the code-behind is generally avoided, but only because MVVM makes it so easy to bind to viewmodel properties and commands in order to wire up your visual element with the functionality behind the scenes
Code that is view-specific in the code-behind of the view is perfectly acceptable assuming it doesn't cross the boundary of concern. For instance, I have a view in my application that does some visual processing of the page, and to do so I require that there is code in the view. This code may also interact with the viewmodel layer, but it will not directly reference the viewmodel, therefore keeping my components loosely coupled
If you have controls that need particular methods calling, then creating an event aggregator message to propagate the notification to the view is perfectly fine since you are still maintaining the separation of concern between the viewmodel and view (and the application components remain encapsulated and testable)
Example View (I've left all event aggregator wire up code and potential dependency injection stuff out for clarity):
public class MyView : IHandle<SomeNotificationMessageType>
{
// Handler for event aggregator messages of type SomeNotificationMessageType
public void Handle(SomeNotificationMessageType message)
{
// Call a method on one of the page controls
SomePageControl.SomeMethod();
}
}
Obviously, what you wouldn't do is something like this in the ViewModel:
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var view = this.GetView() as MyView;
view.SomePageControl.SomeMethod();
}
}
Which violates the MVVM principles since you are tightly coupling MyViewModel and MyView.
What if you wanted to use the Context property in caliburn micro which allows multiple views over the same view model? The code above would break - even if you checked the View type, you would still end up with spaghetti code e.g.
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var myview = this.GetView() as MyView;
if(myview != null)
myview.SomePageControl.SomeMethod();
var myotherview = this.GetView() as MyOtherView;
if(myotherview != null)
myotherview.SomePageControl.SomeMethod();
// ad infinitum...
}
}
Of course this is subjective: it may be that your usercontrol affects the viewmodel and the view in a complex way, in which case you might want to consider looking at the architecture and working out how that usercontrol can better fit
Have you got any background on what the UC is and what the method on it does?

Related

Correct approach when notifying ViewModels of UserControl events in WPF MVVM?

In my WPF View, I'm loading data into User Controls like this:
<ContentControl Content="{Binding ItemEditVm}" />
And then in the ViewModel:
private ItemEditViewModel _itemEditVm;
public ItemEditViewModel ItemEditVm
{
get
{
return _itemEditVm;
}
set
{
_itemEditVm = value;
OnPropertyChanged("ItemEditVm");
}
}
I've got a series of DataTemplates to say which View belongs to which ViewModel. And then in my business logic, I can just spin up a new ViewModel for the UserControl then assign it to the property and all works as expected.
However, to resolve the next task in this application, I need to be able to notify the parent ViewModel of events occurring inside the UserControl. I've done this with a simple event on my child ViewModel and a listener on the parent:
public event EventHandler ItemEditViewModelChanged();
So when I create my ViewModel I can just add a listener:
ItemEditViewModel vm = new ItemEditViewModel(itemId);
vm.ItemEditViewModelChanged += vm_ItemEditViewModelChanged;
And do what needs to be done in vm_ItemEditViewModelChanged().
However, I am instinctively uncomfortable with this. While it doesn't violate any MVVM principles direclty (things are still testable, Views and ViewModels are still separate), it doesn't seem a very flexible way of doing things and it does create undesirable logical links between ViewModel classes.
Is there a better way of doing this? Is my approach to creating and loading UserControls into ContentControls a poor way of creating child controls? Or am I worrying over nothing?
I personally prefer to implement things like this with dependency injection. Typically there will be multiple notifications that need to be made, so start by declaring an interface:
public interface ICustomEventHandler
{
void Event1();
void Event2();
// .. etc
}
Then in the child vm you use dependency injection to inject whatever object needs to watch it:
public class ChildVM
{
[Inject] public ICustomEventHandler Watcher {get; set;}
// .. etc ..
}
First of all this makes mocking very easy, so your unit tests are covered, but more importantly you've formalized the dependencies between this module and the rest of the code and also kept your options open as to how best to implement it. (A simple solution would be for the parent to implement that interface directly and inject itself into the child at creation, in another case you may need to use an intermediate class with singleton scoping or multiple clients).
I am not sure whether this work for you but just my thought.
If you have a MainViewModel which holds your all other ViewModels like the picture above then you can expose Properties/Methods to invoke MainViewModel and Let MainViewModel take the decision to talk to a different ViewModel.

C# MVVM Where Does the Service Layer Sit?

I am attempting to develop a little program which will communicate with a device on a serial port. The program will be responsible for formatting user entered data and reading and presenting values received by the device. I am pretty new to WPF and MVVM and have achieved a basic understanding of the whole databinding / XAML mess (I think).
Currently my understanding goes something like:
View: UI only stuff. Binds to ViewModel.
ViewModel: Takes a model or various properties of a model and presents them in a way that the View can understand. Also provides a way for the view to modify the model.
Model: The data the UI presents and modifies.
Now I am at a loss as to what provides Models to the ViewModel such that the application as a whole is aware of changes to Models.
The Model currently looks something like the following. My device takes calibration records and can read back all the calibration records.
public class Device : ObservableObject
{
public ObservableCollection<CalibRecord> CalibRecords { get; set; }
private SerialPort sp;
public Device(SerialPort port)
{
this.sp = port;
this.CalibRecords = new ObservableCollection<CalibRecord>();
}
public void WriteCalibration(CalibRecord record)
{
/* Write a calibration record to the device */
}
public void ReadCalibration()
{
/* Read all calibration records from the device and update CalibRecords */
}
}
I am struggling for a place to put this guy so that it can be accessed by the entire application. Currently I instantiated it in the main window's ViewModel but then it can't be accessed by other ViewModels unless I inject it into the constructor. This is fine for a couple classes but gets unwieldy quickly the more classes a ViewModel needs.
Perhaps this is what the so-called "business logic" or "service layer" is. Can you help me understand where to put the business logic in an MVVM app? Or, do you guys have some examples I should look at that focuses on the whole application (particularly the business logic) and not just the MVVM stuff?
Your understanding of MVVM is correct, but the "textbook description" doesn't account for services. Typically this is done with dependency injection (DI). Define an interface, IMyDevice and implement it in a MyDevice class. Then register it with your DI container IMyDevice -> MyDevice. By using a DI container (properly) you'll also take yourself out of the VM construction picture. You would have a VM something like:
public class MyViewModel : ViewModelBase
{
public MyViewModel(IMyDevice myDevice)
{
}
}
to get an instance of the VM, you would do:
theDIContainer.Resolve<MyViewModel>();
and it would new up the MyViewModel class and automatically resolve and pass in the IMyDevice instance for you.
There is a lot more to DI then I covered here... just a basic 10,000 mile high answer to your question. Read up on DI and see how it comes into play with MVVM.
The mindset of MVVM is to separate in a loosely coupled manner layers, allowing each to be modified and tested without interfering with the other.
You test the ViewModel and mock the Models. You test the Models. Your Model may take form of several services automatically injected by some DI container. Subsequently there is as little as possible friction between the Models, the ViewModel. Eventually they may be deployed independently; this lowers maintenance and cost; that's the same mindset of that of microservices.
For instance, you might have a Model that is tested and can be used for a WPF app, mobile app, web app, etc. Your ViewModel however should not a priori be involved in another GUI. You can update your webapp without commit/deploy for the other and the Model; lower cost, lower duration commit-to-deploy (including testing).
When you start with cohesive classes and test them, it will be clear where to put what.
It's OK to have only a View and a ViewModel; though the Model should have the business logic if it's enough rich; you should have tests for the Model, tests for the ViewModel ( behavior of the UI). The VM and the Model layers can be much more complicated than just 2 classes, you may have multiple (automatic) dependency injections (check the excellent Dependency Injection in .NET, Mark Seemann).
Subsequently, logic (for your business) should go in the Model, not in the ViewModel; logic for the UI should go in the VM.
Regarding WPF, the View take the form of a UserControl with View.xaml (what you see) and View.xaml.cs (the code-behind); not all UI logic goes into the ViewModel; pure View logic goes into the code-behind. The code-behind contains in particular all the dependency properties, behavior logic (shared with the xaml code) etc.

C# WPF MVVM Window OnLoad Binding

My Code behind looks like this...
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
My ViewModel looks like this...
class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
bool flag = Application.Current.MainWindow.IsInitialized;
if (flag)
{
// Do something...
}
}
I guess my question is....Does this conform to the MVVM design pattern? The only other way to do this is How to fire a Command when a window is loaded in wpf
I don't know why, but I don't want to use mvvm-light or any other boilerplate code..
Accessing UI component from ViewModel is violation of MVVM pattern.
Application.Current.MainWindow.IsInitialized is breaking that pattern.
Custom behaviours is more in accordance with MVVM. So, i would suggest to go with the approach you mentioned as link in your question.
Accessing UI component breaks the testability of your ViewModel. How would you write testcase for your ViewModel class? Application.Current will be null when you try to test it via unit test and it will throw null reference exception.
One of the main motive of MVVM was to seperate UI logic from business
logic so that business logic can be tested separately without worrying
about its consumer which is view.
There is no "pure" way to do this in MVVM without boilerplate code. In general, you shouldn't need to do work in response to the VIew within your VM - just the concept is a violation of MVVM, since your ViewModel is trying to do something in response the View, and things should always flow the other way.
The ViewModel shouldn't, in a real scenario, care about the View's state at all - it should be doing nothing but presenting data for data binding by the View.
Most of the time when people are attempting this, it's to try to avoid loading data up front. This is something that's typically handled better by pushing the data to load and starting it directly on a background thread within the ViewModel, then updating the property within the VM when it completes. C# 5's async/await language features can be used to simplify this quite a bit.
While it is generally believed that having some load/unload logic is a pattern violation, there is a set of use cases, where it's necessary. E.g. a view model may need to be subscribe to some events. If it didn't unsubscribe when unloaded, it might not be garbage collected, depending on the nature of the subscription.
What would break the pattern is accessing view state from within the view model, e.g. manipulating controls. The role of the view model is to expose data to the view and managing load/unload behaviour is part of this contract. Knowing when a view model is loaded means knowing when to expose that data.
While it is true the view model should not care about state of the view, it must know how to prepare data for presentation in the view. More importantly the view model is a layer between the model and the view that makes them separate. Yet in other words: since 'model' means logic, then 'view model' means logic of getting data to display. And it is also about knowing when to fetch it/make it available/etc.
You may want to take a look at this blog post, which provides a convenient way of making a view model aware of being loaded. It is not 100% correct in terms of MVVM purity, because it passes FrameworkElement back into the view model, but imagine we ignore this parameter.
The sample code below is based on the above blog post, but with purer signatures. You could implement IViewModel interface on your classes:
public interface IViewModel : INotifyPropertyChanged
{
void Load();
void Unload();
}
Then instruct the view to call adequate methods when loaded or unloaded by using an attached property:
ViewModelBehavior.LoadUnload="True"
Notice the last line has its place in XAML - the view is the one that enforces a certain behaviour, not vice-versa.
What you are currently doing is correct and that is how it is really done with other frameworks behind the scenes.
Since you mentioned MVVM-Light, I suggest you can take a look at caliburn micro. It has very nice framework to conform the MVVM Pattern. Caliburn micro makes it easy to hook up bindings with events on the controls. Just check out its documentation and it is still considered as MVVMy..
in particular because MVVM is mainly used to guarantee easy to maintain and testable code, you should bear in mind that Application.Current will be null if you use the MainViewModel in UnitTests. Therefore this code will end in a NullPointerException in your tests.
You should consider using the Initialized event if you want to ensure that something is initialized already. But you create the ViewModel after you called InitializeComponent - I simply would leave the check out.

Is this a valid MVP Pattern Implementation

I'm trying to analyse some code here that's been designed using an MVP Approach. No specific MVP Framework has been used. This is all hand-written code.
//Interface Representing our View
public interface IFooView
{
string SomeScreenValue
}
//Presenter Implementation
public class FooPresenter
{
private readonly IFooView _view;
public FooPresenter (IFooView view)
{
//The presenter gets instantiated with a reference to a view.
_view = view
}
public void SomeButton_Click(object sender, EventArgs e)
{
_view.SomeScreenValue = "The Result";
}
}
//The Page Implementation
public class FooPage : System.Web.UI.Page, IFooView
{
private FooPresenter _presenter;
protected void Page_Init(...)
{
_presenter = new FooPresenter(this);
//<-- The View has a Presenter, which references the same View...
Button1.Click += new EventHandler(_presener.SomeButton_Click);
}
}
It works in that it allows the developer to move the business logic away from the code behind into classes, while still affecting the View. But the absense of an actual Model, and the way in which the View => Presenter => View relationship is setup is just a little irksome to me?
So is the above situation a valid implementation of the MVP Pattern ?
This is almost MVP in that your Presenter is de-coupled from the view in such a way that when it updates the UI state it does so through the IFooView interface. However, having a method within your presenter that conforms to a standard .NET event handler seems wrong to me. I would make IFooView raise an event when a button click occurs, then your page can perform the task of handling the button click as you currently do, then raising the event which your Presenter handles. This event can be more closely related to the domain, for example you might want an event such as RecordUpdated exposed via your IFooView.
This will make it easier to provide a mock implementation of IFooView for unit testing, which is after all a big advantage of using an MVP / MVC / MVVM pattern.
If you do not have any data coming from a back-end service, or database, then in the case of simple applications it is OK for the Presenter to take on the role of the model as well. This is the case in your trivial example. The same can be done in MVVM, where the ViewModel can take on the Model responsibilities also. However, I would recommend creating a Model if you do anything non-trivial. In your case, the Presenter would delegate to the Model for maintaining state and would use some sort of 'service' to persist changes to this model, or retrieve model objects from web services.
Yes it is.
But...
I should change the presenter construction to FooPage constructor instead. Sometime you want to handle the preInit event and that´s not possible with this setup.
Yes it is, this is the "passive view" variant of model view presenter. In this variant, the view has no knowledge of the view whatsoever. The view is dumb and fully controlled by the presenter.
The MVP pattern was described by Fowler in 2004 and he retired it in 2006 by splitting the pattern into supervising conroller (sc) and Passive View (pv). In sc, the view is bound to the model and in pv not, in pv the view is only changed by the presenter directly.

c# WPF Threading an OnResponse event to MainWindowViewModel from singleton object

Greetings my smart programming friends!
I have created an OnResponseEvent for an object that is injected into my viewmodel via UnityContainer.
From my injected object class:
public delegate void ResponseEventHandler(AbstractResponse response);
public event ResponseEventHandler OnResponseEvent;
Constructor for MainWindowViewModel:
public MainWindowViewModel(ITrack track)
{
this._track = Track;
track.OnResponseEvent += UpdateTrackResponseWindow;
}
Created delegate to handle the OnResponseEvent in my MainWindowViewModel:
private delegate void HandleTrackResponseCallback(AbstractResponse message);
Since the OnResponseEvent is sending a message, I need to interpret the message in a separate thread and display in a listBox.
Here is where I get confused. If I were using WinForms to write this application, I could use the following code because WinForms knows about my listBox:
if (ListBox.InvokeRequired)
{
var d = new HandleTrackResponseCallback(UpdateTrackResponseWindow);
Invoke(d, new object[] { message });
}
else
lstTrackResponse.Text = Interpret(message); //Interpret is a separate method
However, I am using WPF, and my MainWindowViewModel class does not know anything about my listBox which is located in a view.
Can anyone provide example code how I might handle the OnResponseEvent on a different thread in my MainWindowViewModel class?
Thanks so much, any help is greatly appreciated.
Manipulating the view from the view-model goes against the basic architectural principles of MVVM. Even if it weren't a being called from a different thread it would still not be a wise thing to do.
In MVVM, you would handle this like you do any other data that needs to be displayed in the view:
process and store the data in the view-model itself (using your event handler)
expose it as property including change notification
access that property from the view using traditional data binding
Something as simple as:
<TextBox Text="{Binding Response}"/>
This approach even takes care of the threading problem because now you handle the concurrency issues in the view-model, instead of in the view. Just lock access to the property that TextBox.Text is bound to while you are modifying it.
In general, MVVM avoids ever having a direct dependency of the view-model on the view for several reasons:
the big picture goal of loose-coupling between the view-model and the view
the ability to unit test the view-model without a view
At first this separation might seem clumsy and requires extra work (see above) but it really is worth it and it's what we need to do to get the benefits of the MVVM approach.

Categories

Resources