WPF - Handling events from user control in View Model - wpf

I’m building a WPF application using MVVM pattern (both are new technologies for me). I use user controls for simple bits of reusable functionality that doesn’t contain business logic, and MVVM pattern to build application logic. Suppose a view contains my user control that fires events, and I want to add an event handler to that event. That event handler should be in the view model of the view, because it contains business logic. The question is – view and the view model are connected only by binding; how do I connect an event handler using binding? Is it even possible (I suspect not)? If not – how should I handle events from a control in the view model? Maybe I should use commands or INotifyPropertyChanged?

Generally speaking, it is a good MVVM-practice to avoid code in code behind, as would be the case if you use events in your user controls. So when possible, use INotifyPropertyChanged and ICommand.
With that said, depending on your project and how pragmatic you are, some times it makes more sense to use the control's code behind.
I have at a few occasions used something like this:
private void textBox1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
MyViewModel vm = this.DataContext as MyViewModel;
vm.MethodToExecute(...);
}
You could also consider Attached Command Behaviour, more info about this and implementations to find here:
Firing a double click event from a WPF ListView item using MVVM

Related

MVVM pattern - executing view operations

I'm using MVVM Pattern (with MVVM Light) to build my XAML app (win8). I have a ListView, which is bound to a property of my ViewModel. I also have a button that triggers an operation on that ViewModel, which updates that property (which results in updating the ListView). The button uses commanding to execute the operation on the ViewModel. So far so good.
The problem is that after the list is refreshed I need to perform an operation that strictly belongs to my View, not to the ViewModel. It should scroll the list to a specific item. How to trigger that operation? Should I use a specific ListView event?
Using an EventHandler and the ScrollIntoView(Object) method you can achieve what you want without using references of the View inside the ViewMovel and respecting MVVM pattern.
Create an event in your ViewModel like this:
public event EventHandler ScrollListView;
In your View add a callback to scroll the ListView when the property is updated:
ViewModel vm;
vm.ScrollListView += (sender, e) =>
{
var specificItem = **some item**;
MyListView.SelectedItem = specificItem;
MyListView.UpdateLayout();
MyListView.ScrollIntoView(MyListView.SelectedItem);
};
Then in your ViewModel when you update that property and want to scroll the ListView:
if (this.ScrollListView != null)
{
this.ScrollListView(this, EventArgs.Empty);
}
This is how I usually do with some tweaks for each case of course.
The ViewModel is there to decouple the UI Code from the UI Design (E.g. XAML). [Separation of Concerns of Designer and Developer, Automated testing of UI Code, etc]
Ideally the code-behind file of the View will be empty (except the call to InitializeComponent) and all UI logic and state will be handled by the ViewModel. However, in practice there might be some specific UI manipulation that cannot be handled by data-binding alone and you will need to resort to code. Such code should be placed in the code-behind.
In your case, the logic for (a) when and (b) which item to scroll to must be in the ViewModel (not in the View). Only any additional logic required to perform the actual scrolling in the ListView will be in the View code-behind.
Yes, an event would be the ideal way to do this, to avoid having any references to the View inside the ViewModel. I would recommend however to create a custom event in the ViewModel (e.g. OnFirstItemInViewChanged with arguments the item to scroll to) and in the View code-behind register to this event and just call ListView.ScrollIntoView(item).
Note:
WinForms DataGridView had a property FirstDisplayedScrollingRowIndex. If there was something similar in WPF ListView, you could solve this by binding this property to a ViewModel property, therefore leaving the code-behind completely clean.

WPF MVVM Problems with View

