Consultation about the best design for MVVM - c#

little question. I'm progrraming in MVVM design pattern (C#).
the View is an Excel add-in, and I want to run from the View_Model a method that found in the View. I thought about 2 ways:
Hold in the View Model a pointer to the View (the pointer type is an interface that the View and the View_Model inherit from, otherwise I would get a circular independence because the View hold the View_Model and the View_Model hold the View), and then run the method directly from him.
Create an event in the View_Model and sign the method in the View to that event in the View_Model pointer which I already have in the View, and raise the event when I want to run this method.
Somehow, way number 2 feel little like screaming in the street to only one man instead off go straight and talk to him normally. On the other hand, the advantage in way number 2, is that in the future if I would have other method that relate to this operation I could just sign them to that event and not call them specially.
what would you do?

Method 1 breaks the MVVM principle since the view model should not know about the view. Your approach is a bit like the MVP design pattern.
I would say method 2 is the better approach, it's perfectly fine for the view to know about the view model. It also gives you the flexibility to do whatever you want when that event is raised, say for example, if you wanted to use a different view and call a different method.
Also, this kind of thing can be done using a good messaging framework. The view model publishes a message, the view subscribes to it. The mvvmlight frame work has a good implementation of this, but I am sure there are others too.

take an Interface, implement the view from it. And instantiate the viewmodel by passing this view.
lets say -
Interface
public interface IFooView
{
...
}
View
public Class FooView : IFooView
{
private FooViewModel _viewModel;
public FooView()
{
_viewModel = new FooViewModel(this);
}
}
ViewModel
public class FooViewModel
{
private FooView _view;
public FooViewModel(IFooView view)
{
_view = view;
}
}
Now, you can call the ViewModel from View, also View from ViewModel.

Related

wpf mvvmlight passing data to viewmodel

I have the following views and viewModels View: Staff, VM: StaffViewModel and View: Notes, VM: NotesViewModel.
My StaffViewModel has a SelectedStaffMember property of type SelectedEmployee.
The Staff view has a button that launches another view (Notes).
When the user enters a note I need to save it against the SelectedEmployee, which means the NotesViewModel needs to know the currently selected employee ID.
Right now Im doing this via my ViewModelLocator but this seems wrong, what is the corret way to pass data to a VM???
I'm using MVVM Light.
Relevant code - StaffViewModel
public Employee SelectedEmployee
{
get { return _selectedEmployee; }
set
{
if (value == _selectedEmployee) return;
_selectedEmployee = value;
HolidayAllowance = _staffDataService.GetEmployeeHolidayAllowance(_selectedEmployee.Id);
RaisePropertyChanged();
RaisePropertyChanged(nameof(HolidayAllowance));
}
}
NoteViewModel
public RelayCommand SaveNoteCommand { get; private set; }
private void SaveNote()
{
var note = new Note
{
NoteContent = NoteContent,
EmployeeId = ViewModelLocator.Staff.SelectedEmployee.Id,
NoteDate = NoteDate
};
_dataService.SaveNote(note);
}
I'm using MahApps Flyouts to show the view for add note:
This is where the view is shown, it is launched from MainView.xaml NOT Staff.xaml, which I think is going to be another issue of getting SelectedEmployee ID:
MainView.xaml
<controls:Flyout Name="AddNoteFlyout"
Header="Add Note"
IsModal="True"
IsOpen="{Binding IsAddNoteOpen}"
Opacity="85"
Position="Right"
Width="450">
<views:AddNote VerticalAlignment="Top" Margin="0,30,0,0"/>
</controls:Flyout>
Im considering firing a message on the button click that launches the View, which my staff view would register against. The message would contain the selectedEmployeeId. Would that be a better way?
The simple way
The simple way is what you are doing, but maybe a bit better solution is to create a static or singleton class like a NavigationParameterContainer and store the selected StaffMember in a public property. Then you can retrieve it in your NotesViewModel
The best practice
The better solution for passing data between ViewModels is using a custom navigation service, and navigation aware ViewModels.
MVVMLight don't support this, so either you use a different framework like Prism or write yourself an architecture that you can use for making parameterized navigationt.
The base idea is that you create an INavigationAware interface that support navigation lifecycle callbacks like OnNavigatedTo, which receives an object representing the NavigationParamter (the selected StaffMember).
Then you create some kind of NavigationService with a Navigate method, that accepts some parameter to determine the Page you want to navigate to, and an object wich is the NavigationParamter.
When you navigate you call the Navigate method on your Service and pass the selected item as parameter. Then you need to make the actual navigation inside your service, and after the navigation is finished, you call the OnNavigatedTo callback on your ViewModel if it is implementing the INavigationAware interface. (You can retreive the VM from the Page.DataContext and cast it to INavigationAware if it is not null you can call the OnNavigatedTo).
Finally in your NotesViewModel you just need to implement the INavigationAware interface, and handle the parameter you received in the OnNavigatedTo method.
This is just the basic idea but I strongly recommend you to see some MVVM framework that already implements this. (like PrismLibrary).

