Binding to another control's template - wpf

I have a control template for a DataGrid using another DataGrid for row details.
<DataGrid ItemsSource="{Binding SomeData}"
SelectedItem="{Binding SelectedThing, RelativeSource={RelativeSource TemplatedParent}}"
RowDetailsTemplate="{StaticResource RowDetailsTemplate}">
...
The SelectedItem is bound to the SelectedThing property of the control.
The row details template contains something like this:
<DataGrid ItemsSource="{Binding SubThings}"
SelectedItem="{TemplateBinding SelectedSubThing}">
...
I want to bind the SelectedItem to another property (SelectedSubThing) of the same control. The problem is that TemplateBinding won't work here because it's not referring to the same control.
How can I point this binding to the template of the parent DataGrid?

In the second DataGrid:
<DataGrid ItemsSource="{Binding SubThings}"
SelectedItem="{Binding DataContext.SelectedSubThing, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}">
RelativeSource allows you to walk up the visual tree, and hence find the mother DataGrid.

Related

WPF DataGrid cell binded on a parent property

I have a DataGrid that has the ItemSource property binded to a propery from my model.and i want to have a combobox column in the grid binded also to a property form the same model, not inside the property object that is binded on ItemSource
<DataGrid ItemsSource="{Binding Path=Model.ObjectList}" AutoGenerateColumns="False" AllowDrop="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Item No.">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="?????" SelectedValue="{Binding Path=ItemNumber}" SelectedValuePath="Id"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGrid>
The columns of the grid can have bindings only to properties that are inside an Object element from my ObjectList, Is there a way to bind a property from the parent model to a grid cell?
You should use something like that :
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path= DataContext.ItemSourcePropery}"
where ItemSourceProperty is the ObservableCollection which you want to bind to. Also if you are in a window, set type "Window" or whatever else.

Which object is the source of this binding?

I see DataGrid databinding sytax as below:
ItemsSource="{Binding Path=ListDataColumns, Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}"
The more complete code is:
<DataGrid KeyboardNavigation.ControlTabNavigation="Local" KeyboardNavigation.IsTabStop="False" DataContext="{Binding}"
ItemsSource="{Binding Path=ListDataColumns, Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False" x:Name="DataGridColumnConfig" VerticalAlignment="Top" AllowDrop="True"
IsSynchronizedWithCurrentItem="True" CanUserSortColumns="False" CanUserDeleteRows="False"
CanUserAddRows="False" GridLinesVisibility="All" SelectedItem="{Binding Path=SelectedItem}" SelectedIndex="{Binding Path=SelectedItemIndex}">
I think the code is binding to a property called "ListDataColumns".
How can I determine from the ItemSource that which object is being bound to?
To answer your question completely, we would need more information from you. However, with what you have provided (and using a simplified XAML example), we can tell you the following:
<DataGrid DataContext="{Binding}" ItemsSource="{Binding Path=ListDataColumns,
Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True,
UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding Path=SelectedItem}"
SelectedIndex="{Binding Path=SelectedItemIndex}" ... />
The DataContext is set to {Binding} which is the same as {Binding Path=.} and means that we are binding to the current Binding.Source... in other words, one of the parents of this control should have an instance of an object set as its DataContext and this control will share that same object and have access to the same properties.
The ItemsSource property is set to {Binding Path=ListDataColumns ...} which is the same as {Binding ListDataColumns ...} and means that it will look in whatever object is set as the DataContext (of the parent control) for a property named ListDataColumns.
The SelectedItem property is set to {Binding Path=SelectedItem} which is the same as {Binding SelectedItem} and means that it will look in whatever object is set as the DataContext (of the parent control) for a property named SelectedItem.
The SelectedIndex property is set to {Binding Path=SelectedItemIndex} which is the same as {Binding SelectedItemIndex} and means that it will look in whatever object is set as the DataContext (of the parent control) for a property named SelectedItem.
That is about all that can be taken from your XAML example (ignoring the other Binding properties). However, for users learning XAML and WPF, here are some very useful links on MSDN for help with property path syntax:
Binding.Path Property
PropertyPath XAML Syntax
Property Path Syntax

DataGrid binding in DataTemplate

I'm currently trying to do some binding inside of a datagrid but I'm having problems getting up to the level of DataContext of the view.
Here is the code:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Operators}"
ItemsSource="{Binding DataContext.OperatorList,ElementName=FilterGrid}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
Any ideas on whats wrong? The View's Viewmodel is connected in the code behind.
EDIT: The Binding that is not working is the ItemsSource binding shown above
When you use the DataTemplate of the DataGrid, you cannot use ElementName bindings as it won't resolve properly due to limitations in the resolution capabilities of FindControl within the DataGrid control hierarchy. You need to use a RelativeSource binding that travels up the control tree looking for a specific control type (which you need to determine - from your element name I assumed it was a DataGrid ancestor type).
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox
SelectedItem="{Binding Operators}"
ItemsSource="{Binding DataContext.OperatorList,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
See this SO post that shares some potentially related sample code using MVVM to access the DataContext of the UserControl host to populate a ComboBox ItemsSource.

Append DataGrid inside of DataGrids RowDetailsTemplate

this appears to bind, but rows in Details Grid are empty. Something is off/missing?
I've also tried {Binding SubCustomers}
SubCustomers is a List on parent object.
I am able to bind this way to single Fields such as FirstName etc.. just not the subcollection..
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Source=SubCustomers}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
The problem is that you are trying to bind to a property on the DataContext of the parent, not on that particular row. So, the DataContext of the RowDetails is the row item, and in order to get the parent's property, you need to use RelativeSource bindings. If you bind to the DataContext of the parent, you can then "dot-down" to the property you actually care about:
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="True"
ItemsSource="{Binding DataContext.SubCustomers, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>

Binding a WPF ComboBox to a different ItemsSource within a ListBox DataTemplate

I have a ListBox that contains a textbox and a combobox in its datatemplate:
<ListBox Height="147" Margin="158,29,170,0" Name="PitcherListBox" VerticalAlignment="Top" ItemsSource="{Binding SomeCollectionOfObjects}" Background="Black">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=Name}" />
<ComboBox ItemsSource="{Binding LocalArrayOfIntsProperty}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want to bind the listbox to a collection of objects (which I've done successfully), but I want the combobox in the above datatemplate to have its itemssource set to a local property on the window (array of ints). I still want the combobox to have a two-way bind between its selected item and a property on the collection of objects...
I have the following in code:
PitcherListBox.DataContext = this;
Basically in the end, I want the combobox within the listbox to have a different itemssource than the listbox itself. I can't seem to figure out how to change the ComboBox's ItemsSource in XAML. Can someone provide me some feedback? Thanks!
Try this:
<ComboBox ItemsSource="{Binding LocalArrayOfIntsProperty, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type YourWindowTypeHere}}}" />
Note that you need to replace YourWindowTypeHere with the type of the Window containing the LocalArrayOfIntsProperty! Also remember that you will need to define an xml namespace for that type!

Resources