I want to use WPF with MVVM pattern in my project, but i am confused about some points regarding MVVM pattern. Please help me to clarify these points.
I am using DataTemplate for ViewModel, but i want specific control to be keyboard focused.
How can i focus specific control after ICommand Executed.
How can i move focus to not validated control.
Is there any way to separate DataTemplate depending on ViewModel property value.
How can i validate all controls before ICommand
Is there any other better approach to ask any confirmation from ViewModel with MessageBox
Regards,
Mitan
I highly suggest you have a look at caliburn (or caliburn.micro) which exposes different UImanager interfaces so your viewmodel can do such things without losing unit testability.
To set the foucs on control use codebehind. MVVM doesn't say don't not use codebehind.
Write a method on code behind to set the focus and call this method from view model.
Example
public interface IView
{
void setFoucs();
}
//Code Behind
public class MyWindow : Window, IView
{
public void SetFoucs()
{
MyControl.Focus();
}
}
public class ViewModel
{
public IView _view { get; set; }
public ViewModel(IView view)
{
_view = view;
}
public void SomeMethod()
{
_view.SetFocus();
}
}
For question no 4 - I think your are looking to selecte specific datatemplate based on your some logic. To achieve this use DataTemplateSelector class.
http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-a-datatemplateselector
Question 1:
Not clear what you mean/want. Generally the TabIndex controls the focus flow in your application, with silverlight it is however not as easy to configure as in windows forms. Silverlight also does a good job at setting the tab sequence automatically.
However, you should note that all controls inheriting from Control receive, by default, the focus. This incudes some controls that may be used as a container for other controls (e.g. ContentControl). This behaviour might lead to some unwanted effects. Use the IsTabStop property to remove these controls from the tab order.
Question 2:
Well, it depends on how decoupled you want your application (the more decoupled the better). #pchajer's approach is one way of doing it, however it couples the view to the view model and this - although abstracted via an interface - is IMHO not a good idea for the following reasons:
Usually the view model is pulled from a locator in order to allow for blendability. Now if I have to use code behind to pass the View to the ViewModel this might break it. Better would be if it could be injected into the ViewModel via a constructor parameter and this would then break the locator.
The code becomes less testable as it now depends on the view. To make it testable you need to inject an implementaion of IView into the ViewModel, and this breaks the locator again.
Therefore, I would advise you to use Messaging to send a message to your view once the Command is complete. Then you can set the focus in the message handler. However, be aware that your might have to use the Dispatcher as the message handler could run in a separate thread.
Question 3:
You could capture the BindingValidationError on the control and then set the focus. Again be aware of possible threading issues.
Question 4:
Not sure, but if you mean that you want to use different DataTemplates based on whether a property has a certain value or not a TemplateSelector might help you. See http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-a-datatemplateselector.
Question 5:
The controls are validated when the property change event is fired, usually on the lost focus event. Your Model/ViewModel can implement IDataError to do the validation, and your can access this value from the CanExecute method associated with your command. However, you should try to keep the code in the CanExecute method as quick as possible as this method is called quite frequently.
Question 6:
You can implement your own Window that provides a custom layout. However, using the message box is a lot simpler. Again you should think of using messaging or a dialog service (e.g. http://blog.roboblob.com/2010/01/19/modal-dialogs-with-mvvm-and-silverlight-4/) to decouple your View and ViewModel. In fact there is even a DialogMessage in MVVMLight.

WPF MVVM application - ICollectionView/Threading/General Questions

I have a few questions regarding to building WPF MVVM applications.
1) I'm using ICollectionView objects for databound controls such as ListView and ComboBox. I found this was the simplest way of gaining access to/tracking the selected item of these controls. What is the best way to replace the contents of ICollectionView? Currently I'm doing it like so:
private ICollectionView _files;
public ICollectionView Files {
get { return _files; }
}
void _service_GetFilesCompleted(IList<SomeFile> files) {
this.IsProcessing = false;
_files = CollectionViewSource.GetDefaultView(files);
_files.CurrentChanged += new EventHandler(FileSelectionChanged);
OnPropertyChanged("Files");
}
I didn't know whether it was necessary to reattach the handler every time I refresh the list of files?
2) Now that I've got my head round it, I am starting to like the MVVM pattern. However, one concept I'm not completely sure about is how to send notifications back down to the view. Currently I am doing this by binding to properties on my ViewModel. For example, in the above code I have an "IsProcessing" property that I use to determine whether to display a ProgressBar. Is this the recommended approach?
3) Following on from 2) - there doesn't seem to be a standard way to handle exceptions in an MVVM application. One thought I had was to have one method on my ViewModel base class that handled exceptions. I could then inject an IMessagingService that was responsible for relaying any error messages. A concrete implementation of this could use MessageBox.
4) I have a few tasks that I want to perform asynchronously. Rather than adding this logic directly in my service I created a decorator service that runs the underlying service methods on a new thread. It exposes a number of events that my ViewModel can then subscribe to. I have listed the code below. I understand that BackgroundWorker is a safer option but did not know whether it was suitable for running multiple asynchronous tasks at once?:
public void BeginGetFiles()
{
ThreadStart thread = () => {
var result = _serviceClient.GetUserFiles(username, password);
GetFilesCompleted(result.Files);
};
new Thread(thread).Start();
}
Finally, I realize that there are a number of MVVM frameworks projects that handle some of these requirements. However, I want to understand how to achieve the above using built-in functionality.
Thanks
If you have ListViews and ComboBoxes, you should really be considering an ObservableCollection<> to bind to these controls. Adding and removing items from the collection will automatically notify the control the property has changed.
If you're doing background processing, you can look at the BackgroundWorker or DispatcherTimer to handle updates to the UI. These both have the capability of acting on the UI thread, and can be thread safe.
To get the selected item from a combo box, expose an INotifyCollectionChanged object such as ObservableCollection and bind it to the itemsource, then create another property for the current item and binding ComboBox.SelectedItem (or ComboBox.SelectedValue if required) to it. You will need to manage the selection when updating the collection.
On the face of it, ICollectionView seems like the obvious choice but the WPF implementation really forces your hand on some threading code that you really shouldn't be troubled with.
I used ICollectionView and CollectionViewSource recently (for filtering) and have become frustrated with how many dispatcher issues have crept in. Today I am probably going to revert to the method i describe above.