How to manage multiple windows in MVVM

I am aware there are a couple of questions similar to this one, however I have not quite been able to find a definitive answer. I'm trying to dive in with MVVM, and keep things as pure as possible, but not sure how exactly to go about launching/closing windows while sticking to the pattern.
My original thinking was data bound commands to the ViewModel triggering code to start a new View, with the View's DataContext then set to it's ViewModel via XAML. But this violates pure MVVM I think...
After some googling/reading answers I came across the concept of a WindowManager (like in CaliburnMicro), now if I was to implement one of these in a vanilla MVVM project, does this go in with my ViewModels? or just in the core of my application? I'm currently separating out my project into a Model assembly/project, ViewModel assembly/project and View assembly/project. Should this go into a different, "Core" assembly?
Which leads on a bit to my next question (relates somewhat to the above), how do I launch my application from an MVVM point of view? Initially I would launch my MainView.xaml from App.xaml, and the DataContext in the XAML would attach the assigned ViewModel. If I add a WindowManager, is this the first thing that is launched by my Application? Do I do this from the code behind of App.xaml.cs?
Well it mainly depends on how your application looks like (i.e. how many windows opened at the same time, modal windows or not...etc).
A general recommendation I would give is to not try to do "pure" MVVM ; I often read things like "there should be ZERO code-behind"...etc., I disagree.
I'm currently separating out my project into a Model assembly/project,
ViewModel assembly/project and View assembly/project. Should this go
into a different, "Core" assembly?
Separating views and ViewModels into different assemblies is the best thing you can do to ensure you won't ever reference something related to the views in your viewModel. You'll be fine with this strong separation.
Separating Model from ViewModel using two different assemblies could be a good idea too, but it depends on what your model looks like. I personally like 3-tier architectures, so generally my model is the WCF client proxies and are indeed stored in their own assembly.
A "Core" assembly is always a good idea anyway (IMHO), but only to expose basic utility methods that can be used in all the layers of your application (such as basic extension methods....etc.).
Now for your questions about views (how to show them...etc), I would say do simple. Personally I like instantiating my ViewModels in the code-behind of my Views. I also often use events in my ViewModels so the associated view is notified it should open another view for example.
For example, the scenario you have a MainWindow that should shows a child window when the user click on a button:
// Main viewModel
public MainViewModel : ViewModelBase
{
...
// EventArgs<T> inherits from EventArgs and contains a EventArgsData property containing the T instance
public event EventHandler<EventArgs<MyPopupViewModel>> ConfirmationRequested;
...
// Called when ICommand is executed thanks to RelayCommands
public void DoSomething()
{
if (this.ConfirmationRequested != null)
{
var vm = new MyPopupViewModel
{
// Initializes property of "child" viewmodel depending
// on the current viewModel state
};
this.ConfirmationRequested(this, new EventArgs<MyPopupViewModel>(vm));
}
}
}
...
// Main View
public partial class MainWindow : Window
{
public public MainWindow()
{
this.InitializeComponent();
// Instantiates the viewModel here
this.ViewModel = new MainViewModel();
// Attaches event handlers
this.ViewModel.ConfirmationRequested += (sender, e) =>
{
// Shows the child Window here
// Pass the viewModel in the constructor of the Window
var myPopup = new PopupWindow(e.EventArgsData);
myPopup.Show();
};
}
public MainViewModel ViewModel { get; private set; }
}
// App.xaml, starts MainWindow by setting the StartupUri
<Application x:Class="XXX.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...
StartupUri="Views/MainWindow.xaml">

