How can my design implement MVVM? - wpf

I have an issue trying to understand how to implement the MVVM pattern in my application. It's a small application and I will explain what it does.
My application creates a backup of files. The UI lets the user choose which folder they want to back up and where it should be backed up too. After making their selection they click the "start" button.
This then passes the folder source and folder destination to a class library (called backup.cs) which creates the back ups of all the files inside each folder. During this, a log (Log.cs) is created logging each stage and the state of each file it attempted to back up (complete, failed, other, etc). Now, the log is in memory only.
When the back up is complete I want a window to open (a view) which will display all the logs. It's at this point I can't understand how to use the MVVM pattern.
As it stands today, I pass my log (which holds the data in a hierarchical way) to my MainWindow's constructor and bind to the datacontext, using a treeview in my xaml I get the desired results. However, I now want to use MVVM.
My question is very similar to my previous question, as you can see the answer is to pass the log as a paramter to the ViewModel constructor. The issue is, I don't know how to do that and also display a window!
The only way (in my head) I can achieve this is by passing the Log as a parameter to a constructor of my View but this defeats the point of the MVVM. I could pass the parameter to my ViewModel's constructor (which would fit the MVVM pattern) but would that then mean I have to also create an instance of my View from my ViewModel constructor as well? Otherwise all I would do is create my ViewModel but have no way to display the results since the View isn't displayed.
I hope I have explained where I'm struggling clearly, can any one suggest a way forward please?

Most likely you 'll want the viewmodel to accept (and expose through a property) a collection such as a List<Log> -- typically this would be an ObservableCollection<Log>, but if the operation has already completed there is no real point in going that way. This is what you are describing as a possible solution.
To wire the viewmodel to the view, in essence you need to do this:
var viewModel = new LogsViewModel(...);
var view = new LogsView(); // no constructor parameters
view.DataContext = viewModel;
And finally you add view at some place of the application window's logical tree so that it gets displayed. MVVM frameworks automate this procedure, but you can also do it manually as simply as this.
Your view would then bind to the logs collection to display each log, perhaps using a DataTemplate:
<ItemsControl ItemsSource="{Binding Logs}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- XAML to display each Log does here -->
<TextBlock Text="{Binding FileName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

As an example, if you wanted that LogView being shown based on a button click in you main View.
public override void ShowCommandExecute()
{
var popup = new LogsView
{
WindowStartupLocation = WindowStartupLocation.CenterScreen,
DataContext = new LogsViewViewModel();
};
popup.ShowDialog();
}

Related

WPF/MVVM - binding collection of child controls