Is EventToCommand passing EventArgs bad practice?

I've recently been using the MVVM light toolkit for Silverlight 4.
I really like the EventToCommand behaviour that is included, it makes life a lot easier. One thing I've been wondering about is if setting PassEventArgsToCommand="True" is bad practice as it will tie a particular RelayCommand to a particular event in the View.
E.g. If my RelayCommand is defined as:
public RelayCommand<System.Windows.Input.KeyEventArgs> myCommand
Then this can only be called by a KeyUp, KeyDown etc event.
I thought the ViewModel was to have no UI knowledge (e.g. expose a boolean converter and use a converter to change that to a Visibility), doesn't PassEventArgsToCommand break this?
The ViewModel is the model for the view so where you are referring to state that the view must have or data it should represent then the ViewModel should handle it.
It could be reasonable to use the Visibility enumeration to represent what part of the view should be viewed as that is about the state of the view.
As for the KeyEventArgs, this has come from an action from the user and represents some state of the command which if you need to know what key was pressed then it is a reasonable expectation of the ViewModel to handle.
If you introduce more abstractions and complexities to remove this event arg then you might have future maintenance issues provided you can unit test it with this command.
The only time I would not use Visibility or KeyEventArgs or the like would be if I wanted to use the same ViewModel for other UI technologies. If this is your case then I would create the abstraction (although in my experience this is rare and would typically involve their own ViewModels anyway).
It might not be a good idea to pass the KeyEventArgs directly to your ViewModel if you want to unit test the ViewModel - i.e. you want to invoke a command that takes KeyEventArgs as a parameter.
The reason for this is that you can't instantiate KeyEventArgs in Silverlight (at least not as far as I could see) because KeyEventArgs has no public constructor in Silverlight.
This means you can't pass a key from your unit test. In this situation it may be better to map the specific key(s) to the command in your view / XAML rather than just using an EventTrigger for the KeyDown event.
See this as one solution - this provides a KeyEventToCommand class that allows you to map the keys to commands directly in the XAML.
http://mvvmlight.codeplex.com/discussions/252898
One way to decouple the ViewModel from the View is to use a "broker" - something that mediates the communication between the two. I have used MVVMLight's Messenger class to implement a message broker with good results.
HTH, indyfromoz

How to further decouple this WPF example toward MVC, MVP, or MVVM?

