WPF 中 DataGridColumn 的绑定可见性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22073740/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 00:04:06  来源:igfitidea点击:

Binding Visibility for DataGridColumn in WPF

wpfxamldatagridvisibility

提问by ygoe

How can I hide a column in a WPF DataGridthrough a Binding?

如何DataGrid通过绑定隐藏 WPF 中的列?

This is what I did:

这就是我所做的:

<DataGridTextColumn Header="Column header"
                    Binding="{Binding ColumnValue}"
                    Width="100"
                    ElementStyle="{StaticResource DataGridRightAlign}"
                    Visibility="{Binding MyColumnVisibility}" />

And this is what I got (besides the column still visible):

这就是我得到的(除了列仍然可见):

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=MyColumnVisibility; DataItem=null; target element is 'DataGridTextColumn' (HashCode=1460142); target property is 'Visibility' (type 'Visibility')

System.Windows.Data 错误:2:找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement。BindingExpression:Path=MyColumnVisibility; 数据项=空;目标元素是“DataGridTextColumn”(HashCode=1460142);目标属性是“可见性”(类型“可见性”)

How to fix the binding?

如何修复绑定?

回答by Rohit Vats

First of all DataGridTextColumnor any other supported dataGrid columns doesn't lie in Visual tree of DataGrid. Hence, by default it doesn't inherit DataContextof DataGrid. But, it works for BindingDP only and for not other DP's on DataGridColumn.

首先DataGridTextColumn或任何其他受支持的 dataGrid 列不位于DataGrid. 因此,在默认情况下它不会继承DataContextDataGrid。但是,它Binding仅适用于DP,不适用于 DataGridColumn 上的其他 DP。

Since, they doesn't lie in same VisualTree so any try to get DataContext using RelativeSourcewon't work as well because DataGrid won't able to traverse up to DataGrid.

因为,它们不在同一个 VisualTree 中,因此任何使用 DataContext 的尝试RelativeSource都不会奏效,因为 DataGrid 将无法遍历到 DataGrid。

There are two ways to achieve that though:

不过有两种方法可以实现:



Firstusing Freezableclass - Freezableobjects can inherit the DataContext even when they're not in the visual or logical tree. So, we can take advantage of that to our use.

首先使用Freezable类 -Freezable即使对象不在可视化或逻辑树中,它们也可以继承 DataContext。因此,我们可以利用它来使用。

First create class inheriting from Freezableand DataDP which we can use to bind in XAML:

首先创建继承自FreezableDataDP 的类,我们可以使用它在 XAML 中进行绑定:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object),
                                     typeof(BindingProxy));
}

Now, add an instance of it in DataGrid resources so that it can inherit DataGrid's DataContext and then can bind with its Data DP:

现在,在 DataGrid 资源中添加它的一个实例,以便它可以继承 DataGrid 的 DataContext,然后可以与其 Data DP 绑定:

    <DataGrid>
        <DataGrid.Resources>
            <local:BindingProxy x:Key="proxy" Data="{Binding}"/>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Visibility="{Binding Data.MyColumnVisibility,
                                                Source={StaticResource proxy}}"/>
        </DataGrid.Columns>
    </DataGrid>


Second, you can refer to any UI element in XAML using ElementNameor x:Reference. But ElementNameworks only in same visual tree whereas x:Reference doesn't have such constraint.

其次,您可以使用ElementName或引用 XAML 中的任何 UI 元素x:Reference。但ElementName仅适用于相同的可视化树,而 x:Reference 没有这样的约束。

So, we can use that as well to our advantage. Create dummy FrameworkElementin XAML with Visibility set to collapsed. FrameworkElement will inherit DataContext from it's parent container which can be Window or UserControl.

因此,我们也可以利用它来发挥我们的优势。FrameworkElement在 XAML 中创建虚拟对象,并将可见性设置为折叠。FrameworkElement 将从它的父容器(可以是 Window 或 UserControl)继承 DataContext。

And can use that in DataGrid:

并且可以在 DataGrid 中使用它:

    <FrameworkElement x:Name="dummyElement" Visibility="Collapsed"/>
    <DataGrid>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Test"
                                Binding="{Binding Name}"
                                Visibility="{Binding DataContext.IsEnable,
                                          Source={x:Reference dummyElement}}"/>
        </DataGrid.Columns>
    </DataGrid>

回答by Meysam Chegini

<Window.Resources>
    <ResourceDictionary>
        <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}" />
    </ResourceDictionary>
</Window.Resources>

<!-- Necessary for binding to resolve: adds reference to ProxyElement to tree.-->
<ContentControl Content="{StaticResource ProxyElement}" Visibility="Collapsed" />
<mch:MCHDataGrid Height="350"
                  AutoGenerateColumns="False"
                  FlowDirection="LeftToRight"
                  ItemsSource="{Binding PayStructures}"
                  SelectedItem="{Binding SelectedItem}">
    <DataGrid.Columns>
         <DataGridTemplateColumn Width="70"
                                 Header="name"
                                 IsReadOnly="True"
                                 Visibility="{Binding DataContext.IsShowName,
                                 Source={StaticResource ProxyElement}}">
             <DataGridTemplateColumn.CellTemplate>
                 <DataTemplate>
                     <TextBlock Text="{Binding FieldName}" />
                 </DataTemplate>
             </DataGridTemplateColumn.CellTemplate>
         </DataGridTemplateColumn>                   
     </DataGrid.Columns>
</mch:MCHDataGrid>

Sample of bound property in view model:

视图模型中绑定属性的示例:

private Visibility _isShowName;

public Visibility IsShowName
{
    get { return _isShowName; }
    set
    {
        _isShowName = value;
        OnPropertyChanged();
    }
}