简体   繁体   English

WPF 中 DataGridColumn 的绑定可见性

[英]Binding Visibility for DataGridColumn in WPF

How can I hide a column in a WPF DataGrid through a Binding?如何通过绑定隐藏 WPF DataGrid中的列?

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. System.Windows.Data 错误:2:找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement。 BindingExpression:Path=MyColumnVisibility; BindingExpression:Path=MyColumnVisibility; DataItem=null;数据项=空; target element is 'DataGridTextColumn' (HashCode=1460142);目标元素是“DataGridTextColumn”(HashCode=1460142); target property is 'Visibility' (type 'Visibility')目标属性是“可见性”(类型“可见性”)

How to fix the binding?如何修复绑定?

First of all, DataGridTextColumn (or any other supported dataGrid column) does not lie in the Visual tree of the DataGrid .首先, DataGridTextColumn (或任何其他受支持的 dataGrid 列)不在DataGrid的可视化树中 Hence, by default it doesn't inherit the DataContext of the DataGrid .因此,默认情况下它不继承DataGridDataContext However, it works for Binding DP only and for no other DP's on DataGridColumn.但是,它仅适用于Binding DP,而不适用于 DataGridColumn 上的其他 DP。

Since they don't lie in the same VisualTree, any attempt to get the DataContext using RelativeSource won't work as well because DataGridTextColumn is unable to traverse up to the DataGrid .由于它们不在同一个 VisualTree 中,因此任何使用RelativeSource获取DataContext尝试都不会奏效,因为DataGridTextColumn无法遍历到DataGrid

There are two other ways to achieve this though:不过,还有其他两种方法可以实现这一目标:


First using a Freezable class.首先使用Freezable类。 Freezable objects can inherit the DataContext even when they're not in the visual or logical tree –We can take advantage of that.即使Freezable对象不在可视化或逻辑树中,它们也可以继承 DataContext——我们可以利用这一点。

First, create a class inheriting from Freezable and Data DP which we can use to bind in XAML:首先,创建一个继承自FreezableData DP 的类,我们可以使用它在 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 the DataGrid's DataContext and 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 ElementName or x:Reference .其次,您可以使用ElementNamex:Reference XAML 中的任何 UI 元素。 However, ElementName works only in the same visual tree, whereas x:Reference doesn't have such constraints.但是, ElementName仅适用于同一个可视化树,而 x:Reference 没有这样的约束。

So, we can use that as well to our advantage.因此,我们也可以利用它来发挥我们的优势。 Create a dummy FrameworkElement in XAML with Visibility set to collapsed .在 XAML 中创建一个虚拟FrameworkElement ,并将 Visibility 设置为collapsed The FrameworkElement will inherit the DataContext from its parent container, which can be a Window or UserControl. 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>
<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();
    }
}

Another easy solution I like is to add a dummy collapsed FrameworkElement at the same level as the DataGrid .我喜欢的另一个简单的解决方案是在与DataGrid相同的级别添加一个虚拟折叠的FrameworkElement The FrameworkElement can then be used as the Source of the Binding with the x:Reference markup extension.然后可以将FrameworkElement用作带有x:Reference标记扩展的BindingSource

For example like this:例如像这样:

<FrameworkElement x:Name="FrameWorkElementProxy" Visibility="Collapsed"/>
<DataGrid>
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="post" 
            Visibility="{Binding DataContext.DataGridColumnVisibility, Source={x:Reference Name=FrameWorkElementProxy}}"/>
    </DataGrid.Columns>
</DataGrid>

Another fast option if you have created the Window/Page/UserControl DataContext object in the XAML like this:如果您在 XAML 中创建了 Window/Page/UserControl DataContext object,则另一个快速选项如下:

<Window.DataContext>  
    <local:ViewModel x:Name="MyDataContext"/>  
</Window.DataContext>

is that you can add x:Reference using the x:Name of the DataContext object in the Source of the binding:是您可以在绑定中使用 DataContext object 的x:Name添加x:Reference

<DataGridTextColumn Header="Column header"
                    Binding="{Binding ColumnValue}"
                    Width="100"
                    ElementStyle="{StaticResource DataGridRightAlign}"
                    Visibility="{Binding MyColumnVisibility, Source={x:Reference Name=MyDataContext}}"

That way you can avoid using Binding DataContext.MyColumnVisibility , and just use Binding MyColumnVisibility这样你就可以避免使用Binding DataContext.MyColumnVisibility ,而只使用Binding MyColumnVisibility

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM