How to bind to SelectedItem property of WPF TreeView? - mvvm

I have adapted the TreeView Control sample project here for use with Entity Framework objects. It works beautifully, but like many others attempting to update collections or properties on their ParentViewModels based SelectedItem changes, I too am unable to bridge the gap of understanding.
I am working in MVVM, and want my code-behind free of any mess. As a beginner, I like the cleanliness of implementing PropertyChanged notifications but since their is no inherent "SelectedItem" property to bind to on the TreeView, I am unable to raise my PropertyChanged event as I normally would with ListBox.
I too have a SelectedItem property (that actually successfully captures the object where isSelected = true) on my ChildViewModel (see H.B.'s answer to this question). I also have a SelectedItem of type ChildViewModel on my ParentViewModel which is bound to my View (see #Martin Liversage's post here). I cannot get them to sync up.
Please help me understand how to communicate the SelectedItem property of my ChildViewModel to my ParentViewModel. I do not bind my TreeView to a CollectionView, so I am unable to get the CurrentItem in the view collection.
My viewmodel collections I'm dealing with are very query-heavy, so I've not included any code for now. Please let me know what is needed for clarity.

So, at least you're starting to get used to your daily MVVM-WTF... 'Why do I have to post on SO for stuff as basic as this'. One day, you'll love MVVM, I promise ;)
That being said: As you know, the TreeView doesn't support synchronizing the SelectedItem property. It does exist, though, but it is readonly. What you want to do, is to extend the behavior of the TreeView to synchronize it's selected item with a property on it's ViewModel.
This problem description points you in the right direction: Behaviors. Behaviors (or, to be precise, System.Windows.Interactivity.Behavior<>s) allow you to extend the functionality of any DependencyObject. (Good introduction)
An approach to synchronize your TreeView with a selected item via behaviors, can be found here:
SO Thread
This should do for you already. You can just copy and paste the code of Steve GreatRex and go for it. Please comment, if you need help with the approach. Have fun learning!

Related

VM role in MVVM - should it handle everything and why?

Where exactly is the limit to adopt VM so it can suite better a particular View? Example:
There should be a command in UI (ex button) that should allow adding new item. Additional requirement can be that new item should be selected, ensured that its visible on control (lets say TreeView control), and to begin edit on the newly added item (in order to change predefined value that was set in VM). Lets assume that control doesn't have automatic mechanism to achieve this, so we need to do it manually. So the execution flow looks like this:
invoke add command on VM - done is View's xaml.
set SelectedItem to new item (usually we bind control's SelectedItem property to VM's CurrentItem property, and then just assign new item to CurrentItem.
ensure that new item is visible on control - this must be done in View's code behind.
Start editing - this must be done in View's code behind.
Now, since everywhere on net there are articles on using messages for almost everything, a question:
What do I break if I do it in the simple old fashion way? I use Click event instead of Command binding on adding new item, and in the method I do this:
// in View's Click event handler
ViewModel.AddCommand.Execute(null);
EnsureVisibleSelectedItem();
BeginEdit();
.. clean and clear! And what do I gain if I do it using messages:
// in ViewModel's AddCommand
AddNewItem();
SetCurrentItem();
SendMessageToEnsureVisibleSelectedItem();
SendMessageToBeginEditSelectedItem();
... where View has registered to receive these two messages.
Any light on this is greatly appreciated. To my opinion, UI can change, and VM should be able to adopt new UI without making changes to itself, so I dont quite understand current MVVM policy that is preached on internet.
I would say "make it simple".
What's really important in MVVM is:
what doesn't depend on the view should go in the ViewModel (your ViewModel must not be aware of the view in any way - not just by object reference)
everything else in the View and its code-behind.
Yes, in its code-behind. There's nothing wrong in writing code-behind if it is code that is related to the view, not logic. For instance, drag & drop management should be written in the code-behind.
To answer your question, you do not break anything in writing:
// in View's Click event handler
ViewModel.AddCommand.Execute(null);
EnsureVisibleSelectedItem();
BeginEdit();
Everything that is not related to the view is in the ViewModel, everything else in the View/code-behind. That's just fine.
No if I look at your second example:
// in ViewModel's AddCommand
AddNewItem();
SetCurrentItem();
SendMessageToEnsureVisibleSelectedItem();
SendMessageToBeginEditSelectedItem();
AddNewItem is OK (not related to the view), SetCurrentItem is OK (not related to the view), but what about SendMessageToEnsureVisibleSelectedItem and SendMessageToBeginEditSelectedItem?
EnsureVisible is typically useful for a treeview, but what if your view wasn't built with a treeview? What if the control would automatically make the new selected item visible? Of course you could ignore the message, but you would have written some useless code in ViewModel because you thought your view would need it for UI display.
You have typically written here some code in the ViewModel that is aware of how the View should be working. Yes, you have reduced the number of lines in the code-behind, but you definitely have broken the pattern.
Your "old fashion way" is actually a good way for your needs. Your ViewModel is not aware of the view, that's what's important.

MVVM: Does the ViewModel format the data it gets from the model?

I'm a little confused about MVVM.
I understand the concept and can see the advantages. My problem is: does the ViewModel pass data directly from the model.
For example, let's say I have a "User" model with a findByName() method. The ViewModel would call this in order to pass
the relevant user details to the view.
The model would likely retrun a set of "User" objects each which has properties such as name, email address etc and may also have methods.
My question is, should the ViewModel return the set of User objects to the view, or return a restructured version of this which
contains only what the view needs?
As I understand it, the "User" object in this case is part of the model layer and in MVVM the View should be dependant only on the ViewModel.
My issue with this is the ammount of seemingly redundant binding logic required in the ViewModel that would be created to restructure the output.
Passing the set of User objects directly to the View (via the ViewModel) would be far simpler.
There's a little bit of redundancy, sure. However, if you implement MVVM by presenting the objects, you get to
format the model information for the view without polluting the model with presentation logic
notify the view when anything changes
use WPF's validation (if you're using WPF)
run acceptance tests from the VM level rather than the GUI if you want to
abstract your presentation away from any changes to the model.
That last one's important. Mostly presentation bindings nowadays are dynamic and fail silently - web pages, WPF, you name it. That means that if someone decides to rename something on the model, it will suddenly break in your GUI and you won't know.
By putting a VM between your Model and View you buffer yourself from changes like this.
If you want to go ahead and get something working with the Users as they are, I say go for it - it'll help you get fast feedback on your GUI. However, the first time those User objects don't do exactly what the View needs, or you need to notify the View of a change, or you find yourself polluting the model, or something in the binding breaks, maybe that's a good time to move to MVVM.
Doesn't that just move the break to the ViewModels which are using the model? You'd still need to go through and update all of those.
If I renamed something (e.g. changed "surname" to "lastname") I'd expect things to break. I don't see how adding the binding in the VM layer fixes that.

