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.
Related
I have a class which monitors a log file. It will fire an event when a new line is added.
What is the proper way, to update multiple controls in WPF?
Keep in mind that I am new to WPF bindings.
You should learn about bindings and MVVM. In MVVM you can have your viewmodel class implement INotifyPropertyChanged allowing the view to be automatically updated when a binding property in viewmodel class is updated. In your case your viewmodel can subscribe to the fired event and update a property which in turn will update the view (controls).
I'm kinda new to WPF. I'm making an app using WPF (all the UI controls are already fixed) and MVVM but most of the events are in the code-behind. I'm in the process of clearing the code-behind but I have codes like (the ones below) to switch through tabs, and to trigger visibility of controls depending on parameters:
tabItem1.Selected = true;
textBox1.Visibility = Visibility.Hidden;
lbxHusbandsWives.Items.Add(txtHusbandsWives.Text + '/' +
cbxHusbandsWivesCountry.Text + '/' +
dpHusbandsWives.SelectedDate.Value.ToShortDateString());
How can I do that in the viewmodel? Well, inside a Command? So I can clear the messy code-behind? Thanks for your help. :)
As I said many times before, MVVM doesn't mean "no code behind". There are things that you can or should do in code-behind, as long as they are strictly related to the view and are not necessary for the ViewModel to work properly.
That being said, in most cases you don't need to do anything in code-behind. You normally use bindings to control the view from the ViewModel. This allows the ViewModel to be completely ignorant of the view: it just exposes properties that the view can access, and sends notifications when the values of the properties change. The ViewModel should definitely not manipulate the view or its components.
Everything in the code you posted can be done with bindings in XAML:
textBox1.Visibility can be bound to a bool property of the ViewModel, using a BooleanToVisibilityConverter
lbxHusbandsWives.ItemsSource can be bound to an ObservableCollection in the ViewModel (an ObservableCollection notifies the view when items are added to or removed from it)
txtHusbandsWives.Text, cbxHusbandsWivesCountry.Text and dpHusbandsWives.SelectedDate can also be bound to properties of the appropriate type
I have a command that I would like to be enabled only when a certain control has focus. I can do this with a routed command and command binding, but I'd like to keep the implementation in my ViewModel.
Is a command binding and an event handler in the code behind the only way?
To handle this within the ViewModel, you will need to add the concept of the 'certain control' having focus into your view model, enabling the command when this focus state changes.You could do this by adding a boolean IsCertainControlFocussed property to your view model.
To update this state you have two options, either handle the GotFocus and LostFocus events in the code behind of you view and set this boolean property on your view model. Or use one of the MVVM framework absraction mechanisms. For example the MVVM Light framework has an EventToCommand behaviour which allows you to wire an event to a command exposed by your view model, which could set this property.
http://geekswithblogs.net/lbugnion/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx
Which technique you use depends on how important it is to you to have no code-behind. Personally I do not follow this religiously, as long as the View Model has the right responsibilities, and is testable, a little it of code behind does no harm!
Calling OnPropertyChanged for an ObservableCollection only works when there has been some change to the properties of the collection, not the objects it contains (add, remove, clear, etc).
Is there any way to notify the View that there has been a change to an item within the collection?
The objects it contains have to implement INotifyPropertyChanged as well. In your setter you trigger the event, and WPF will pick up on this and read in the new value as long as you are using two-way bindings or read-only bindings.
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