C# WPF中特定于标题的上下文菜单绑定

C# WPF中特定于标题的上下文菜单绑定,c#,wpf,binding,datagrid,contextmenu,C#,Wpf,Binding,Datagrid,Contextmenu,我正在尝试为WPF datagrid构建特定于标题的上下文菜单(换句话说,每个列标题都可以有不同于其他标题的上下文菜单)。 此外,支持上下文菜单的数据是绑定数据。 我的问题是,我似乎无法将菜单连接到数据上下文。 我试过这里和其他地方的一些建议,但到目前为止没有成功 我知道上下文菜单不在文档其余部分的可视树中,所以我尝试使用它的PlacementTarget(如下所示),但当我单击列标题时,我的PlacementTarget只是标题的文本块。如何从那里进入网格的DataContext 这是我尝试过

我正在尝试为WPF datagrid构建特定于标题的上下文菜单(换句话说,每个列标题都可以有不同于其他标题的上下文菜单)。 此外,支持上下文菜单的数据是绑定数据。 我的问题是,我似乎无法将菜单连接到数据上下文。 我试过这里和其他地方的一些建议,但到目前为止没有成功

我知道上下文菜单不在文档其余部分的可视树中,所以我尝试使用它的PlacementTarget(如下所示),但当我单击列标题时,我的PlacementTarget只是标题的文本块。如何从那里进入网格的DataContext

这是我尝试过的一个例子:

<Window x:Class="ContextMenuExample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ContextMenuExample"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <local:ExampleViewModel />
</Window.DataContext>
<Grid>
    <DataGrid ItemsSource="{Binding MyGridData}" IsReadOnly="True" AutoGenerateColumns="False">
        <!-- THESE WORK, BUT THEY ARE GRID-GLOBAL.  I WANT HEADER-SPECIFIC CONTEXT MENUS -->
        <DataGrid.ContextMenu>
            <ContextMenu>
                <CheckBox  Name="GridCheckbox1" Content="Grid Menu - Item1" IsChecked="{Binding Column1Checked, Mode=TwoWay}"/>
                <CheckBox  Name="GridCheckbox2" Content="Grid Menu - Item2" IsChecked="{Binding Column2Checked, Mode=TwoWay}"/>
                <CheckBox  Name="GridCheckbox3" Content="Grid Menu - Item3" IsChecked="{Binding Column3Checked, Mode=TwoWay}"/>
            </ContextMenu>
        </DataGrid.ContextMenu>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Column 1 Data" Binding="{Binding Column1Data}" Width="Auto">
                <!-- ATTEMPT 1 - JUST SEE IF I CAN BIND DIRECTLY.  SHOULDN'T WORK. -->
                <!-- System.Windows.Data Error: 40 : BindingExpression path error: 'Column1Checked' property not found on 'object' ''String' (HashCode=-1586790989)'. BindingExpression:Path=Column1Checked; DataItem='String' (HashCode=-1586790989); target element is 'CheckBox' (Name='Header1Checkbox'); target property is 'IsChecked' (type 'Nullable`1') -->
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Name="Header1TextBlock" Text="{TemplateBinding Content}" >
                            <TextBlock.ContextMenu>
                                <ContextMenu>
                                    <CheckBox Name="Header1Checkbox" Content="Header Menu 1" IsChecked="{Binding Column1Checked, Mode=TwoWay}"/>
                                </ContextMenu>
                            </TextBlock.ContextMenu>
                        </TextBlock>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>
            <DataGridTextColumn Header="Column 2 Data" Binding="{Binding Column1Data}" Width="Auto">
                <!-- ATTEMPT 2 - BIND TO THE PLACEMENT TARGET. THIS MAKES THE TextBlock MY DATA CONTEXT.  CLOSER (?) BUT STILL WRONG -->
                <!-- System.Windows.Data Error: 40 : BindingExpression path error: 'Column2Checked' property not found on 'object' ''TextBlock' (Name='Header2TextBlock')'. BindingExpression:Path=Column2Checked; DataItem='TextBlock' (Name='Header2TextBlock'); target element is 'CheckBox' (Name='Header2Checkbox'); target property is 'IsChecked' (type 'Nullable`1') -->
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Name="Header2TextBlock" Text="{TemplateBinding Content}" >
                            <TextBlock.ContextMenu>
                                <ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
                                    <CheckBox Name="Header2Checkbox" Content="Header Menu 2" IsChecked="{Binding Column2Checked, Mode=TwoWay}"/>
                                </ContextMenu>
                            </TextBlock.ContextMenu>
                        </TextBlock>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>
            <DataGridTextColumn Header="Column 3 Data" Binding="{Binding Column1Data}" Width="Auto">
                <!-- ATTEMPT 3 - BIND TO THE PLACEMENT TARGETS' CONTEXT. I'M NOT EVEN SURE WHAT THIS IS, BUT IT DOESN'T WORK -->
                <!-- System.Windows.Data Error: 40 : BindingExpression path error: 'Column3Checked' property not found on 'object' ''String' (HashCode=975011251)'. BindingExpression:Path=Column3Checked; DataItem='String' (HashCode=975011251); target element is 'CheckBox' (Name='Header3Checkbox'); target property is 'IsChecked' (type 'Nullable`1') -->
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Name="Header3TextBlock" Text="{TemplateBinding Content}" >
                            <TextBlock.ContextMenu>
                                <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
                                    <CheckBox Name="Header3Checkbox" Content="Header Menu 3" IsChecked="{Binding Column3Checked, Mode=TwoWay}"/>
                                </ContextMenu>
                            </TextBlock.ContextMenu>
                        </TextBlock>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

