MVVM selecting a treeview item programmatically - wpf

It seems that others have had variations on this question, but from what I can tell it hasnt been addressed for folks using collections in a single view model.
I have a VM that contains an ObservableCollection of objects, not a VM for each object. Therefore I dont think I can use the SelectedItem bool that is often discussed because I dont think I can bind to the property on the collection's objects...just the properties on the VM.
So I've got the whole thing pretty well written with no code-behind and minimal coupling, but when a new item is added to the collection, which is bound to the treeView, I need to select that item.
Ideas?
Thanks!

When thinking about this. You should really build a wrapper for every element of the tree view that has the IsSelected bool on it as well as the IsExpanded bool they make life so much easier for displaying the data. You could even just add them to your class and use them from there.

Josh Smith has an article on CodeProject where he suggests creating a ViewModel object to represent each node of the TreeView, and then autowires them up as needed.
http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx

Related

MVVM concept for collections and parent/child relationships

In the model of my application I have a list of "parents" each referecing a list of "children" (e.g. a list of footballteams each containing a list of players).
I visualize this list in a tree view. I created a viewmodel-class for the tree and a viewmodel-class for a footballteam (let's call it "footballteamViewModel"). The class for the tree holds an ObservableCollection with footballteamViewModel-items. The items-source for the tree is this ObservableCollection. During initialization, I create for every footballteam in the model a corresponding footballteamViewModel object and add it to the ObservableCollection.
The thing is, that the list of footballteams in my model can be changed from outside of the tree and I want the tree to be updated. So if someone removes a footballteam from my list in the model, I would have to remove the corresponding item in my ObservableCollection of footballteamViewModel-items.
I cannot bind the list of footballteams from the model directly to the view. So I have to update my ObservableCollection in the ViewModel somehow, every time the collection in the model is changed.
My way to handle this is to use an ObservableCollection in the model and register to the collectionChanged-event in the ViewModel, so that I update my ViewModel (the Observable Collection of footballteamViewModel objects) whenever the model-collection is changed. But this does not feel "right". Is there a better way?
While typing this I found another post which describes exactly the same problem: WPF/MVVM: Delegating a domain Model collection to a ViewModel. The answers there encourage me that the way I'm solving this problem is not totally wrong but still I wonder if there is another method.
EDIT: From the first answers that you provided I assume that there is no definite answer to my question. They were all helpful, so it's worth reading them all. I only mark the answer with the reference to the Bindable Linq/Continous Linq/Optics frameworks, because I think it will help other who stumble over my question most.
This is one of the more nasty spots of MVVM.
One thing I have done a while ago is create a ViewModelCollection<T> which inherits ObservableCollection<T> and has modificator methods (Add, Remove), that perform operations on both collections,like so:
public interface IViewModel<T>
{
T WrappedModel { get; }
}
public class ViewModelCollection<T,M> : ObservableCollection<T,M> where T : IViewModel<M>
{
private IList<M> _baseCollection;
public ViewModelCollection(IList<T> baseCollection)
{
_baseCollection = baseCollection;
}
public override void Add(T objectToAdd)
{
IViewModel<M> vm = objectToAdd as IViewModel<M>;
if (vm != null)
{
this.Add(objectToAdd);
_baseCollection.Add(vm.WrappedModel);
}
}
public override void Remove(T objectToRemove)
{
IViewModel<M> vm = objectToRemoveas IViewModel<M>;
if (vm != null)
{
this.Remove(objectToRemove);
_baseCollection.Remove(vm.WrappedModel);
}
}
}
By now I don't do this at all, I just work with Castle Proxies that add the INotifyPropertyChanged functionality to my models - saves a lot of boilerplate code!
Please note, I haven't tested the code, just typed it down from memory.
You said that you cannot bind the model collection directly to the view (which means that the viewmodel needs to make its own ObservableCollection with a copy of what the model collection contains), and additionally that the view needs to be updated live when the model collection changes (which means that the model needs to inform the viewmodel of such changes, and the viewmodel needs to update its internal copy).
All of this doesn't leave much wiggle room really. One variation that might be interesting is making the model's collection a read/write IEnumerable, in which case consumers of the model would be forced to swap it with a new instance whenever they need to modify the collection. In return, the viewmodel's "stay in sync" code can be simplified and sync can be triggered through INotifyPropertyChanged on the collection property.
Your solution is not wrong at all, but there are some libraries that could help you implement it easier, like BindableLinq, ContinuousLinq or Obtics. You have a discusion about them here. Sadly, none of them seem to be under further development.
My personal experience with Clinq is excellent and i still use it, should work for your case.
Late, but may helps other ppl...
read this excellent 3 Part blog post series about this topic.
Part 3 is about collections and shows some solutions - helps me a lot
MVVM: To Wrap or Not to Wrap? How much should the ViewModel wrap the Model?

Dynamically specify and change a Silverlight DataGrid's columns during runtime (MVVM)

What's the best method of dynamically specifying DataGrid columns in the Silverlight DataGrid control at runtime following the MVVM pattern?
What I'd like to do would be bind the "DataGrid.Columns" property to a property in my ViewModel so that, if the user adds/removes columns, I simply update the ViewModel property and the DataGrid would change. Problem is, the "DataGrid.Columns" property can't be bound to (I don't think).
Because this property isn't available nor is the DataGrid control itself available at the ViewModel level, my current approach is to step outside of the MVVM pattern for this particular implementation and capture certain events in View's code-behind using MVVM Light's Messenger class and then talk directly with the DataGrid control to achieve this capability. I know this is a general statement to this approach without details but is there an easier way... or maybe not so much easier, but a better way that adheres to the MVVM pattern a little better?
It's driving me crazy that the DataGrid control's Columns property can't be bound... seems like such a simple thing.
FYI - Before it's suggested to use AutoGenerateColumns = True, the class being bound for each item in the collection that's bound to DataGrid.ItemsSource does not have individual properties to identify what is bound to the columns... it's a collection property that contains the columns in order to keep them completely dynamic so that particular path is out. Also, handling the AutoGeneratingColumns and using e.Cancel to show/hide columns is also iffy for this same reason (I think).
I agree that it is a pain that DataGrid.Columns cannot be bound to. My recommendation here would be to define your columns in the ViewModel in an ObservableCollection. In the View (code behind), handle the CollectionChanged event of this ObservableCollection, and modify the DataGrid.Columns in code.
While this solution is less elegant, it is straightforward. For your ViewModel, you can unit test that the CollectionChanged event is raised properly when columns are added, removed or moved. The View code cannot be tested, so I guess this is something you need to live with. The advantage is that, if some day the DataGrid.Columns property can be databound, it will be easy to refactor this to remove the code behind.
Another way (I think) would be to create an attached behavior or a Blend behavior to take care of this. Attach it to the DataGrid; instead of binding to the DataGrid.Columns directly, bind to a property on the behavior, and have the behavior modify the DataGrid (the AssociatedObect) directly.
Does that make sense?
Cheers,
Laurent

WPF Collections and Databinding

I am new to WPF and trying to wrap my head around WPF's framework, what it does and does not do for you.
To clarify this, I would like to know what is the difference between this:
public List<MyCustomObject> MyCustomObjects
{
get { return (List<MyCustomObject>)GetValue(MyCustomObjectsProperty); }
set { SetValue(MyCustomObjectsProperty, value); }
}
public static readonly DependencyProperty MyCustomObjectsProperty =
DependencyProperty.Register("MyCustomObjects", typeof(List<MyCustomObject>),
typeof(Main), new UIPropertyMetadata(new List<MyCustomObject>()));
and this:
public ObservableCollection<MyCustomObject> MyCustomObjects { get; set; }
public Main ()
{
MyCustomObjects = new ObservableCollection<<MyCustomObject>();
}
Ok, we must put some order into things, there's a few concepts mixed in together here.
First of all, you're asking what the difference is between a field-backed property and a dependency property. Google would be your best friend, however I recommend this blog post by WPF's vanguard Josh Smith: Overview of dependency properties in WPF
In short: dependency properties support the richness that is WPF: Styling, animation, binding, metadata, and more.
Secondly, you're asking what the difference is between a List and an ObservableCollection. Well the latter provides change notifications (in the forms of events) on any change to the collection (addition, removal, change of order, clearing, etc.), and the former does not. You can read more about that here: The ObservableCollection Class
In short: ObservableCollection provides change notifications which are required for the UI to automatically reflect changes in the view model.
In addition to Aviad and Reed's answers, I would like to point out a serious bug in your first code sample :
public static readonly DependencyProperty MyCustomObjectsProperty =
DependencyProperty.Register("MyCustomObjects", typeof(List<MyCustomObject>),
typeof(Main), new UIPropertyMetadata(new List<MyCustomObject>()));
The new List<MyCustomObject>() used as the default value will be created only once, so by default all instances of your type will share the same List<MyCustomObject> instance, which is probably not what you want... The only sensible default value here is null
In the first case, you're setting up a Dependency Property containing a List<T> instance.
In the second, you're making a normal CLR property, but having it setup as an ObservableCollection<T>.
For WPF Data Binding, there are some differences here.
Typically, you want all of your properties in the DataContext (which is the object that, by default, things "bind" to) to either implement INotifyPropertyChanged or to be a Dependency Property. This lets the binding framework know when changes are made to that object. Normally, though, you'd only use a Dependency Property if your working with a custom control - it's usually a better idea to have your object to which your data bound be a separate class, assigned to the DataContext. (For details here, see Josh Smith on MVVM or my recent detailed post on MVVM...)
However, with a collection, you typically also want the binding system to know when the items within the collection change (ie: an item is added). ObservableCollection<T> handles this by implementing INotifyCollectionChanged.
By using the second approach (using an ObservableCollection<T>), your UI can tell when items were added or removed from the collection - not just when a new collection is assigned. This lets things work automatically, like a ListBox adding elements when a new item is added to your collection.
1:
You're using a dependency property to "tell" the framework when that property is changed. This will have the following consequences for your binding:
MyCustomObjects.Add(new MyCustomObject()); //Wont update the view through databinding
MyCustomObjects = new List<MyCustomObject>(); //Will update the view through databinding
You could gain the same databinding functionality by implementing INotifyPropertyChanged on which ever class exposes the property, but dependency properties a capable of much more than just notifying about changes. These are rather advanced features though, which you aren't likely to come across in your average joe app :)
2:
You're using an observable collection, which implements INotifyCollectionChanged for you, to tell the databinding whenever the content of the collection has changed. This will have the opposite consequences than #1:
MyCustomObjects.Add(new MyCustomObject()); //Will update the view through databinding
MyCustomObjects = new ObservableCollection<MyCustomObject>(); //Won't update the view through databinding

Can MethodParameters in an ObjectDataProvider be databound to other controls?

I've been exploring WPF and XAML for a while now, but have hit a slight stumbling block revolving around binding to a method.
My situation is:
There is a ComboBox bound to a DataTable. There is a ListBox bound to the return value of a method (GetDates) via an ObjectDataProvider. One of the input parameters of the method GetDates is an Id stored in the ComboBox/DataTable.
How can I bind a MethodParameter in the ObjectDataProvider to a particular value of the SelectedItem of a ComboBox (in this case, the SelectedItem is of type DataRowView)? Alternatively, am I missing a better way of solving this problem?
I can see ways out of it by using the code-behind, but I'd like to know if there's a more XAML-y solution. It's always useful to pick up little tips and tricks, even if it turns out not to be the best fix to this problem.
http://msdn.microsoft.com/en-us/library/system.windows.data.objectdataprovider.methodparameters.aspx
This seems to describe what I need - although it's actually trying to answer a different problem.
(Aside: Is it just me or is that example on MSDN trying to do too much all at once?)
By binding the ItemsSource of the ComboBox to a DataTable, and the SelectedItem of the ComboBox to a MethodParameter (with a converter to extract the value I need from the DataRowView), the ObjectDataProvider will have the parameter it needs.
It would probably be easier to read/follow/maintain if I just hooked into the ComboBox.SelectionChanged event.

MVVM: CollectionView in ViewModel or CollectionViewSource in xaml?

I'm developing a WPF application using the MVVM pattern and I need to display a list of items in a ListView (with filtering), with the fields of the selected item displayed in a Master/Detail view. I'm torn between the following two ways of doing this:
Exposing a CollectionView in my ViewModel, and binding to this.
Exposing a plain IList in my ViewModel, and using CollectionViewSource to create the CollectionView in XAML.
Is there an accepted way of doing this? Any thoughts on the best way?
I do the former (expose CollectionView from the VM) but what really matters is where your filtering logic is. That should definitely be in the VM so that it can be tested, even if the view has to wire up the CollectionViewSource to the VM. That said, I don't think there's anything particularly nasty or anti-MVVM about exposing a CollectionView from your VM.
I know I'm a bit late answering your question but I just saw it today.
I have created master/detail viewmodels that use the CollectionViewSource and blogged about it.
I wrote about a viewmodel for master/detail tables here that uses :
http://reyntjes.blogspot.com/2009/04/master-detail-viewmodel_24.html
You can also find a viewmodel for the observablecollection class on my blog pages.
Maybe you find it of use to you.

Resources