2014-02-27 165 views
44

如何通过绑定来隐藏WPF DataGrid中的列?WPF中DataGridColumn的绑定可见性

这是我做过什么:

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

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

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

不知道是什么意思执政。在我的窗口的某个地方是否有一些总统先生决定什么可行,哪些不行?或者我需要投票支持某些事情?

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

回答

105

首先DataGridTextColumn或任何其他支持的dataGrid列不在DataGrid的可视化树中。因此,默认它不会继承的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的DataContext的,然后可以绑定其数据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> 

,你可以参考的XAML中的y UI元素使用ElementNamex:Reference。但ElementName只能在同一个可视化树中工作,而x:引用不具有这样的约束。

所以,我们也可以使用它,以及我们的优势。在可见性设置为折叠的XAML中创建虚拟FrameworkElement。 FrameworkElement将从其父容器(可以是Window或UserControl)继承DataContext。

而且可以使用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> 
+2

我喜欢第二种方法。这很容易编写,我已经有了相同可见性的另一个控件,所以我可以给它一个'x:Name'并引用它的'Visibility'属性。不是直截了当的,更多的是在路上横向转弯,但仍然很简单。我想,当绑定到被引用元素的DataContext属性时,你“劫持”另一个元素来共享它的DataContext和其他不可访问的DataGridColumn,对吧? dummyElement只是一个桥梁。 – ygoe

+2

@LonelyPixel - 是的,你说得对。我尝试劫持DataGrid从它的DataGrid兄弟孩子,因为他们都共享相同的DataContext,除非明确设置。我可以使用x:DataGrid自身的引用,但这会导致循环依赖。 –

+1

+1为您的答案。对不起,我误解了这个问题。通过使用'x:Reference' - 在WPF 4.0中,至少在Visual Studio 2010中可能仍然出现异常:'服务提供者缺少INameResolver服务',它可以被忽略。据我了解,它是在WPF 4.5中修复的。 –

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

<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(); 
      } 
     } 
+0

我想这已经提出了一个一年前。太晚了。 – ygoe

相关问题