Implement interface with WPF MVVM pattern

I wanna implement an interface(Add behavior) for set of WPF usercontrols.
I'm using MVVM design pattern.
Where I should implement the interface? in usercontrol code behind or in View model class?
Ex:
My Interface is
interface IWizard
{
event RoutedEventHandler MoveNext;
event RoutedEventHandler MoveBack;
event RoutedEventHandler Cancelled;
bool IsLast;
bool IsFirst;
}
Now in other place I wanna access user controls which are implemented this interface as this.
((IWizard)userControl).MoveNext += ...
((IWizard)userControl).MoveBack += ...
((IWizard)userControl).IsLast = true;
etc..
Implement in UserControl Code behind
I can't acess the interface's properties/methods directly in view model. I have to link them manually. right ?
PS: In this example I wanna Bind(TwoWay Bind) IsLast Property with a visibility of a button.
Implement in View model class
I can't access the usercontrol as a Interface object.
ex: ((IWizard)userControl).MoveNext += ...
What is the best practice on Implementing an Interface on Usercontrol with MVVM design Pattern?
You should implement this interface in UserControl because it is directly related to UserControl, it has nothing to do with ViewModel. View Model is for business logic and interaction between View and Model. Events which occurs on UI/View should not be doing anything on ViewModel directly.
I know you won't be able to access properties directly in view model but that's what MVVM is for. Use the bindings and commands to bind properties and methods from Control to your ViewModel
In perfect-world MVVM, ViewModel has no knowledge whatsoever about View. Whether View implements any interface at all is irrelevant from ViewModel's point of view.
In your scenario, what I think is more important is who will respond to MoveNext, MoveBack and Canceled events. Most likely, that would be ViewModel. What that means you probably could use methods such as WizardMoved(object sender, EventArgs e) in those ViewModels. Look what we've done here - ViewModel needs to have kind of indirect knowledge about View. That is not a good sign.
Perhaps instead, you could approach problem differently. Maybe what you need is IWizardMovement interface that will define methods to handle wizard moving events - and this interface will be implemented by ViewModels. So that when you pass ViewModel to View, it can easily subscribe ViewModel's handlers to its own events (note that not it doesn't really matter what interface View implements).
public interface IWizardMovementViewModel
{
void WizardMovedNext(object sender, EventArgs e);
void WizardMovedBack(object sender, EventArgs e);
void WizardMoveCanceled(object sender, EventArgs e);
}
Now, since in MVVM View knows about ViewModel (and never the other way around), you can easily utilize this knowledge:
// Wizard user control constructor
public Wizard(IWizardMovementViewModel viewModel)
{
MoveNext += viewModel.WizardMovedNext;
MoveBack += viewModel.WizardMovedBack;
Canceled += viewModel.WizardMoveCanceled;
}
ViewModel is separated from View for good now, and how your View looks like is not important anymore (as it should never been in first place).
First of all, your view-model shouldn't have a field called "userControl".
When you design an MVVM application you should think in terms of layers. The Model layer should be usable by itself. The View-Model layer shoul be usable with the Models and Services. The View is what combines everything together.
But what about navigation?
Rather than giving your view-model direct access to the user control, you should only give it access to the abstract notion of navigation. In WPF that means NavigationWindow.NavigationService or Frame.NavigationService.
You can see an example of this in NavigationViewModel class in Granite.Xaml (http://granite.codeplex.com/SourceControl/changeset/view/85060#2109525). Since it takes an abstract interface (INavigator in my case, IWizard in yours) you can still test the view-model in isolation using simple mocking techniques.
Add a IsLast property to the ViewModel, make sure it raises NotifyPropertyChanged correctly.
Bind the Visibility of the Button to the IsLast property using a ValueConverter that converts a boolean into a Visability and back.
Done.

Right Way to access a View Model from an existing View Model

I am somewhat new to MVVM. I am not sure what the best way is to do what I am trying to do.
Here is the scenario:
I have a VM that is going to show another window. I can call myNewWindowView.Show(), but first I need to set some data in the VM of my new window.
Should I expose both the myNewWindowView and the NewWindowViewModel to the calling ViewModel?
Here is an example:
class MainVM
{
public void FindCustomer(string nameParial)
{
List<Customer> customers = ServiceCall.GetCustomers(nameParital);
// This is the part I am not sure how to do. I am not sure if this
// View Model should have a reference to a different view model and
// the view too.
myNewWindowViewModel.CustomerList = customers;
myNewWindowView.Show();
}
}
I would keep the viewmodel separate from any view. I tend to think of them as layers, but they are only interchangeable in one direction.
So a model of type foo can have any view model layered on top of it, and it never expects or cares about the viewmodel type.
A viewmodel can only be for one type of model, but it doesn't care or expect what type of view will use it.
A view will be for a particular type of viewmodel.
What you seem to have is a viewmodel the cares about what views are doing, which seems wrong to me.
If it were me, I'd get the view for the MainVM to display the new window, getting the MainVM to pass out the appropriate viewmodel for the new window.
This is the code I would put behind the view for the main viewmodel
class MainWindow : Window
{
public MainWindow()
{
Initialize();
DataContext = new MainVM();
}
public void FindCustomerClick(object sender, RoutedEventArgs args)
{
CustomerListView clv = new CustomerListView();
clv.DataContext = (DataContext as MainVM).FindCustomer(search.Text);
clv.Show();
}
}
As you can see, the viewmodel has a method that takes a string and returns a CustomerListViewModel, which is then applied to the DataContext of a CustomerListView.
Don't reference views inside your view model. Have views create views and view models create view models.
A simple way to accomplish this separation of concerns is with events. The quick and dirty way to do it is to create a ChildViewModel property on your parent view model, and then handle PropertyChanged in the view, e.g.:
ParentViewModel vm = (ParentViewModel)DataContext;
vm.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "ChildViewModel")
{
MyChildWindow w = new MyChildWindow();
w.Show(vm.ChildViewModel);
}
};
Now every time the parent view model changes the ChildViewModel property, the parent view will open a new child view.
A less quick, and less dirty, approach is to create a CreateViewEventHandler delegate and CreateViewEventArgs class, and make the event handler, and a protected OnCreateView method, part of your base view model class (assuming you have one). This allows the view model to be a lot more explicit about when a child window should be created.
Note that if it's important for the parent view model to know when the child view model has closed, the child view model can expose an event that the parent can subscribe to (or, again, use a property and the PropertyChanged event).
Note that in both cases, you can write unit tests that verify that the view model opens the window (i.e. raises the event) when it's supposed to without involving the views.
I haven't used any MVVM frameworks myself, but the ones I've looked at have messaging tools that are designed to facilitate this kind of thing.

