WPF Databinding between two usercontrols - wpf

I'll try to give a bit more details of this question
In a WPF application, on the left side of 'mainwindow' I have a UserControl containing a listBox, like this
<UserControl.Resources>
<ObjectDataProvider x:Key="viewModel" ObjectType="{x:Type vm:TemplateListViewModel}"/>
</UserControl.Resources>
<StackPanel>
<ListBox Height="Auto" Name="TemplateList" ItemsSource="{Binding Source={StaticResource viewModel}, Path=TemplateNames}"
</StackPanel>
As shown, listbox items are fetched from a xml file via viewModel.
Now I have another usercontrol2 containing a Label to echo the selection from "TemplateList".
Also under this label I have another usercontrol3 containing a datagrid, which data will be fetched from a xml file based on the label, or the selection from the listbox on the left side of the window through usercontrol3's viewmodel.
So the question is how to pass the "SelectedItem" or "SelectedIndex" to viewModel of the Label and datagrid?
I know it works when I bind a label to a listbox with 'elementName' and Path to 'SelectedItem'. Now I couldn't figure out how to do with usercontrols and 'ObjectDataProvider'. I tried as suggested below couldn't get it to work out. So far for usercontrol2, if I use the same ObjectDataProvider as the above, I can get this label to work as
<Label Name="TemplateNameLabel" Content="{Binding Source={StaticResource viewModel}, Path=TemplateNames[0]}" />
Where 'TemplateNames' if of type 'XmlNodeList' because it was read from xml file. But I really want is something like
<Label Name="TemplateNameLabel" Content="{Binding Source={StaticResource viewModel}, Path=TemplateNames[SelectedIndex]}" />
Can this be done without any command, just like binding to 'elementname' without usercontrol involved?
Thanks.

I've removed not important properties to highlight the main:
<ListBox Name="TemplateList" ItemsSource="{Binding Source={StaticResource viewModel}, Path=TemplateNames}" SelectedItem="{Binding Path=SelectedTemplate, Mode=OneWayToSource}" />
Note, that you will need SelectedTemplate property with public setter of type TemplateName - the same type that is used for single element in the TemplateNames collection in the ViewModel. In that setter you could pass the value to whatever other view-models you need.

Related

Change binding source back to view model inside container in XAML

I am using Silverlight 4 and the MVVM pattern.
My view model has two properties:
SomeProperty and
MyCommand
SomeProperty is a complex type and has a lot of subproperties. MyCommand is a property to handle commanding from a Button.
I have a child window (the view) with a Grid as the LayoutRoot which is bound to the SomeProperty property of the view model.
<Grid x:Name="LayoutRoot" DataContext="{Binding SomeProperty, Mode=TwoWay}">
...
</Grid>
However, inside the Grid I want to bind a Button's Command property to the MyCommand property of the view model:
<Button Command={Binding MyCommand} />
But this is not working because MyCommand is a property of the view model, and not a property of the view model's SomeProperty property. (When I click on the Button it does not execute the command.)
Anywho, is there a way using data binding in Silverlight 4 such that I can have a container UI element set its DataContext property explicitly, but then have a different control within the container reference a property that's a sibling (or parent or whatever) of the DataContext of the containing control?
My current workaround is to define the binding in the view's class, but I'd rather have it in the XAML.
Thanks
If you give your root element (ChildWindow, UserControl, whatever) a name, then you can use ElementName to get to the view model.
<UserControl x:Name="MyUserControl">
<Grid x:Name="LayoutRoot" DataContext="{Binding SomeProperty, Mode=TwoWay}">
<Button Command="{Binding MyCommand}" DataContext="{Binding DataContext, ElementName=MyUserControl}" />
</Grid>
</UserControl>
Or, here's another way to do the same thing.
<UserControl x:Name="MyUserControl">
<Grid x:Name="LayoutRoot" DataContext="{Binding SomeProperty, Mode=TwoWay}">
<Button Command="{Binding DataContext.MyCommand, ElementName=MyUserControl}" />
</Grid>
</UserControl>
You try add datacontext to binding? The datacontext have to point to your viewmodel, because the default data context is a parent control or parent data context, in this case your layout root.
See this
and this
I hope this help.
Regards.
I use a version of the BindableProxy described in this post:
http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx
Above your Grid (probably within the UserControl.Resources) you would create:
<UserControl.Resources>
<ns:BindableProxy x:Key="BindableProxy" />
<UserControl.Resources>
Then, in the button binding:
<Button Command="{Binding DataSource.MyCommand, Source={StaticResource BindableProxy}}" />