some advice from he WPF/MVVM gurus, pls.
I come from a Windows Forms background and I am porting a personal project from VB.NET to WPF. I started with a straight re-write with the logic going in the code-behind files, albeit with a discrete Data Access Layer.However then I discovered MVVM and that I was 'doing it all wrong' and should be abstracting the logic into a View Model accessing a data model. I think I've absorbed the new paradigm and my code behind files are now (nearly) empty.
(As an aside, I buy into the rationale behind MVVM, but I'm not sure about the 'easier to test and debug' argument, due to all the 'plumbing' of routed events and commands etc, I appreciate the need but it seems to me sometimes to obscure rather than clarify what is going on. But I a very much a novice, maybe it will come with practice.)
Anyhow - here's what has got me scratching my head; the app is a dive planning/recording tool for scuba diving centres. Logically, its like a calendar or diary app, with the need to record the time and site of each dive and who went on each dive. The main screen resembles one page of a diary and I have a user control that encapsulates the dive info. On change of selected date, the diary page is cleared and re-populated with the dives for the new selected date. The View Model retrieves and exposes a list of 'Dive' objects (classes) for the new date. The container is a Stackpanel and I want to clear its children and then create and add the new Dive user controls to the child controls collection.
My question is - where is the appropriate place to do this - View code behind or View Model? The former is relatively easy but seems to me to break the pattern, but I am stumped by how I would achieve it in the view model. The sequence needs to be
User selects a new date (calendar control)
Handle the selected date change event
Clear Stackpanel child controls
Retrieve list of dives for new date from db and generate a user control for each
Add user controls as stackpanel child controls.
I guess what I'm asking is - is there a way of binding the collection of child controls to a collection of objects in the view model such that it responds dynamically - and is this a sensible approach?
The appropriate way to do this would be to wrap your StackPanel in an ItemsControl and bind the ItemsSource to your Dives of the selected day. When your DivesOfThatDay is changed (make sure to implement INotifyChanged or a DependencyProperty, or use an ObservableCollection), every single entry will be generated automatically.
<ItemsControl ItemsSource="{Binding DivesOfThatDay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type Dive}">
<!-- Your Template -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In MVVM you should always avoid generating Controls in Code-Behind. Your View should take the Data from your ViewModel and do that on its own - otherwise MVVM would be kind of useless. In your case it should work like this:
User selects a new date in the view
Because the date control in the view is bound to some property in your viewmodel, that property gets updated.
The viewmodel reacts to this change by clearing its current collection of dives and fetching a new one.
The model data (from the database) gets encapsulated in a viewmodel (a Dive) and added to the dive collection in the viewmodel
The view (ItemsControl) gets notified of this change (via INotifyPropertyChanged, INotifyCollectionChanged or whatever) and tells its ItemContainerGenerator to update the controls.
The ItemsContainerGenerator generates a view for every Dive in your viewmodel and adds it to the stackpanel.
Or in short V → VM → M → VM → V

WPF Mutate Command Pattern

Should I mutate the parameter passed to the Execute method on ICommand? If not, what is the best way to change the State of the application, or View Model, after a command is invoked?
Thoughts
The Command Pattern invokes a method on an object, in the case of WPF it's the model or view model. This requires the model to know how to perform the action on itself. We've all seen and used the RelayCommand implementation. The problem I have with this is that it's difficult to swap out behaviors. It's also difficult to find a place to put that "special case" code. What if I want to show another view?
I like the idea of creating a Command for each Use Case. I would have a concrete class that implements ICommand that handles the logic for executing the use case. This requires a reference to the model just like the Command Pattern. The difference is that the action logic would be outside of the model and thus be mutating the model passed in as a parameter. Let's look at some sample code.
I have a window that shows a list of the ubiquitous Person object. We want to invoke a command on a Person that clears their name. MainViewModel has a collection of Person objects called People.
<Window.Resources>
<commands:ClearNameCommand x:Key="ClearNameCommand"/>
</Window.Resources>
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
Here is my list box that is bound to the collection and displays each person with a button to clear their name.
<ListBox ItemsSource="{Binding People}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name" Width="100"/>
<TextBox Text="{Binding Name}" Width="100"/>
<Button Command="{StaticResource ClearNameCommand}" CommandParameter="{Binding}" Content="Clear"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Below is the Execute method on the concrete class ClearNameCommand. It displays a dialog box asking if they want to perform the action. I think this proves as a good example of why you wouldn't put this command in the model. Also imagine that you had to log somewhere that the name was cleared? Undo Redo maybe?? Where does all this code go??!!
public void Execute(object parameter)
{
Person p = parameter as Person;
if (p != null)
{
if (MessageBox.Show(
"Are you sure you want to clear the name?",
"Clear Name",
MessageBoxButton.YesNo,
MessageBoxImage.Question) == MessageBoxResult.Yes)
{
p.Name = "";
}
}
}
I suppose you could leave all of the preparation code in the command and then call a Clear method on the Person. However, I'm still not convinced that is the best way. What if clear changes? You end up with Clear2 and Clear3 and so on. Not to mention a method for every possible use case or maybe even more.
Some More Thoughts
So let's say I have a View Model with a reference to a Model that allows pass-through Data Binding or it wraps the Model all together. What I want to get away from is creating a Command property on the View Model for every single use case. Also, what is so clean about that design? You're still mutating the Model object in the Execute method. I don't think I'm bending the Command Pattern all that much. My Window is the Client. The Model is the Receiver. And the Button is the Invoker. The only difference is you're injecting the dependency with the invoker.
To rephrase my question slightly, does anyone see any red flags for doing this?
I found this while researching the command pattern.
http://msdn.microsoft.com/en-us/library/cc984279.aspx
I really have no idea what you're talking about... you seem to have a very... er, unique way of working with Commands.
This requires the model to know how to perform the action on itself.
A model class should never have Commands in it... instead, put them in whichever view model that displays that model class.
... it's difficult to swap out behaviors
Again... what? Don't 'swap out behaviours'. A Command shouldn't change its functionality. Just create one for each function.
It's also difficult to find a place to put that "special case" code
What is "special case" code?
What if I want to show another view?
Each view should have its own view model. Each view model should have its own set of ICommand objects. It's really not a problem if you have to duplicate a little Lambda expression in a RelayCommand.
imagine that you had to log somewhere that the name was cleared? Undo Redo maybe?? Where does all this code go??!!
View model, view model, view model.
I suppose you could leave all of the preparation code in the command and then call a Clear method on the Person
What do you think the difference would be between calling p.Name = "" and calling p.ClearName() which did the same thing? No difference, or at most, it would take fractionally longer calling the method than setting the property directly.
What if clear changes? You end up with Clear2 and Clear3 and so on
Once again... what??? How would Name = "" change?
While I hope I answered some of your questions, I think that I must have misunderstood you in some way because I don't fully understand your question. Please feel free to ask further questions, but please add them as an edit to your question and I will reply in this answer, so that the comments don't get ridiculously long.
UPDATE >>>
In response to the first two comments:
Yes... in almost all cases, I would have one view for one view model. And no, I have absolutely no problem with changing the value of anything from a Command. I can't think of any reason why you would think that that is not OK. Imagine this scenario:
You have a list of objects and an edit panel in the UI that the user can use to edit the objects. You also have a Button with a Command that is named Duplicate. Now, by definition, that Command is going to 'mutate' as you call it, a data object, or model class.
It would create a new object and set its properties dependant on the values of the currently selected object. Are you suggesting that this Command is somehow wrong for doing this? In my opinion, that vast majority of Command (or method) functionality will 'mutate' some property or properties of the data objects in the view... how else do we provide this useful functionality?
And to continue with the 'where should this be?' question... where else can it be? In the view model, we have access to the currently selected item and the whole collection of items. From the view model, we can have access to any number of services that provide all kinds of functionality for us. You'd find it hard to connect with some of these things from your separate Command classes.

Accessing variables from XAML and object from ViewModel using Code Behind

I'm a newbie in windows phone development. I would like to ask if it is possible to do this scenario. I need to access a variable in XAML using my code behind, then I will add it as an item to my existing list found in my View Model. Therefore, I need to access both of my View Model to get the list and the XAML to get the variable from the resources.
Is this doable? If yes, how can I access it. This is what I have in my current XAML.
<phone:PhoneApplicationPage.Resources>
<system:String x:Key="scanName">SCAN</system:String>
</phone:PhoneApplicationPage.Resources>
Thanks much,
What you're trying to do is a pretty big violation of everything MVVM is about, but it is possible...
With the following lines in the codebehind of your view, you can...
...access the resource string:
var scanName = this.Resources["scanName"];
...access the ViewModel:
var vm = DataContext as MyViewModel;
if (vm == null) return;
vm.ScanHistory.Add(scanName);
That being said, you really shouldn't do this. The idea of MVVM is to decouple ViewModel and View completely and let the WPF binding mechanisms wire it together for you. In your case, as far as I can tell, you should store the scan name somewhere else, either as a resource or a config value, fetch it in your ViewModel and provide a property on your ViewModel to which your View can bind.
I haven't near winphone app so i make simple example on wpf(it's similiar with winphone).
//write string value from dynamic resource into textblock
<TextBlock FontSize="14" Text="{DynamicResource scanName}"/>
//changing resource in codebehind (this is Window in my example)
this.Resources["scanName"] = "new value";
As my mind you scenario is veru specific.Try to read about bindings. May be bindings will be more useful in your scenario.

