I'm using the MVVM pattern and I have a POCO (in my Model) with a Start Date property.
I want to show the elapsed time since the start date in a control on a WPF window/user control...
I don't see how I can bind a ModelView property to a UI control and have it update this duration automatically...can anyone suggest a way?
I could use something (a timer or a thread) to update a duration property on my ModelView but I just don't see any other way because as I understand it the UI will only update when a property value changes. However the start date on my POCO isn't changing it's just the elapsed time that's changing which is a calculated value.
Am I missing something?
You're on the right track. Have a look at the Presentation Model pattern on Martin Fowler's page.
The basic idea is to build a model for the UI (ViewModel) and have the UI just sync up with it. Every bit of information to be displayed in the UI, should have a corresponding field or property in the ViewModel (although they may be retrieved or derived from values in the Model) .. the ViewModel makes it easy to store the View State/Session State (such as the current selection of items in a UserList) which is not present the in the Model class behind.
Since you want to show the 'elapsed time since' value in the UI, your ViewModel should have a property caled ElapsedTimeSince. Your WPF View has a control which is data-bound to this property.
Now as per your need, ensure you have a thread/timer event that re-evaluates the property value periodically using the current time and the Model's StartDate property. Your UI should reflect the updated value.
Related
I'm developing a WPF/MVVM application and I have a listbox binding to data in a ViewModel. At various points I need the view model to cause the listbox to scroll to a given element.
How can I do this without creating a custom control and while still maintaining good separation of concerns?
I've currently got it working by creating a custom behavior class in the view layer with a dependency property VisibleIndex which the XAML code then binds to an integer in the view model:
<ListBox x:Name="myListBox"
local:ListBoxVisibilityBehavior.VisibleIndex="{Binding VisibleIndex}">
When the integer is set it triggers the dependency properties update handler which tells the listbox to scroll to the associated index.
This seems a bit hacky though because the dependency property value is never changed by the listbox and the update handler only gets called when the value changes, so the only way to ensure that the relevent item is visible is to do something like this:
// view-model code
this.VisibleIndex = -1;
this.VisibleIndex = 10;
The only reason I'm using a behaviour class at the moment is for binding my custom dependency property, is there a way to do something like this with events instead?
Attached properties are somewhat required in your case - as at some point, 'somewhere' you need to call the following method...
ListBox.ScrollIntoView(item)
or
ListBoxItem.BringIntoView();
And for that you need some sort of code behind - and attached properties/behaviors are a nice way of packaging that, w/o impacting your MVVM.
Having said that - if you just need to have your 'selected item' scrolled into view at all times (which is the case most of the time). Then you could use a different attached-property based solution (that again):
mvvm how to make a list view auto scroll to a new Item in a list view
All you have to do then is to set or bind to SelectedItem.
That's a bit 'nicer' if you wish - but the mechanism is the same.
For anyone else interested in the answer to this one of the MS engineers on the WPF forum cleared it up for me. Instead of binding to an event directly you bind to a wrapper object that encapsulates that event. The behaviour can then grab the reference to the wrapper from its DP and do whatever it wants with it i.e. subscribe to the event, trigger it etc.
I have the following configuration...
Single form with approximately 50-60 controls (it's a lot, I know) and a single view model which is responsible for storing the state of the form. The view model properties are bound to the editable controls on the form via a BindingSource.
My problem is this... I want to be able to clear the form with a button. To clear the form, I have tried the following:
Assigning the DataSource of the BindingSource to null and reassigning a new view model. This ends up lagging terribly.
Setting all of the properties to null/empty in the view model and then firing the OnPropertyChanged event (my view model base class is implementing INotifyPropertyChanged). This too lags terribly, and it would, given that I'm clearing 60 fields and then firing an OnPropertyChanged event for each one.
So, is there a way I can modify the application so that it is able to clear the view model and reflect the changes on the form in timely fashion? My form requires all 50-60 controls to be on the same form, but the controls could be divided up into four logical groups. Would it be beneficial for me to break up the view model into four presenters/view models that could handle the logical groups independently? Would this impact performance and the time it takes to reflect the changes in the form?
Thanks!
Is this senerio valid?
I have a View to maintain an Item.
I have View Model which exposes the Item Object (implements INotifyPropertyChanged) as a Property to which is View is bound.
Is it valid for me to pass the Item object to a Backgroundworker where it is modified, then raise the PropertyChanged event when the BackgroundWorking is complete?
Or should the BackgroundWorker in no way modify the Item object. I would update the existing Item object with the results passed back by the BackgroundWorker. This would be done in the RunWorkerCompleted event. But does this lock the UI thread and defeat the object of having a backgound worker?
Confused?
I'll try to explain.
The User takes an option to create an Item. I create the View and View Model. In the View model an empty Item object is created. He is presented with a View to maintain the Item. On selecting the Item Type property, this instigates a complex process to create a list of proerties to be entered by the User. I could block the UI thread whilst the list is created but this gives a poor user experience. I want to pass the processing to a background thread while keeping the UI alive. At present, I set a flag to indicate the section on the View is loading, pass the Item object to the BackgroundWorker which updates the observable collection of Properties. When the BackgroundWorking is complete I call the PropertyChanged event which updates the section of the View which is bound to the list and turn off the flag to indicate the section is loading. This seems to work with no issues. But I have a gut feeling that I should not be updating bound onjects from the View Model in a background thread.
Thanks Tim
This sounds ok. As long as your item-object is no DependencyObject, you can change the properties of them in the background worker.
DataBinding to properties of your object will work, the binding engine will do the thread-switching automatically for you.
However, dont't fill data-bound collections or manipulate properties of DependencyObjects (such as UI-Controls) in the background worker without dispatching the manipulations. This would lead to an exception.
Edit:
Only for clarification: The real question is not, if the item-object is a DependencyObject but if the property is a CLR-property or a DependencyProperty. Because DependencyProperties are bound to DependencyObjects, I often use the above simplification, but its not the full truth.
This means that if you have a CLR-property, you can set its value from a foreign thread, regardless of your class is a DepenendencyObject or not. This is a slight difference to my first statement.
I am new to MVVM, and I am trying to implement a simple application, following the pattern.
For simplicity, I am breaking the problem down to it's simplest form. If I manage to get this to work, I will have little trouble getting the application made.
The simple application consists of a tabcontrol. It is important that both tabs have their own ViewModel. However, they will get most of their data from the same source. The main issue is to get the second tab to know that the first have initiated a change on the datasource.
So, for simplicity, let's just say that the model is holding a single integer. This integer needs initially to be set to 1.
The first tab is holding a textblock and a button. The text of the textblock is bound to the integer in the datamodel. Upon pressing the button, the integer in the moddel should be incremented with 1.
The second tab holds only a textblock, also bound to the integer in the datamodel. The challenge is to get this textblock to update along with the first textblock, but still being it's own viewmodel.
I need somewhere central to store the values of the model, and in some way, let the viewmodels know that they have been updated, so their properties can be updated, and the Views therefore get's updated accordingly.
Can someone explain in as much detail as possible how this is done? I have tried a billion different ways, but I am not getting it to work.
Let me see if I have your question down right:
You have a data source (your model).
You have 2 view models.
View model 1 changes data in the model.
View model 2 needs to update with changes in the model.
If that all sounds right, here's one solution:
Have your model implement INotifyPropertyChanged. When the integer changes, raise the PropertyChanged event. In view model 2, listen for the model's PropertyChanged event. When it occurs, raise view model 2's property changed event, and its UI will get updated automatically.
I have no idea in which scenario you want to do that.
But a solution that crosses my mind is to have a "parent" ViewModel that holds instances of the two tab ViewModels.
e.g.
public class ParentViewModel{
private Tab1ViewModel viewModel1;
private Tab2ViewModel viewModel2;
}
Then the ParentViewModel can subscribe to the INotifyPropertyChanged event of the ViewModel1 and set the value on the ViewModel2.
I have recently implemented something similar to this. It was for implementing a wizard, consisting of:
7 Views
8 View models
1 Model
The main ViewModel created the Model and passed this on to all the other view models through their constructors.
In your scenario you could have a main ViewModel with an ObservableCollection of ViewModels. Each of these VM's would have the same instance of the model as their data source.
As previously mentioned, implement INotifyPropertyChanged on the model and bind the views directly to the model through a property on the ViewModel. I found this diagram very useful : http://karlshifflett.files.wordpress.com/2009/01/wpflobmvvm1.png
I am creating a custom DataGrid by deriving the traditional tookit based WPF DataGrid. I want a functionality in the grid to load items one by one asynchronously, wherein as soon as ItemsSource is changed i.e. a new collection is Set to the ItemsSource property or the bound collection is Changed dues to items that rae added, moved or removed (wherein the notifications comes to the data grid when the underlying source implements INotifyCollectionChanged such as ObservableCollection).
This is because even with virtualising stackpanel underneath the datagrid takes time to load (2-3 seconds delay) to load the data rows when it has several columns and some are template based. With above behavior that delay would "appear" to have reduced giving datagrid a feel that it has the data and is responsive enough to load it.
How can I achieve it?
Thx
Vinit.
Sounds like you are looking for data virtualization', which typically means creating your own custom type that resembles IList, and doing a lot of work to hydrate objects after-the-fact.
You will end up having your data that the grid is displaying look something like this:
Index 0: new MyDataObject(0);
Index 1: new MyDataObject(1);
And MyDataObject implements INotifyPropertyChanged.
In the constructor, you do the logic necessary to time, schedule, or interpret when the real results should be read. Until then, you return rather empty data... null and string.Empty from your properties.
Then, once the data becomes available (ideally in a background thread, read from wherever - your own local data, or a database or web service), then you can update the real underlying property values and fire the property change notifications so that the UI gets properly loaded then.
It's a little too complex to just jump into, so some searching will help. Hope this gets you started.