Search code examples
c#wpfbindingdatacontext

Binding Datacontext in Resources


I have a problem with binding a value in the Resource of a DataGrid. Outside of the resources-Tag it works perfectly, but inside it doesn't work. I think maybe the Datacontext changed or is null. I don't know what to do. I read something about freezables, but I didn't get them to work too. Is that the solution or is that, what I'm doing not possible. Here my code with the non-working and the working part - just for demonstration. I need the Contextmenu in the Resources-Section to get it only, if clicked on the header-row.

<UserControl x:Class="testapp.test.testManager.Window"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:testapp.test.testManager" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="600"
         DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">    
<Grid> 
    <DataGrid ItemsSource="{Binding Lst, UpdateSourceTrigger=PropertyChanged}" 
              AutoGeneratingColumn="dg_AutoGeneratingColumn">
        <DataGrid.Resources>
            <ContextMenu x:Key="DataGridColumnHeaderContextMenu">
                <MenuItem Header="{StaticResource General}">
                    <!-- HERE the Binding cannot find "TestCheck" -->
                    <CheckBox Content="Testentry Header" IsChecked="{Binding TestCheck, UpdateSourceTrigger=PropertyChanged,Mode=OneWay}"/>
        <!-- ... --->                    
                </MenuItem>                    
            </ContextMenu>
            <Style TargetType="{x:Type DataGridColumnHeader}">
                <Setter Property="ContextMenu" Value="{StaticResource DataGridColumnHeaderContextMenu}" />
            </Style>
        </DataGrid.Resources>           
        <DataGrid.ContextMenu>
            <ContextMenu>
                <MenuItem Header="{StaticResource General}">
                    <!-- Here the Binding can find "TestCheck" -->
                    <CheckBox Content="Testentry" IsChecked="{Binding TestCheck, UpdateSourceTrigger=PropertyChanged,Mode=OneWay}"/>
                    <!-- ... -->
                </MenuItem>
            </ContextMenu>
        </DataGrid.ContextMenu>            
    </DataGrid>
</Grid>


Solution

  • Issue is ContextMenu doesn't lie in same Visual tree as that of DataGrid and hence can't inherit DataContext of DataGrid.

    You can use x:Reference to get the DataGrid instance and bind with it's DataContext. (x:Reference is available from WPF 4.0)

    Give x:Name to dataGrid and bind with it:

    <DataGrid ItemsSource="{Binding Lst, UpdateSourceTrigger=PropertyChanged}"
              x:Name="dataGrid">
       <DataGrid.Resources>
           <ContextMenu x:Key="DataGridColumnHeaderContextMenu">
             <MenuItem Header="{StaticResource General}">
                <CheckBox Content="Testentry Header"
                          IsChecked="{Binding DataContext.TestCheck,
                                              Source={x:Reference dataGrid}}"/>
    ....
    </DataGrid>
    

    Also you can achieve that using Freezable class like you mentioned in question. Refer to my answer over here for the details to achieve that via Freezable.