【问题标题】:Cannot bind to DataGrid Columns from within DataGridColumnHeader style template无法从 DataGridColumnHeader 样式模板中绑定到 DataGrid 列
【发布时间】:2018-04-12 14:35:30
【问题描述】:

我正在使用自定义的DataGrid,并且希望在我右键单击可以改变列可见性的列标题时能够拥有ContextMenu。我为我的DataGridColumnHeader 定义了一个Style,其中包含一个模板,我试图在其中定义一个ContextMenu,它将DataGrid 的列作为ItemsSource

<ContextMenu ItemsSource="{Binding Columns, RelativeSource={RelativeSource AncestorType={x:Type customControls:CustomDataGrid}}}">
    <ContextMenu.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Header}"/>
        </DataTemplate>
    </ContextMenu.ItemTemplate>
    <ContextMenu.ItemContainerStyle>
        <Style TargetType="MenuItem">
             <Setter Property="IsChecked" Value="{Binding Visibility, Converter={StaticResource BooleanToVisibilityConverter}, Mode = TwoWay}"/>
        </Style>
    </ContextMenu.ItemContainerStyle>
</ContextMenu>

但是,当我右键单击列标题以查看 ContextMenu 时,没有任何反应(它没有按预期打开),当我在 VS 中查看 Live Property Explorer 时,我可以看到 ItemsSource 属性ContextMenu 是空的,所以它显然没有找到 DataGrid 的 Columns 属性。

请注意,在 VS 的 Live Visual Tree 中,我可以看到为位于层次结构中我的自定义 DataGrid 下的控件定义的 DataGridColumnHeader 样式。

有什么想法吗?干杯。

【问题讨论】:

    标签: wpf mvvm


    【解决方案1】:

    DataGrid 不是ContextMenu 的视觉祖先。

    您可以将DataGridColumnHeaderTag 属性绑定到DataGrid,然后使用PlacementTarget 属性将ContextMenu 绑定到DataGrid

    <Style TargetType="DataGridColumnHeader">
        <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
        <Setter Property="ContextMenu">
            <Setter.Value>
                <ContextMenu ItemsSource="{Binding PlacementTarget.Tag.Columns, RelativeSource={RelativeSource Self}}">
                    <ContextMenu.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Header}"/>
                        </DataTemplate>
                    </ContextMenu.ItemTemplate>
                    <ContextMenu.ItemContainerStyle>
                        <Style TargetType="MenuItem">
                            <Setter Property="IsCheckable" Value="True" />
                            <Setter Property="IsChecked" Value="{Binding Visibility, Converter={StaticResource VisibilityToBooleanConverter}}"/>
                        </Style>
                    </ContextMenu.ItemContainerStyle>
                </ContextMenu>
            </Setter.Value>
        </Setter>
    </Style>
    

    另请注意,您应该使用VisibilityToBooleanConverter 而不是BooleanToVisibilityConverter

    class VisibilityToBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Visibility visibility = (Visibility)value;
            return visibility == Visibility.Visible;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            bool b = (bool)value;
            return b ? Visibility.Visible : Visibility.Collapsed;
        }
    }
    

    【讨论】:

    • 我的 ContextMenu 是在 DataGridColumnHeader 的 Template 属性中定义的,因此它仍然无法正常工作。我已经像您在上面所做的那样定义了 Tag 属性,但似乎我的模板中 ContextMenu 的 ItemsSource 找不到 Columns 属性 - 也许我需要一些不同的 RelativeSource 绑定?
    • 我现在已将 ContextMenu 从模板中移出,并将其设置为 DataGridColumnHeader,就像您在答案中所做的那样。我运行应用程序并检查 Live 属性资源管理器中的属性,可以看到 Tag 属性找到 DataGrid 很好,但 ItemsSource 仍然无法通过 Tag 属性找到 Columns(它的评估值为空)
    • 那么你显然做错了什么,因为这对我有用。提问时应提供 MVCE:stackoverflow.com/help/mcve。您在原始问题中没有提到任何关于 Template 属性的内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 2016-01-14
    • 1970-01-01
    • 2011-03-12
    • 2019-03-23
    • 2011-10-09
    相关资源
    最近更新 更多