WPF databinding in child control

I am new to WPF. I'm trying to build an application which has a function (call it Initialisation) where a user has to fill in a lot of data and some parts of the form are repeated. We're rewriting a legacy app that has quite a long wizard in although we will probably use collapsible panels in one window rather than next/previous pages. Also some parts are repeated e.g. the user can specify a number of items, if they say 3 they will need to fill in some configuration info for each, so those controls would need to be repeated three times.
I'm using MVVM and am using this example here: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
The old wizard had about 4 pages so I'm intending to have one user control (Initialisation) that contains 4 child user controls to break the xaml up a bit.
So far I have the Initialisation (its ViewModel inherits from Workspace ViewModel as in the above example) and it contains one child which is working:
<Expander ExpandDirection="Down" Header="ChildOne">
<view:ChildOne />
</Expander>
I will have separate ViewModels for each child and for Intialisation and this brings me to my problem.
The problem I am having is that ChildOne contains a dropdown which I am trying to bind like so:
<ComboBox x:Name="textMessageTypeCmb" ItemsSource="{Binding Path=TextMessageSelectionOptions, Mode=OneTime}"/>
TextMessageSelectionOptions is a public property in ChildOne's ViewModel. This results in no errors but an empty dropdown - that property getter is never called. If I move that property getter code into the Initialisation's ViewModel instead it works but I'm trying to keep my code in manageable chunks so I'd like to put hat code back in ChildOne's ViewModel. It also works if in my MainWindow I create ChildOne as a workspace instead of Initialisation like this
ChildOneViewModel ws = this.Workspaces.FirstOrDefault(vm => vm is ChildOneViewModel) as ChildOneViewModel;
Can anyone advise whether I am taking the right approach (by dividing it up into several user controls) and what I need to do in the binding to make this work? I don't really understand any of this yet especially binding.
It seems to me that your ChildOne view's DataContext is still this Initialisation vm.
You can bind it the views Datacontext to a ChildOneViewModel object
...
<view:ChildOne DataContext={Binding PropertyReturnsChildOneViewModellObject/>
...
or specify the path for the combobox ItemsSource prop.
<ComboBox x:Name="textMessageTypeCmb" ItemsSource="{Binding Path=PropertyReturnsChildOneViewModellObject.TextMessageSelectionOptions, Mode=OneTime}"/>
Note: PropertyReturnsChildOneViewModellObject is a property of the Initialisation vm.

Why the view constructor is not called every time I create a new viewmodel?

I am using WPF with model-view-viewmodel pattern. I have a ResultsView and ResultsViewModel which are connected like this:
<DataTemplate DataType="{x:Type VM:ResultsViewModel}">
<VW:ResultsView/>
</DataTemplate>
In my main window I have some kind of paged setup where MainContent property stores the current page (ViewModel instance).
I create the page like this
MainContent = new ResultsViewModel();
ResultsView is based on UserControl, it also has a handler for Loaded event which does some UI initialization stuff.
Everything works fine while the user is navigating between different pages.
But if the user opens the ResultsView two times in a row, the ResultsView constructor is not called the second time, and also Loaded event is not called. It seems that now I have the same old ResultsView instance attached to the new ResultsViewModel()!
Why WPF does not create a new View each time I create a new ViewModel? Is there some way I can force WPF to discard the old view if the old viewmodel is destroyed?
<DataTemplate x:Shared="False" DataType="{x:Type VM:ResultsViewModel}">
<VW:ResultsView/>
</DataTemplate>
See Kent's answer for practical work-around for your issue.
That said, it's a good practice to only instantiate the View once, as there is overhead associated with constructing the Visual Tree and setting up all of the bindings. Generally the View/ViewModel should be designed so that you can swap out the underlying ViewModel without the View caring or even noticing (other than DataContext changing and therefore all binding values being re-evaluated.) If you currently have logic in your Loaded event that prepares for a specific ViewModel, consider registering for notification of when DataContext changes instead (see this example).

Resources