I've decoupled events in this WPF application in the following way.
What is the best way to continue decoupling?
Shell.xaml:
<Button x:Name="btnProcess"
Content="Process"
Margin="10"/>
Bootstrapper.cs:
public void Run()
{
Shell shell = new Shell(new Customer());
shell.Show();
}
Shell.xaml.cs:
public Shell(IPerson person)
{
InitializeComponent();
btnProcess.Click +=new RoutedEventHandler(person.Process);
}
Customer.cs:
public class Customer : IPerson
{
public void Process(object sender, RoutedEventArgs e)
{
Button theButton = (Button)sender;
theButton.Content = "Customer processed.";
}
}
The above code successfully decouples the view Shell from the model Customer:IPerson so that I can swap in e.g. a model Employee:IPerson etc. which handles "Processed" in its own way. That was the first goal.
But now:
how do I decouple the Processed method from talking specifically to a Button, so that it could also talk to a MenuItem or a ListView which fires the event in the view and so that it doesn't even have to be an element at all that calls it, e.g. a unit test class?
how do I alter other elements of the view other than the sender (Button), e.g. how would I alter the status bar in Shell? I see two ways:
I could either build a container which holds all views and inject the container in the Customer upon creation, then the customer can look in the container and manipulate the calling view anyway it wants (although I would have to somehow match the view that sent the event and the view in the container as the same one)
I could somehow send the whole view (Window object) to the Model with the eventargs when firing the event, although the Model would need some way of knowing (via interface) what kinds of regions were available to manipulate at runtime
How would you continue this application in the direction of a more decoupled design?
What pattern is this actually, e.g. MVC, MVP, MVVM? I only see a view (Shell) and a Model (Customer).
How would a Presenter fit in?
How would a ViewModel fit in?
How would a Controller fit in?
I suggest you to implement your event handling using commands instead of classic events.
Its very easy in WPF because the command pattern is already implemented, and you can tell all of your UI inputs (button, menu item...) that their command is [name of your command] and handle all of them in one place.
Cameron MacFarland did a good job here, but I can add a little.
When following M-V-VM, the tools in your box for decoupling are data binding, commands, attached behaviors and interfaces. Data binding should be self evident. You've already gotten a good description of commands, but I'd suggest you avoid RoutedCommand and stick with an ICommand implementation. Attached behaviors are attached DependencyProperty's that subscribe to events on the element they are attached to, and in this scenario would be used to relay event handling to the ViewModel. Interfaces give you the greatest flexibility, but you have to work out how to pass the interface to the ViewModel. The best way to learn all of this right now is to Google and to look at existing M-V-VM frameworks. Here's a list of frameworks:
Prism/Composite WPF (http://www.codeplex.com/CompositeWPF). This one comes from the Microsoft Patterns & Practices group. Lots of good stuff here, but one of the examples of the three things above that you can learn from here is how to use ICommand. Prism includes a DelegateCommand that implements ICommand and simplifies using commands from a ViewModel in M-V-VM.
Caliburn (http://www.codeplex.com/caliburn). Recently released, one of the key things you can learn from this one is how to use attached behaviors, which this library uses for it's "Actions".
Onyx (http://www.codeplex.com/wpfonyx). Disclaimer: I'm the author of this one. This one hasn't been released yet, though the current alpha source is available. This one provides a novel solution to the problem of how to provide interfaces to your ViewModel.
As Chen suggests, i'd look into the Command pattern: Routed commands
A working example from which i learned a lot can be found on Jaime Rodriquez his blog: Southridge
how do I decouple the Processed method from talking specifically to a Button
Commands. Put a command in the IPerson interface and call that command from the Shell's xaml.
how do I alter other elements of the view
Properties and Binding. If you have a property showing the state (processed/not processed) then you can use binding to display that property directly in the xaml.
How would you continue
I'd head more down the MVVM path by creating a ViewModel between the Shell and the IPerson. The ViewModel is designed to have 1) The properties needed for bindings, and 2) any Commands that need executing. The ViewModel is designed to provide the UI with what it needs from the Model.
What pattern is this
Currently? Nothing. I see only two objects, the View and the Model. You don't have a Presenter, Controller or ViewModel.
For WPF I prefer ViewModel. See this question for more info on MVVM.

Resources