MVVM - WPF Desktop - wpf

Just started learning MVVM. I have a tabcontrol where I am adding multiple instances of same views/pages
Dim tb As New UXTabItem
tb.Header = "Childrens"
tb.Name = "tab" & itrt
itrt = itrt + 1
tb.Source = New Uri("/Views/childrens.xaml", UriKind.Relative)
UXTabControl1.Items.Add(tb)
Since each of the same view will handle different data but since the uri is same so all the tabs get populated with same view and changes reflect on each tabs. Which should not be the case. Should I be using a separate viewmodel for each of those? Any example would be much helpful.

One of the primary goals/advantages of MVVM is that you don't create WPF UI objects in code.
You should be populating a collection of view model objects and binding the ItemsSource of the TabControl that you define in XAML to it. You should have a DataTemplate defined for the data type of those objects and put their XAML in there, instead of loading it at runtime.
The TabControl is a little tricky, because it uses two templates: the ItemTemplate is used to define the look of the tab, and the ContentTemplate is used to define the look of the tab items' content. It's pretty common to see this:
<TabControl ItemsSource="{Binding MyItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
which populates the tab with a Text property on the view model, and the tab item's content with whatever template in the resource dictionary matches the view model's type.

I would have an ObservableCollection<TabViewModel> Tabs in my parent ViewModel, and bind the TabControl's ItemSource to that. Each Tab has it's own instance of TabViewModel, so adding a new Tab would mean adding a new TabViewModel to the Tabs collection in the ParentViewModel.
The TabViewModel would contain properties for things like Header or Uri, and these would be bound to the UI at the appropriate spots. Each TabViewModel can be drawn using the same View, but the data inside the object would be different for each tab.
My ParentViewModel would also contain a TabIndex property that defines which tab is selected