XAML Control array for static number of combo boxes

I would like an array of 10 combo boxes on a wpf form.
The ItemsSource of the combo boxes are identical - an ObservableCollection of selectable Items.
Each Selected Item will bound to an item in a different ObservableCollection, imaginatively called 'SelectedItems'..
What is the best way to do the array? I could of course have 10 separate combo boxes but this would be not very elegant..
I don't think an ItemsControl template is what I'm after as the number of combo boxes is static.
Thanks
Joe
If I understand you right, you have 10 ComboBoxes with the same item list, but different data sources
In that case, I could create a common style for the ComboBox which sets the common properties such as ItemsSource (and SelectedItem if the binding is the same for all items), and then actually create the individual ComboBoxes on the form as needed.
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type ComboBox}">
<!-- Set the binding to wherever your ItemsSource resides. In this
case,I'm binding to a static class called Lists and a static
property called ComboBoxItems -->
<Setter Property="ItemsSource"
Value="{Binding Source={x:Static local:Lists.ComboBoxItems}}" />
<!-- Only use this setter if your binding is the same everywhere -->
<Setter Property="SelectedItem" Value="{Binding SelectedItem}" />
</Style>
</StackPanel.Resources>
<ComboBox DataContext="{Binding Item1}" />
<ComboBox DataContext="{Binding Item2}" />
<ComboBox DataContext="{Binding Item3}" />
<ComboBox DataContext="{Binding Item4}" />
<ComboBox DataContext="{Binding Item5}" />
<ComboBox DataContext="{Binding Item6}" />
<ComboBox DataContext="{Binding Item7}" />
<ComboBox DataContext="{Binding Item8}" />
<ComboBox DataContext="{Binding Item9}" />
<ComboBox DataContext="{Binding Item10}" />
</StackPanel>
Of course, if the DataSource for your ComboBoxes CAN be put in a collection, it is preferred that they are and that you use an ItemsControl to display the ComboBoxes
<ItemsControl ItemsSource="{Binding SelectedItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding }"
ItemsSource="{Binding Source={x:Static local:Lists.ComboBoxItems}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Each Selected Item will bound to an item in a different ObservableCollection, imaginatively called 'SelectedItems'..
Given that you're effectively binding to a collection, I would do an ItemsControl template, and just treat it that way. Unless you want to customize the layout (ie: these won't be arranged together in the View), that will simplify the design, even if the number of items is always "static".
If you want to have the items arranged separately on the View, then just having 10 combo boxes may be more appropriate.
Personally I think an ItemsControl which has an ItemTemplate which constructs each ComboBox is the way to go! Are you always going to have exactly 10 of these?
From an MVVM perspective, I can imagine a parent View Model which has a collection of selection view models. Each selection view model will have the list of items that can be selected, and the currently selected item. This view model will easily bind to your view.
Not knowing why you need this... which would probably be important in deciding how to do this... here is my stab at it.
Why not design the UI, give each ComboBox a name, create a List and Add each into that List at runtime?

WPF DataTemplate and Binding - Is this possible in xaml?

