绑定WPF中DataGridColumn的可见性

时间:2014-02-27 15:58:48

标签: wpf xaml datagrid visibility

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

这就是我所做的:

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

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

  

System.Windows.Data错误:2:找不到目标元素的管理FrameworkElement或FrameworkContentElement。 BindingExpression:路径= MyColumnVisibility;的DataItem = NULL; target元素是'DataGridTextColumn'(HashCode = 1460142);目标属性是“可见性”(类型“可见性”)

不知道管理意味着什么。在我窗口的某个地方是否有一些总统先生决定哪些有效,哪些无效?或者我是否必须投票?

在网上搜索解决方案时,我发现有十几页有很好的标题,但完全不相关或不可复制的内容。所以这似乎是关于这个问题的第一个问题。有什么想法吗?

2 个答案:

答案 0 :(得分:134)

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

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

有两种方法可以实现这一目标:


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

首先创建继承自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));
}

现在,在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>

第二,您可以使用ElementNamex:Reference引用XAML中的任何UI元素。但ElementName仅适用于同一视觉树,而x:参考没有此类约束。

因此,我们也可以利用它。在可见性设置为折叠的XAML中创建虚拟FrameworkElement。 FrameworkElement将从其父容器继承DataContext,该容器可以是Window或UserControl。

可以在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>

答案 1 :(得分:10)

<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>

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

private Visibility _isShowName;

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