This is NOT trivial, IMO, and Rachel and Robert are both right.
Think of this task being one of managing 'work spaces", each represented by a tab control. I like to structure my view models into three related layers
DetailViewModel - the model for a given workspace (represented by a tab control)
MasterViewModel - the model for a collection of detail view models (ObservableCollection{DetailViewModel}). You would use this to bind to a list ion our presentation that shows what items may be selected for editing / display in a tab control. This is where filtering of the list would also be handled, if you allow that.
ShellViewModel - the model that actually has a collection of workspaces (ie, ObservableCollection{Workspace} along with the commands to manage them (ie, EditWorkspaceCommand, AddWorkspaceCommand, DeleteWorkspaceCommand). A workspace is a DetailViewModel that has a CloseCommand.
I found Josh Smith's MVVM article on MSDN useful for grokking this design.
HTH,
Berryl

Related

Create a control after selecting Item from grid in MVVM

I have a collection of items in grid(of telerik) and after I select any item of collection of items ( I know how to notice changing of selected item) I need to create a control in the same user control which will display some property of selected item.
The problem is that depending of what type(the class of collection have a field SomeType) of selected item is, I need to add a specific class.
So for example if I had a collection of cars, and I selected car which was suv, than I would had to add SuvControl, and when I selected van, then I would had to add VanControl. Those controls are different because have different names of fields and would have different behaviors.
I'm using MVVM Light .
I couldn't find any good example so I'll reward even for a link to some example.
What I would do would be binding the SelectedItem [property of the ListBox to the view model
SelectedItem={Binding SelectedItem, Mode=TwoWay}
or you could do ElementName binding too - all this to get to the details view's viewmodel.
The details view would use a DataTemplateSelector and you would display your details view like this:
<Grid
x:Name="DetailsGrid">
<prismvm:DataTemplateSelector
Content={Binding SelectedItem}>
<prismvm:DataTemplateSelector.Resources>
<DataTemplate
x:Key="Type1ViewModel">
<views:Type1View/>
</DataTemplate>
<DataTemplate
x:Key="Type2ViewModel">
<views:Type2View/>
</DataTemplate>
</prismvm:DataTemplateSelector.Resources>
</prismvm:DataTemplateSelector>
</Grid>
As suggested the DataTemplateSelector is the right way to go in most cases, and certainly the cleanest.
An alternative when you have few different templates (2 or 3) if to put them all and bind their visibility to the item type property so only one is visible at a time. Again, this is nor the recommended technique but in simple cases it can bring you to the desired result quickly.

WPF DataTemplate and usercontrol lifetime

I have a tab control with a few tabs. When a tab is selected, I set the content of the tab to its corresponding view model.
I also have a DataTemplate defined for the base view model that all of the other view models derive from:
<DataTemplate DataType="{x:Type vm:BaseViewModel}">
<view:BaseView/>
</DataTemplate>
This way, my view models, which are nearly identical, will be displayed using the same base view.
BaseView is a user control. In BaseView I have an Infragistics XamDataGrid defined. It seems that only one instance of this grid is created for all of the view models, meaning I can switch between tabs as many times as I want but the user control is never recreated from scratch.
How does WPF handle the lifetime of user controls when combined with DataTemplates?
The problem I am trying to solve is that in the xaml of BaseView, I have defined a Field in the XamDataGrid like so:
<igDP:XamDataGrid.FieldLayouts>
<igDP:FieldLayout>
<igDP:FieldLayout.FieldSettings>
<igDP:FieldSettings DataValueChangedNotificationsActive="true"
AllowCellVirtualization="False"
AllowResize="True"
AllowRecordFiltering="True"/>
</igDP:FieldLayout.FieldSettings>
<igDP:Field Name="IsDirty" Visibility="Collapsed"/>
</igDP:FieldLayout>
</igDP:XamDataGrid.FieldLayouts>
The IsDirty column (all of the view models have an IsDirty property) is only correctly collapsed the first time the grid is displayed. When I click another tab, the grid's data source changes, a new FieldLayout is created by the grid, and it doesn't pick up the Collapsed setting for IsDirty. As a result the IsDirty column is visible. My thinking was if I can force the user control to be totally recreated, I could avoid this issue.
Add DataTemplate to Resources and set x:Shared="false"

How to present a collection of objects in a listbox in WPF

I have a collection of objects that I want to present. How can I do this? A listbox would do but each object has many attributes which I want to present. I already bound a listbox to a collection and I have all my objects listed. My question is regarding the visualization of the listbox and if the listbox is the correct thing to use or there is something else that I should use.
I find the existing answers to be a bit lacking, normally one would not process collections or boil their items down to a string, at the very best you would do some dynamic manipulation using a CollectionView (e.g. sorting, grouping), but normally you use Data Templating to display the individual items which allows you to use all their properties.
Further there are several controls which work well with collections, firstly you need to know if you want selection, if not an ItemsControl is a good choice, otherwise you should use a ListBox or ListView.
ListViews are normally employed if you have different views for your objects, e.g. a details view and a thumbnail view. You can use the ListView.View for this, there is one existing view in the framework, the GridView, which offers columns. What Matthew Ferreira suggested is exactly what you should not do with a ListView since you want to make the templates dependent on the current view, in fact that code does not even compile since DataTemplate can only have one child.
ListViews are supposed to encapsulate the view logic in their view so it can be changed at will. If you decide to use a ItemsControl or ListBox then setting the ItemTemplate is what you want to do. Read the Data Templating overview i linked to, it makes for a good starting point.
You might want to consider using a ListView control instead. ListView has support for columns if you are planning on showing several properties from your object. You can use the ItemTemplate property to format the display of your object. For example:
<ListView ItemsSource="{Binding Path=myObjectCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Title}"/>
<CheckBox IsChecked="{Binding Path=ShouldCheck}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This example assumes that your object has the properties Title and ShouldCheck.
Your collection of object is probably to be viewed as your model. The usual thing in WPF is to add a ViewModel that translates and exposes the model data into a form suitable for binding. Depending on what you want to do, your VM could e.g. format each object into a string representation and then expose it as a collection of strings that the Listbox can bind to and display.

Set WPF TabControl to show the same Content for every tab

I'd like to use a TabControl where each tab shows the same view just with different parameters. Therefore I do not want to create a new content control for each tab but reuse the same control for all tabs (binding some properties of it to the SelectedItem property of the TabControl)
I tried to my contained control as resource and set the Content property of the tab items to it, but this resulted in an exception, because the same element cannot appear as content in to different parents.
Any ideas?
<TabControl>
<TabControl.ContentTemplate>
<DataTemplate>
your view
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
I found a solution in this question
TabControl's TabItems sharing same content... Do Not Want
(even if the poster wanted specifically the opposite behaviour :) ...)

Confusion with WPF MVVM

I have downloaded the document about MVVM from CodePlex, but I don't understand this diagram.
alt text http://img194.imageshack.us/img194/3959/diagram.png
In the document, ContactView never sets its DataContext to ContactViewModel, so I don't understand why this diagram has shown that ContactView refers to ContactViewModel via DataContext.
I don't know when it sets ContactView.DataContext, or is the document missing this point?
It may not need to specifically set the DataContext if the contacts are being shown in a listview or something similar.
If the datacontext of the listview is set to the Contacts property of the MainViewModel, then each item's datacontext will be set automatically to the specific ContactViewModel object, which may trigger the items to be presented using a ContactView control, assuming that certain template bindings were set up earlier in the document.
Sorry, I was having problems with codeplex and have only just managed to get the document to download. The block of code just before the diagram confirms my suspicion:
<Grid>
<ListBox ItemsSource="{Binding Contacts}">
<ListBox.ItemTemplate>
<DataTemplate>
<views:ContactView />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Since the ListBox is bound the the Contacts ObservableCollection each ListItem will have its DataContext set to the specific object that it is bound to. The DataTemplate is set up to show each item as a ContactView control. Therefore the ContactView's DataContext will be set to the right Contact object from the collection, all of this happens behind the scenes without you needing to actually set the property yourself.

Resources