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).
Related
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.
I want to use MVVM pattern to develop a WPF application, the Model is an entityframework model. since entityframwork Implements INotifyPropertyChanged and raises PropertyChanged event in each property setter, do I have to raise this event in the viewmodel properties (wrappers of the model properties)?
You need to raise the PropertyChanged event for all properties you are binding to in your view (XAML) otherwise they won't know when they are supposed to update.
Therefore, if you are wrapping the model properties in the view model you will need to raise the event.
However, you can bind to the model properties directly:
<TextBox Text="{Binding Model.Property}" />
and as these properties implement INotifyChanged the UI will get notified and so will update. Therefore you don't need to wrap them at all.
Yes, you do.
UI components are bound to your properties, and your properties use EF entity objects. So you can catch changes in entity properties, but how the UI should now about the change? Answer: Your view model implements INotifyPropertyChanged and raises PropertyChanged event.
I used the List<Person> collection as the ItemsSource for the DataGrid control.
But it did not update the View if i remove the item from the List collection. I was struggling for a long time for the solution.
Then Instead of the List<Person> collection in my ViewModel. I changed this into ObservableCollection<Person> collection. Now it updates the view when ever there is a change in the collection.
I am not sure why it updates only for ObservableCollection<Person> ? Anyone ?
Well its in the name. A simple List doesn't tell the ui to update, in other words "the view can't observe the list". There is no weird magic behind Databinding. WPF and DataBinding needs the Data model to tell them "this is new" or "this is changed", you propably already saw INotifyPropertyChanged, INotifyCollectionChanged is the same but for collections, and the List<> doesn't implement it, ObservableCollection does.
Because List does not implement INotifyCollectionChanged
Because the update of a databinding is not a kind of magic, there are several requirements to make databinding working correctly. If you have a single property to bind on this property must be either a dependency property or its parent class must implement the INotifyPropertyChanged interface to notify the wpf binding system about changes of the property value.
For a collection there is a simelar mechanism: it must implement INotifyPropertyChanged to inform the wpf binding system about removed/moved/added items.
See here for more details: http://msdn.microsoft.com/en-us/library/system.collections.specialized.inotifycollectionchanged.aspx
ObservableCollection<T> fires change events every time you change the items in the collection. List<T> doesn't. That's the reason.
DataBinding is lazy. If you don't tell your view that something has changed, it won't bother updating. Under the hoods, WPF DataBinding registers for change notifications, so that your ViewModel can tell the view when it has changed. It does this with interfaces like INotifyPropertyChanged and INotifyCollectionChanged.
ObservableCollection<T> implements the interface INotifyCollectionChanged. This interface defines the event CollectionChanged, which your View basically attaches its own event handler to. That handler will update the view when the event is raised by the collection.
I have bound the WPF DataGrid to an observable collection of view models, where each view model represents each row in the DataGrid. The view model handles the BeginEdit and CellEditEnding events.
In one of the scenarios, I want to change the contents of the observable collection in the CellEditEnding event. But, I cant do this because the DataGrid is still in edit mode and if I try to add / remove items from the observable collection an exception is thrown and it causes my application to crash.
Any suggestions?
Dispatch it please.
In the CellEditEnding handler invoke your code with the Dispatcher.BeginInvoke() method.
Also you said
The view model handles the BeginEdit and CellEditEnding events.
If you are using pure MVVM then this is forbidden. MVVM implements events via Delegate/Relay Commands.
I have a View with a dataGrid. This datagrid bind a property in the ViewModel that is an ObservableCollection.
I edit some data in the dataGrid, and a field is updated by code, because it depends on some operations. Well, if I check the item in the observable collection, I can see that all the data is correct, but the info in the dataGrid is no refresh.
I want to force the refresh because I know that the observableCollection only raise the change property event when I add o remove items, but not if I edit one of them.
Because I am use Entity Framework 4.1, really the ItemsSource of the dataGrid is the local of the DbSet, so I don't know how to implement the notifyPorpertyChanged in the classes of the model edmx, and I am looking for an alternative, like to force refresh the dataGrid.
Because the property of the ViewModel that I use to bing the ItemsSource of the dataGrid is a reference to the local, I mean that to set the property I do myProperty = myContext.MyTable.Local and that raise the event PropertyChanged that I implement in my ViewModel, I try to do myProperty = myContext.MyTable.Local again to try to raise the event and force the refresh of the dataGrid, but it does not work.
What alternatives do I have?
Make sure that you have the Binding Mode set to TwoWay. Implement in the set portion of your property OnPropertyChanged and the rest should take care of itself.