In C#, how can I set DataContext on a View from the ViewModel?

I"m trying to wrap my head around MVVM. I understand a lot of it, but I'm having difficulty grasping one aspect: Setting DataContext.
I want to show an view with a particular object. The user doesn't get to decide what is visible, so I need to create the view in code. Then, I want to set the DataContext of the view to an object (for binding). I'm trying not to put code in the View for this, but View.LayoutRoot.DataContext isn't public.
What am I missing?
trying to avoid this:
public class View
{
public View(object dataContext)
{
InitializeComponent();
LayoutRoot.DataContext = dataContext;
}
}
with something like this:
public class ViewModel
{
...
public UIElement GetView()
{
UIElement *element = new View();
element.LayoutRoot.DataContext = element;
return element;
}
}
Don't forget that the View should know about the ViewModel, and not the other way around.
So in your case puting code in the ViewModel to create the view isn't the best way around.
Josh Smith's article on MVVM has a section on applying the View to the ViewModel. He recommends using WPF's DataTemplates to select your View in XAML.
If you use a XAML control or Window (which should be the case if you use MVVM), LayoutRoot (Grid by default) is public. In your example, you use just a plain class for View, so it is hard to tell what is going on.
Also, I second Cameron's opinion - nor View or ModelView should deal with assigning DataContext. It can be done in different ways (DataTemplate, dependency injection, special builder class, plain code) but normally it happens on the application level.

Categories