I am DataTemplating a listbox's ItemSource to display a series of comboboxes. I want to give the DisplayMemberPath of the combo to a property, which is in a different source than its own ItemsSource. (Assuming DisplayMemberPath is just a string representing name of a property, I am getting this from the user). I have achieved this with a CollectionViewSource, but all the comboboxes are displaying the same list.
What I am expecting to have after data templating is to have comboboxes display,
ComboboxInstance1.DisplayMemberPath = PropertyMapOfEmployee in FilterControls[0]
ComboboxInstance2.DisplayMemberPath = PropertyMapOfEmployee in FilterControls[1]
Is this possible to achieve in XAML ?
Thanks. Mani
UserControl:
<Resources>
<CollectionViewSource x:Key="bindingSource" Source="{Binding BindingItems}"/>
<CollectionViewSource x:Key="FilterSource" Source="{Binding FilterControls}"/>
<DataTemplate DataType="{x:Type CustomTypes:FilterElement}">
<ComboBox ItemsSource="{Binding Source={StaticResource bindingEmp}"
DisplayMemberPath="{Binding Source={StaticResource FilterSource},
Path=PropertyMapofEmployee}" />
</DataTemplate>
<Resources>
---
<DockPanel>
<ListBox x:Name="lstBox" ItemsSource="{Binding FilterControls}" />
</DockPanel>
ViewModel:
List<FilterElement> FilterControls;
List<Employee> Employees
class FilterElement
{
string Caption;
String PropertyMapofEmployee
}
<ComboBox ItemsSource="{Binding Source={StaticResource bindingEmp}"
DisplayMemberPath="{Binding PropertyMapofEmployee}" />
I'm not sure you can do that in XAML. (Having the DisplayMemberPath point to a property that is on an object other than the DataContext). You may want to look at the RelativeSource Class to see if that would meet your needs.
Have you thought about providing a reference in your Employee object to the FilterElement and then hooking up to the binding the Employee.PropertyMapOfEmployee property that you've created?

WPF Combobox binding

I got two Comboboxes and both of them have binding with the same Source.
<ComboBox ItemsSource="{Binding Source={StaticResource UsersViewSource}}"
And when I change something in the first one, it reflects also to the second one. And I dunno how to keep their SelectedItem values separately, using the same ItemsSource.
The IsSynchronizedWithCurrentItem property should be set to False:
true if the SelectedItem is always
synchronized with the current item in
the ItemCollection; false if the
SelectedItem is never synchronized
with the current item; null if the
SelectedItem is synchronized with the
current item only if the Selector uses
a CollectionView. The default value is
null.
Here's a sample:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:Array x:Key="myStrings" Type="sys:String">
<sys:String>one</sys:String>
<sys:String>two</sys:String>
<sys:String>three</sys:String>
<sys:String>four</sys:String>
<sys:String>five</sys:String>
</x:Array>
</Page.Resources>
<StackPanel Width="200">
<ComboBox IsSynchronizedWithCurrentItem="False" Margin="25"
ItemsSource="{Binding Source={StaticResource myStrings}}" />
<ComboBox IsSynchronizedWithCurrentItem="False" Margin="25"
ItemsSource="{Binding Source={StaticResource myStrings}}" />
</StackPanel>
</Page>
You just need to set the IsSynchronizedWithCurrentItem property to false (by default it's null)
I'd guess (from the name of your binding) that the reason this is happening is that you're binding to a CollectionViewSource (that wraps a collection). This class is a proxy that WPF uses that includes (amongst other things) the selected item of a collection. Obviously if you're sharing this collection between two comboboxes, you're also sharing the selected item.
If you set ItemsSource to something that's not a CollectionViewSource, the control will automatically wrap it in one. So, my suggestion would be to bind directly to a collection instead of wrapping in a CollectionViewSource - or, alternatively, create two CollectionViewSource instances, one for each ComboBox.
You can separately bind the SelectedItem property for each combo box separately.
i.e.
SelectedItem={Binding SelectedItem1}
This way when each one's item gets set, it gets stored into a different place.

How to bind items of a TabControl to an observable collection in wpf?

What is the simplest example of binding the items of a TabControl to an ObservableCollection?
Each tab's content will have unique data, and indeed this data will have observableCollections of its own bound to the items components.
Currently I have a user control, which I would like to set as the content of each tab as soon as it is created. I also need to dynamically set the datacontext of this new user control when the tab is created. So, essentially, I would like the tabcontrol's observablecollection contain modelviews that map to the data in each tab.
On top of that, I need to do all this without violating MVVM in WPF! Any help?
Much appreciated!
Basic example :
<Window.Resources>
<DataTemplate x:Key="templateForTheContent" DataType="{x:Type vm:TheViewModelType}">
<v:YourUserControl/>
</DataTemplate>
<DataTemplate x:Key="templateForTheHeader" DataType="{x:Type vm:TheViewModelType}">
<TextBlock Text="{Binding ThePropertyToDisplayInTheHeader}"/>
</DataTemplate>
</Window.Resources>
...
<TabControl ItemsSource="{Binding YourCollection}"
ContentTemplate="{StaticResource templateForTheContent}"
ItemTemplate="{StaticResource templateForTheHeader}">
</TabControl>

Resources