C# XAML nested and/or template bindings

Date: 2020-05-14
  1. Add name attribute to the control tag:
    • x:Name=”variantEditorColumn”
  2. Set the DataContext attribute of an element to apply the data to all of its children:
    • DataContext=”{Binding Source={x:Reference variantEditorColumn}}”>
  3. Add (relative) bindings to the children:
    • ItemsSource=”{Binding Path=LookupItems1}”
  4. Add absolute bindings to non-children
    • ItemsSource=”{Binding Path=LookupItems1,Source={x:Reference variantEditorColumn}}”
<dxg:GridColumn x:Class="QuotationOrderHandling.Views.Controls.VariantEditorGridColumn"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
                xmlns:controls="clr-namespace:QuotationOrderHandling.Views.Controls"
                x:Name="variantEditorColumn"
                >
    <dxg:GridColumn.Resources>
        <controls:DebugDummyConverter x:Key="debugDummyConverter" />
    </dxg:GridColumn.Resources>
    <dxg:GridColumn.CellDisplayTemplate>
        <DataTemplate>
            <Label Content="{Binding Path=Row,ConverterParameter={x:Reference variantEditorColumn},Converter={StaticResource debugDummyConverter}}"></Label>
        </DataTemplate>
    </dxg:GridColumn.CellDisplayTemplate>
    <dxg:GridColumn.CellEditTemplate>
        <DataTemplate>
            <StackPanel Orientation="Vertical">
                <Label Content="{Binding Path=Row,ConverterParameter={x:Reference variantEditorColumn},Converter={StaticResource debugDummyConverter}}"></Label>
                <Popup Placement="Bottom" HorizontalAlignment="Left" VerticalAlignment="Top" Width="250" Height="120" IsOpen="True">
                    <Border BorderBrush="DarkGray" BorderThickness="1" Width="Auto" Height="Auto" HorizontalAlignment="Left" VerticalAlignment="Top" >
                        <DockPanel Background="WhiteSmoke" Width="250" Height="200">
                            <StackPanel Orientation="Vertical" Margin="10" DataContext="{Binding Source={x:Reference variantEditorColumn}}">
                                <Label Content="{Binding Path=Variant1Name}"></Label>
                                <dxg:LookUpEdit x:Name="lookupEdit1" ItemsSource="{Binding Path=LookupItems1}" ValueMember="KeyStr" DisplayMember="KeyName" AutoPopulateColumns="False" EditValue="{Binding Variant1, Mode=TwoWay}" EditValueChanged="lookupEdit1_EditValueChanged" PopupWidth="580">
                                    <dxg:LookUpEdit.StyleSettings>
                                        <dxg:SearchLookUpEditStyleSettings AllowGrouping="False" />
                                    </dxg:LookUpEdit.StyleSettings>
                                    <dxg:LookUpEdit.PopupContentTemplate>
                                        <ControlTemplate>
                                            <dxg:GridControl Name="PART_GridControl">
                                                <dxg:GridControl.Columns>
                                                    <dxg:GridColumn FieldName="KeyStr" Header="Sleutel" Width="150" />
                                                    <dxg:GridColumn FieldName="KeyName" Header="Omschrijving"  Width="380" />
                                                </dxg:GridControl.Columns>
                                                <dxg:GridControl.View>
                                                    <dxg:TableView AutoWidth="False" SearchPanelHighlightResults="True" SearchDelay="50" x:Name="CurrentTableView"/>
                                                </dxg:GridControl.View>
                                            </dxg:GridControl>
                                        </ControlTemplate>
                                    </dxg:LookUpEdit.PopupContentTemplate>
                                </dxg:LookUpEdit>

                                <Label Content="{Binding Path=Variant2Name}"></Label>
                                <dxg:LookUpEdit x:Name="lookupEdit2" ItemsSource="{Binding Path=LookupItems2}" ValueMember="KeyStr" DisplayMember="KeyName" AutoPopulateColumns="False" EditValue="{Binding Variant2, Mode=TwoWay}" EditValueChanged="lookupEdit2_EditValueChanged"  PopupWidth="580">
                                    <dxg:LookUpEdit.StyleSettings>
                                        <dxg:SearchLookUpEditStyleSettings AllowGrouping="False" />
                                    </dxg:LookUpEdit.StyleSettings>
                                    <dxg:LookUpEdit.PopupContentTemplate>
                                        <ControlTemplate>
                                            <dxg:GridControl Name="PART_GridControl">
                                                <dxg:GridControl.Columns>
                                                    <dxg:GridColumn FieldName="KeyStr" Header="Sleutel" Width="150" />
                                                    <dxg:GridColumn FieldName="KeyName" Header="Omschrijving"  Width="380" />
                                                </dxg:GridControl.Columns>
                                                <dxg:GridControl.View>
                                                    <dxg:TableView AutoWidth="False" SearchPanelHighlightResults="True" SearchDelay="50" x:Name="CurrentTableView"/>
                                                </dxg:GridControl.View>
                                            </dxg:GridControl>
                                        </ControlTemplate>
                                    </dxg:LookUpEdit.PopupContentTemplate>
                                </dxg:LookUpEdit>
                            </StackPanel>
                        </DockPanel>
                    </Border>
                </Popup>
            </StackPanel>
        </DataTemplate>
    </dxg:GridColumn.CellEditTemplate>
</dxg:GridColumn>
Other binding types:
{Binding ElementName=variantEditorColumn,Path=LookupItems1,Converter={StaticResource debugDummyConverter}}
{Binding Path=LookupItems1, RelativeSource={RelativeSource Self}}
{Binding Path=LookupItems1, RelativeSource={RelativeSource TemplatedParent}}
{Binding Path=LookupItems1, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}
{Binding Path=DataContext.LookupItems1,RelativeSource={RelativeSource AncestorType={x:Type GridColumn}}}

Debug bindings

Create the class below, and register it as above. The debugger will break with the value parameter to the resolved binding.

Source: https://www.wpf-tutorial.com/data-binding/debugging/

public class DebugDummyConverter : IValueConverter
{
	public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
	{
		Debugger.Break();
		return value;
	}

	public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
	{
		Debugger.Break();
		return value;
	}
}

Relative bindings in template:

<localPage:CorasauDataGridForeignKeyColumnClient x:Name="colVariant1" FieldName="Variant1" Visible="False">
    <localPage:CorasauDataGridForeignKeyColumnClient.DisplayTemplate>
        <ControlTemplate>
            <TextBlock Margin="2" VerticalAlignment="Center" Text="{Binding DataContext.RowData.Row.Variant1,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" />
        </ControlTemplate>
    </localPage:CorasauDataGridForeignKeyColumnClient.DisplayTemplate>
    <localPage:CorasauDataGridForeignKeyColumnClient.CellTemplate>
        <DataTemplate>
            <localPage:CorasauGridLookupEditorClient  x:Name="PART_Editor"  HasCustomLookUp="True" GotFocus="variant1_GotFocus" ItemsSource="{Binding DataContext.RowData.Row.Variant1Source,Mode=OneWay,RelativeSource={RelativeSource TemplatedParent}}"/>
        </DataTemplate>
    </localPage:CorasauDataGridForeignKeyColumnClient.CellTemplate>
</localPage:CorasauDataGridForeignKeyColumnClient>
37480cookie-checkC# XAML nested and/or template bindings