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.
Related
I have a WPF Data Grid bound to an observable collection, which is working as intended.
What I am trying to do now is add text below it to say: "Number of selected rows: {count goes here}"
What's the proper way to do this? I could add a new property in the View Model called SelectedCount or something similar and bind to that, but it doesn't feel right. It seems redundant. Also, I could set the label text dynamically in the code behind, but I'm not sure if that's the "right" place to do this either.
Here's an example below.
EDIT:
Please pretend there's a checkbox column header whose intention is to provide check/uncheck all functionality. The state of this header checkbox should not count towards the final count.
You could use element binding to declaratively bind to the SelectedItems.Count property in XAML:
<TextBlock Text="{Binding ElementName=MyDataGrid,
Path=SelectedItems.Count, StringFormat=Number of selected rows: {0}}" />
Update
Presumably you're using MVVM, so adding a SelectedXCount property to your view model is a perfectly reasonable application of the view model. The advantage of having it in the view model is that you could unit test based on the number of selected items. E.g. if you want to check that the user can only progress (a CanNext property returns true) if the user has selected some items.
The SelectedItems property is not a DependencyProperty so can't be bound to, but there are many articles online that get around the issue when using the DataGrid in MVVM. Most of the solutions involve using a mechanism for calling a view model command on the invocation of the DataGrid's SelectionChanged event.
I have a library that generates a Grid based on input parameters. The Grid may contain different controls based on the input. I want to create a ListBox where each list item will get its own generated Grid. Is this doable? I couldnt find any Panel-derived (Gird, StackPanel etc) that expose the Content property like Button for example.
How are you passing the data to build the Grid?
I'll assume you have a control that receives the data via a Dependency Property. I.e. you have something like MyControl.MyData property, where MyData is a Dependency Property. In that case, try using a DataTemplate.
Make an ObservableCollection where each item is the data you need to pass in order to build the grid.
On the instance of the ListBox, define ItemTemplate to use a DataTemplate consisting of your control.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<myAssembly:MyControl MyData="{Binding }"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
#XAMeLi is almost right on the money with his answer - what would be better is a DataTemplateSelector, that way each data item can have a different template (or generated grid). In your class that extends DataTemplateSelector you can easily generate or load the appropriate grid layout as either a separate control or as a dynamic DataTemplate.
Check this article for a good example: WPF Tutorial - How To Use A DataTemplateSelector
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
I am stuck on how to pass data from one control to another. If I have a listbox control and the Contol Item contains a datatemplate which renders out 5 fields ( first name, last name, email, phone and DOB) all of which come from an observable collection. How can I allow the user to select a listbox item and have the valuesbe stored within a new listbox control?
Is this done through the creation of a new collection or is there a more simple way to bind these values to a new control?
thank you,
If it is not too late, I would strongly recommend that you use the MVVM pattern. The problem you are facing is typical for WPF without a decent presentation model and wont be the last one.
Using MVVM you would pass data between controls/views through the ViewModel. In your example you would have a PersonViewModel with an ObservableCollection containing first name, last name, email and DOB. Additionally it would have a property SelectedItem. This property can be bound to in a lot of different controls/views without them having to know each other.
Let's say you have a:
<ListBox Name="DemoList" ItemsSource="{Binding ...}">
<ListBox.ItemTemplate>
...
</ListBox.ItemTemplate>
</ListBox>
And another control, maybe a TextBox:
<TextBox Text="I want to bind this to the Email property" />
You can achieve this pretty easily, with:
<TextBox Text="{Binding ElementName=DemoList, Path=SelectedItem.Email}" />
Note the ElementName property of the Binding. This allows you to bind relative to another control, and in this case you want the SelectedItem of your ListBox. SelectedItem will contain an element of the collection in the ItemsSource (or null if nothing is selected), so you can then bind to its properties.
It gets more complex if you want to support multiple selection, but it doesn't sound like this is a requirement for you.
I have question on the checkbox.
First of all,
I have a usercontrol which has a list box like this and this user control will be switched by 2 button and then the data source is changed and then the the displayed officer status will be changed:
When I check the checkbox, Officers[0].IsOnDuty will be changed to true.
The problem is:
When I click another button and switch to another data source, this checked check box is still checked but the Officers[0].IsOnDuty for this data source is false.
How to solve this?
The data context of the list box item is an item for your officers collection, not the collection itself. And using a one way binding is incorrect, as the data source (the officer) will not be updated. So change the DataTemplate to:
<CheckBox IsChecked="{Binding Path=IsOnDuty, Mode=TwoWay}" />
*Here is the list box xaml:
<ListBox ItemsSource="{Binding OfficersCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Officers[0].IsOnDuty, Mode=OneWay}" />
*
The problem with your approach is that once you change the ItemsSource (by switching to the next page) your chekcbox is still bound to the item of the first collection. I think this happens because you explicitly use an indexer for the binding Path=Officers[0].IsOnDuty
Your samplelist box xaml does not really make sense. the ItemsSoruce is a OfficerCollection and your ItemTemplate binds to a collection of Officers too. Depending on what you are trying to accomplish you should do one of the following:
If your are just interested in the first officer (as your sample suggest), add a DependencyProperty FirstOfficer (or a INotifyPropertyChanged) property to your collection and bind to it: IsChecked="{Binding Path=Officers.FirstOfficer, Mode=OneWay}"
If you however are interested in all Officers and want checkboxes for all of them you should create a DataTemplate for the Officer type and use this as the ItemTemplate.
Generally you can stay out of a lot of trouble if you stick with MVVM and really tailor your ViewModel objects very close to what the View needs so you can bind your View to the ViewModel in the simplest possible way. Think of the ViewModel as the View you want to build but without a visual representation.