GetView() vs property in ViewModel - c#

I'm currently in the need of setting the SelectedIndex property of my TabControl when a certain event (IEventAggregator) takes place and thought about how I'd implement that.
I came up with 2 possibilities:
Use GetView() provided by ViewAware in order to access my TabControl and set the SelectedIndex to my value
Use a property in my associated ViewModel and bind this property to my TabControl's SelectedIndex property via XAML
Both options are working fine but I personally want to get this question answered since this is not the first time I'm wondering where to implement the functionality in such cases.
I know that the first option won't enable the Notify support but besides that: What would be the proper way?

Having a GetView() method to manipulate the view directly from the viewmodel completely breaks MVVM. You might as well just put all your logic in codebehind. The whole point of MVVM is to abstract away the actual view so that it is decoupled from the logic, and the app can be unit tested.
What if you change your mind about the tabs in the future and decide to show your multiple views some other way? You've now got to start editing your viewmodel to edit the new view instead of just tweaking some XAML.
And for unit testing you're going to have no way to mock out your TabControl.

Related

How to determine whether property should be placed in view or in the model?

I guess I'm a little confused as to whether properties like display range should be placed in the model (that gets inherited as a datacontext so that subcontrols can bind to it easily)or whether I should have properties be placed in the graphviewer class, and then let the components that need access to it have their own properties that they bind to the ancestor instead. Is it cleaner to bind to an ancestor control or just to bind off the model? I feel like the latter is cleaner, but then display range is pretty clearly a property of the view.
For example. I have a property AxisdivisionUnit that is needed in a scrollviewer, as well as used by a few thumbs to recalculate position on graph updates. The scrollviewer only appears when a treeview in the top level control (graphviewer) is populated. So I could either put the property axisdivisionunit on the graphviewer and bind the property to properties in the scrollviewer and thumb. Or I could have the thumb and scrollviewer bind to properties in the model (viewmodel if i were better at separating the UI out entirely.
Let me see if I can help..
First off, since you are discussing mainly the presentation of what things look like on your UI, then I do not think that the property should be in your model at all. The real question is whether it belongs in your View or ViewModel.
AxisDivisionUnit, sounds like it is only part of how the graph looks. I'm thinking that it would make more sense for that to be in the view only. If you had some properties describing the limits of your graph that were tied to business logic, then something like that may be better off in the ViewModel since you could possibly want to test that code and if you were to replace the UI you'd still want to enforce those exact same limitations.
I guess ask yourself, "If I were to replace this graph with a totally different graph and UI to display the same data, would I have to enforce this same logic?" If the answer is no, that it is just how you want to display it for this case... then it belongs in the View and you can bind a Control's property to another control's property or use triggers, behaviors, etc. to implement it in the View.

Which executes first Code Behind or View Model

Based on my previous question Accessing variables from XAML and object from ViewModel using Code Behind:
How would I know which executes first?
Is it the code behind or the ViewModel?
I just want to make sure that my code behind executes prior the ViewModel
The View and the ViewModel are both regular classes that get instantiated. This is done by calling the constructor as in any other class. So, as a simple answer to your question: Set a breakpoint in each constructor and see which one gets hit first.
There is no general answer to your question because it depends on your architecture and use case. Often, some control is bound to a property of the ViewModel of it's parent, which changes at some point. At that point your View already exists and you have no idea how long the value to which the property has been set is existing already. In other cases, your View is created for a specific ViewModel and takes it as constructor parameter.
The one way to make sure that the ViewModel exists before the View is to pass the ViewModel as a constructor parameter. The idea behind constructor parameters is to express: "This class needs existing instances of type xy to be created", which is what you are asking for. However, as you will set it as the Views DataContext in the constructor and as the DataContext can change after creation of the View, you cannot be sure that the View won't get a new ViewModel assigned after creation. Even worse, you will not be able to use your control in XAML anymore, because it doesn't have a default constructor anymore.
According to your first question, it is not really clear why the ViewModel should exist prior to the View. If you need to read a resource value from your View and assign it to a property on your ViewModel, I would expect it to be the other way around? Or are you accessing the View in your ViewModel (don't!)?
The question is, why you have to ask this question in the first place. There is something pretty wrong in your (or your bosses...) concept: View and ViewModel are two entities which should really work without knowing about each other. The idea is to build applications that could work perfectly without a single View existing by just getting/setting values on ViewModels and to have Views which would compile any run perfectly well without ViewModels, just without anything to show or do... If you try to hack this approach, you're better off not using MVVM at all.

Get reference to clicked item in view

I've recently been learning the MVVM pattern in WPF and just started making my first proper, rather big application. So far it's all smooth sailing, and I'm liking what I'm seeing a lot. However I recently met something of a stumbling block.
The application is built with a main TabControl, each TabItem containing a pretty big details view.
TabControl inside main View, ItemsSource bound to MainViewModel.OpenTabs
TabItem with data specific View+ViewModel
TabItem with data specific View+ViewModel
TabItem with data specific View+ViewModel
etc...
The OpenTabs collection is an ObservableCollection<BaseViewModel> on MainViewModel, and the TabControl's SelectedItem is bound to MainViewModel.ActiveTab.
So far so good! However, what I'm not sure I'm getting is how to handle closing of tabs while at the same time following MVVM. If I wasn't trying to be strict with the MVVM (in order to learn it properly), I'd just bind a MouseDown-event on the TabItem-headers and thus get a reference to the clicked item in that event, removing it from the OpenTabs collection in that way. But - unless I'm mistaken - the interaction logic shouldn't need references to actual UI items in order to be effective and proper MVVM.
So, how do I handle this MVVM style? Do I use a command that sends a specific parameter with it to my MainViewModel? It seems like the preferred implementation of ICommand in MVVM doesn't take object parameters (looking at MVVM Light as well as some other tutorials).
Should I just create a CloseTab(int id) public method on my MainViewModel and call that from the view codebehind after catching the Click on my TabItem close button? This seems like MVVM-cheating. :)
Also a final note - this should work even if I click close on a TabItem that isn't the currently active one. Otherwise it wouldn't be hard to setup with OpenTabs.Remove(ActiveTab).
Thanks for any help! I'd also appreciate any links to recommended reading/watching regarding these problems.
Solution: It seems the best way is to use a command that can accept command parameters. I used the RelayCommand from MVVM Light framework:
In MainViewModel:
CloseTabCommand = new RelayCommand<BaseViewModel>((vm) =>
{
OpenTabs.Remove(vm);
});
In XAML:
<Button
Command="{Binding Source={StaticResource MainViewModel}, Path=CloseTabCommand}"
CommandParameter="{Binding}">
Note: Your binding paths may of course vary depending on how your Views and ViewModels are set up.
The best and the right way is to create the command. In different frameworks ICommand usually has two implementation, with the parameter and without one (as often you do not need it).
MVVM light has two ICommand implementation as well: RelayCommand and RelayCommand<T>
I suggest creating your own DelegateCommand implementation, a good example on how to this can be found here or here. Or use the Prism variant, you can download it here.
With a DelegateCommand you can pass arguments down to your ViewModel.

MVVM viewmodel reference view

I am required to use the mvvm pattern. I know that the viewmodel should not care about the view from what I been reading. As a result I don't know how to solve this problem:
I have a dll that basically turns a textbox and listview into an autocomplete control:
SomeDll.InitAutocomplete<string>(TextBox1, ListView1, SomeObservableCollection);
anyways I don't know how to call that method from the viewmodel using the mvvm patter. if I reference the controls in the view I will be braking the rules.
I am new to MVVM pattern and my company requires me to follow it. what will be the most appropriate way of solving this problem?
I know I will be able to solve it by passing the entire view to the viewmodel as a constructor parameter but that will totaly break the mvvm pattern just because I need to reference two controls in the view.
What you're doing here is a pure view concern, so I'd recommend doing it in the view (i.e. the code-behind). The view knows about the VM and its observable collection, so why not let the code behind make this call?
(I'd also recommend seeing if you can get a non-code/XAML API for "SomeDll", but I have no idea how much control you might have over that)
There are two things that I'd point out here -
First, this is effectively all View-layer code. As such, using code behind isn't necessarily a violation of MVVM - you're not bridging that View->ViewModel layer by including some code in the code behind, if necessary.
That being said, this is often handled more elegantly in one of two ways -
You could wrap this functionality into a new control - effectively an AutoCompleteTextBox control. This would allow you to include the "textbox" and "listview" visual elements into the control template, and bind to the completion items within Xaml.
You could turn this into an attached property (or Blend behavior), which would allow you to "attach" it to a text box, and add that functionality (all within xaml). The items collection would then become a binding on the attached property (or behavior).

A viewmodel's role beyond databinding?

I'm a bit confused as to what a viewmodel's role is beyond databinding. I have a menu built in silverlight. The menu has x number of menu items which is determined at runtime. One of the features I would like to add to this is that each menuitem has a different text colour when hovered over.
Is it the role of the view to have a colour selector method or should the view handle this in it's code behind?
Normally I would keep the coloring/styling in XAML if possible - My view of the ViewModel is that it is responsible for providing all the data (ie. not graphical stuff) from the Model in a manner the View can consume.
If it was complex logic that determined the color and it was to be reused - I might be tempted to put it in the ViewModel tho.
The view model is used by the data binding process as a "safe" way to allow you to sort/filter/group the records as seen by a specific control without (necessarily) making changes to the actual bound data set (that is, unless/until you tell it to). (FMI read Bea's article here.)
I agree with Goblin here, in that the presentation aspects like color might be best kept separate in the XAML, for example in the DataTemplate used by that control.

Categories

Resources