类网格数据
{
public int Column1Data{get;set;}
公共int Column2Data{get;set;}
public int Column3Data{get;set;}
}
类示例示例ViewModel:INotifyPropertyChanged
{
检查私人布尔柱1;
私人布尔柱2检查;
检查私人布尔柱3;
公共事件属性更改事件处理程序属性更改;
公共列表MyGridData
{
得到
{
返回新列表
{
new GridData(){Column1Data=1,Column2Data=2,Column3Data=3},
new GridData(){Column1Data=4,Column2Data=5,Column3Data=6},
new GridData(){Column1Data=7,Column2Data=8,Column3Data=9}
};
}
}
公共图书馆专栏1检查
{ 
获取{return column1Checked;}
设置{
如果(列1已检查!=值)
{
第1列检查=数值;
PropertyChanged(此,新PropertyChangedEventArgs(名称)(列1选中));
}
}
}
公共图书馆2检查
{ 
获取{return column2Checked;}
设置{
如果(列2已检查!=值)
{
column2Checked=值;
PropertyChanged(这是新PropertyChangedEventArgs(名称)(列2选中));
}
}
}
公众专栏3被检查
{ 
获取{return column3Checked;}
设置{
如果(第3列已检查!=值)
{
column3Checked=值;
PropertyChanged(这是新PropertyChangedEventArgs(名称)(列3选中));
}
}
}
}
所以我的问题是。。。如何将关联菜单绑定到ViewModel

谢谢您的帮助。

试试这个

<DataGridTextColumn Header="Column 1 Data" Binding="{Binding Column1Data}" Width="Auto">
    <DataGridTextColumn.HeaderTemplate>
        <DataTemplate>
            <TextBlock Name="Header1TextBlock" Text="{TemplateBinding Content}">
                <TextBlock.ContextMenu>
                    <ContextMenu>
                        <CheckBox Name="Header1Checkbox" Content="Header Menu 1" IsChecked="{Binding DataContext.Column1Checked, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}"/>
                    </ContextMenu>
                </TextBlock.ContextMenu>
            </TextBlock>
        </DataTemplate>
    </DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>

我不太确定它是否有效,因为您的
上下文菜单是在模板中定义的。

试试这个

<DataGridTextColumn Header="Column 1 Data" Binding="{Binding Column1Data}" Width="Auto">
    <DataGridTextColumn.HeaderTemplate>
        <DataTemplate>
            <TextBlock Name="Header1TextBlock" Text="{TemplateBinding Content}">
                <TextBlock.ContextMenu>
                    <ContextMenu>
                        <CheckBox Name="Header1Checkbox" Content="Header Menu 1" IsChecked="{Binding DataContext.Column1Checked, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}"/>
                    </ContextMenu>
                </TextBlock.ContextMenu>
            </TextBlock>
        </DataTemplate>
    </DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>


我不太确定它是否有效,因为您的
ContextMenu
是在模板中定义的。

我终于在这里找到了我需要的:

多亏了daub815

这就是我的工作:

                <DataGridTextColumn Header="Column 1 Data" Binding="{Binding Column1Data}" Width="Auto">
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Name="Header1TextBlock" Text="{TemplateBinding Content}" Tag="{Binding DataContext, ElementName=MyDataGrid}">
                            <TextBlock.ContextMenu>
                                <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
                                    <CheckBox Name="Header1Checkbox" Content="Header Menu 1" IsChecked="{Binding Column1Checked, Mode=TwoWay}"/>
                                </ContextMenu>
                            </TextBlock.ContextMenu>
                        </TextBlock>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>


(其中MyDataGrid是DataGrid对象)

我终于在这里找到了我需要的东西:

多亏了daub815

这就是我的工作:

                <DataGridTextColumn Header="Column 1 Data" Binding="{Binding Column1Data}" Width="Auto">
                <DataGridTextColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Name="Header1TextBlock" Text="{TemplateBinding Content}" Tag="{Binding DataContext, ElementName=MyDataGrid}">
                            <TextBlock.ContextMenu>
                                <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
                                    <CheckBox Name="Header1Checkbox" Content="Header Menu 1" IsChecked="{Binding Column1Checked, Mode=TwoWay}"/>
                                </ContextMenu>
                            </TextBlock.ContextMenu>
                        </TextBlock>
                    </DataTemplate>
                </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>


(其中MyDataGrid是DataGrid对象)

Hi-Jai,感谢您的帮助。不幸的是,这不起作用。我认为,因为“窗口”对象没有DataContext,所以不管怎样,这都不会起作用。我尝试了“AncestorType=DataGrid”,但也不起作用。这可能是因为上下文菜单不是可视化树的一部分,因此查找祖先很困难。如果我能找到一种方法来产生相同的结果,而不在DataTemplate中声明我的ContextMenu,我会的。我只是不知道如何得到结果,我想要其他的方法。嗨,洁,谢谢你的帮助。不幸的是,这不起作用。我认为,因为“窗口”对象没有DataContext,所以不管怎样,这都不会起作用。