what's the best practice for events handling in MVVM

I am doing a silverlight using the MVVM model, and i am finding it hard to do the events handling via MVVM especially that the events handlers are doing lots of changes in the view like enabling and disabling buttons, update media element functions and position. I am still new to the MVVM and i can't Imagen how can i do this. does anyone already know good article to start with or simple approach to understand :) I'll reply with what i may find interesting while i do my search as well. Thanks
1) Understand that there are different "flavors" of MVVM. Strict/hardcore MVVM patterns, although theoretically desires, isn't necessary.
2) Many view events can be handled via Commands. WPF supports this, and i believe Silverlight 4 does as well. A simple view-event to start with would be Button clicks. This allows you to handle the event in the ViewModel (instead of the View's 'code-behind').
3) For things like enabling/disabling view controls/states via the MVVM model, here is an example/explanation:
Xaml controls (say, a Button) is Data-Bound to the ViewModel for whatever property
(in this case, it will be the button's IsEnabled property).
Your ViewModel has an IsButtonEnabled property.
Whenever you change this property in the VM, raise the PropertyChanged notification, and you will see the binded result in the view (the button's IsEnabled state will be updated).
ps - you can do many things via VM properties in this manner: from text, to various property states, color, you can even play animations in the property setters/getters....etc.
Cheers

MVVM User control - where do i declare it to get data from page?

I have a WPF user control ...which is in MVVM. The user control(which contains a listview) need data from the page (where it is included). I have to set a property in View's code behind to get this data input. Will this comply with MVVM(But MVVM pattern do not support adding code in code behind file of view as far as i know).if not, what is the way for the same?
You want to do this via data binding. The controls are bound to properties in your viewmodel which receives the data, applies the needed logic and gives it back to the view for displaying it.
Have a look here to get an idea on how all that works.
I have got a link : http://social.msdn.microsoft.com/Forums/en/wpf/thread/a3eedc3e-0d59-420c-aba0-44fe8b00552f
But I'm not really getting whats meant by injection in it (as given below) :
an interface to the UserControl public model called IUserControlModel. It has the properties that should be visible from outside;
- a UserControlViewModel that contains a public property of type IUserControlModel that is injected in the constructor; plus all the properties used for XAML binds specific to the usercontrol implementation; XAML may have binds directly to the IUserControlModel properties too;
- a MainWindowViewModel that nests the IUserControlModel inside.
I think your problem can be solved in easier way. If you expose ItemsSource property of ListView as Dependency Property of your user control you can achieve what you want without unnecesary (in this case) overhead of implementing MVVM pattern : You then can just use databinding to add data from the page where the user control is included.
post that I think answers your question :
Post link

MVVM View reference to ViewModel

I'm using MVVM in a WPF app. I'm very new to both. Let me state that I am not a purist in the MVVM pattern, I am trying to use as many best practices as I can but am trying to make what I think are reasonable compromises to make it work in our environment. For example, I am not trying to achieve 0% code in my View code-behind.
I have a couple of questions about best practices.
1) I understand I don't want my VM to know about the attached View, but is it reasonable for the View to have a reference to its VM?
2) If a control in a View opens another View (such as a dialog) should I handle this in the View? It seems wrong to handle it in the VM since then the VM has some knowledge of a specific View.
1) The View has definitely a reference to the ViewModel through the DataContext. And you are allowed to cast the DataContext in your View:
public class ShellView : Window
{
…
public ShellViewModel { get { return DataContext as ShellViewModel; } }
This isn’t a violation with the Model-View-ViewModel pattern.
.
2) You are right. A ViewModel shouldn’t open another View. A better approach is to use Controllers. They are responsible for the Workflow of an application.
If you are interested in more detailed information then you might have a look at the WPF Application Framework (WAF).
1) Here are two simple practices for View's "knowing about" a ViewModel. It's reasonable for a View to know about a ViewModel (for Data Binding) -- but you may not need it in your case. See if either of these approaches help solve your problem. There are other ways, but these should be simple enough:
public View(ViewModel vm)
{
View.DataContext = vm;
}
public Bootstrapper(View v, ViewModel vm)
{
v.DataContext = vm;
//or, if you want it to have no parameters
View v = new View();
ViewModel vm = new ViewModel();
v.DataContext = vm;
}
The first option isn't bad if you have a service location tool, but there is a flavor of MVVM that doesn't like any code in the View's Code-Behind. The second option isn't bad either, should be simple enough for your task.
2.) This question can be a bit of a sticky point in MVVM design. If we are talking about a general Win32 MessageBox, I will often separate that logic into an additional object and put it in the VM. This way tends to a little more clear. (For example, I have selected an item in a ListBox, I have attached a Delete ICommand to that action, and in my ViewModel when this ICommand is Executed, I will poke my MessageBoxObject to ask if the user "wants to really delete" this item). More advanced "Dialogs" would use additional ViewModels and DataTemplates for those ViewModels. I prefer the Mediator approach.
1). The view will need a reference to the view model at some level, since the viewmodel will act as the view's datacontext.
2) One way to handle this is to have a generalized viewmodel representing a dialog, that is owned by the main viewmodel (the one being used as the views datacontext.)
You can use a command to crate a new instance of a dialog viewmodel, which will have a corresponding datatemplate defined in your resources. This template will be set to bind to the dialogviewmodel type.
Quite late, but I think this is tricky enough to deserve lots of different perspectives.
I understand I don't want my VM to know about the attached View, but
is it reasonable for the View to have a reference to its VM?
As already answered, a proper View-ViewModel arrangement involves the ViewModel being assigned as the View's DataContext property. That allows DataBindings to be "automagically" established from declarative XAML, or fine-tuned via code behind.
Sometimes, you'll be tempted to write, in your code behind, something like this:
var dc = DataContext as CleverViewModel;
CleverViewModel.CleverProperty.Add(someValue); // just a simple example
I believe the proper way to achieve this sort of things is NOT to cast DataContext, but instead:
Have some dedicated control in View, for example an ItemsControl with its ItemsSource two-way databound to some property in viewmodel:
<ItemsSource x:Name="cleverControl" Visibility="Collapsed" ItemsSource="{Binding CleverProperty, Mode=TwoWay}"/>
Cast the bound property instead of the whole ViewModel, in code behind:
var collection = (ObservableCollection<double>)cleverControl.ItemsSource;
collection.Add(someValue);
Note the important difference: the second approach in this example doesn't require the View to know the ViewModel type, it only needs a property named CleverProperty of type ObservableCollection<double>. This allows me to have polymorphic or even duck-typed ViewModels.
If a control in a View opens another View (such as a dialog) should I
handle this in the View? It seems wrong to handle it in the VM since
then the VM has some knowledge of a specific View.
This shouldn't happen in strict MVVM, and its not difficult to avoid using DataTemplates. DataTemplates map a given type of DataContext to a given type of view, so anytime the datacontext of a ContentControl changes, its display also changes, provided that you have a DataTemplate for that type:
A control in the view could send a command to the ViewModel, which in turn would update some of its own properties, that would be reflected by the view.
A View could contain another View, outside the knowledge of the ViewModel. In this case, the code behind can manipulate the datacontext of the contained view.
There are more subtleties, but I have been using this approach with good results. Hope this helps someone.
Build Your Own MVVM Framework
I found the approach suggested by Rob Eisenberg very interesting.
Key points:
Convention over configuration
ViewModel first
Which is very similar to ASP.NET MVC philosophy.
I highly recommend watching the video.