WPF DataGridColumn可见性

时间:2014-08-26 11:29:50

标签: c# wpf visibility datagridcolumn

当我们需要在某些条件下隐藏DataGrid的列时,我们都会遇到问题。至少有两种方法可以解决这个问题。方法的流程需要代理元素。我使用这些方法。如您所见,使用FreezableProxy作为代理元素不需要ContentControl,但需要指定其他类(FreezableProxy)。使用FrameworkElement作为代理不需要指定其他类(如FreezableProxy),但需要在标记中添加ContentControl

XAML:

<Window.Resources>
    <SampleRadioBoxCheckedConverter:FreezableProxy x:Key="FreezableProxy" Data="{Binding}"/>
    <FrameworkElement x:Key="FrameworkElement" DataContext="{Binding}"/>
</Window.Resources>

<Grid Margin="10">
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <DataGrid AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name"/>
            <DataGridTextColumn Header="Type" 
                                Visibility="{Binding Data.IsPartnerColumnVisible, Source={StaticResource FreezableProxy}}"/>
            <DataGridTextColumn Header="Number" 
                                Visibility="{Binding DataContext.IsPartnerColumnVisible, Source={StaticResource FrameworkElement}}"/>

        </DataGrid.Columns>
    </DataGrid>
    <ContentControl Grid.Row="1" Content="{StaticResource FrameworkElement}" Visibility="Collapsed"></ContentControl>

</Grid>

代码隐藏:

public class FreezableProxy : Freezable
{
    protected override Freezable CreateInstanceCore()
    {
        return new FreezableProxy();
    }

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

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

public partial class MainWindow : INotifyPropertyChanged
{
    private Visibility _isPartnerColumnVisible = Visibility.Hidden;
    public Visibility IsPartnerColumnVisible
    {
        get
        {
            return _isPartnerColumnVisible;
        }
        set
        {
            _isPartnerColumnVisible = value;
            RaisePropertyChanged("IsPartnerColumnVisible");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    void RaisePropertyChanged(String prop)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
    }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }
}

Bouth方法看起来很相似。建议我们使用第二种方法(使用FrameworkElement)。然后我有一个问题 - 如果ContentControl实际设置为Binding,为什么我需要指定其他{StaticResource FrameworkElement}ContentControl做了什么魔术?当我们使用FrezableProxy时,我们不需要指定任何ContentControl-s或其他内容,它可以正常工作。

更新

<FrameworkElement x:Key="FrameworkElement" DataContext="{Binding}"/>
/////<ContentControl Grid.Row="1" Content="{StaticResource FrameworkElement}" Visibility="Collapsed"></ContentControl>

为什么这不起作用? ContentControl已注释,但我明确设置了DataContext的{​​{1}}属性。

2 个答案:

答案 0 :(得分:2)

问题是 DataGridColumns与其父dataGrid 不在同一个Visual树中。因此,绑定不起作用,因为使用RelativeSource无法找到DataContext,因为它依赖于Visual Tree。

因此,提到的所有方法都是将DataContext传递给列。


现在,区分两种方法:

FreezableProxy方法

实际的参考资料是here。 Freezable背后的魔法在这里定义,所以引用相同的链接:

  

Freezable类的主要目的是定义具有的对象   可修改和只读状态,但我们的有趣功能   case是 Freezable对象即使在什么时候也可以继承DataContext   它们不在视觉或逻辑树中

因此,您不需要任何ContentControl或任何代理控制,因为使用freezable我们会自动获得继承的DataContext。


FrameworkElement + ContentControl方法

使用标志 FrameworkMetadataOptions.Inherits 声明DataContext属性。这意味着子控件会自动从它的父元素继承它,除非为子控件明确设置。

所以ContentControl自动从Grid继承DataContext,ContentControl的子元素将从ContentControl继承它。这就是FrameworkElement从ContentControl继承它的原因。 (无需手动绑定DataContext)。这将有效:

<FrameworkElement x:Key="FrameworkElement"/>

另一种方法是在我的回答中使用 x:Reference ,如here所述。

答案 1 :(得分:0)

你错了。使用过的元素必须是ContentControl,而且可以是任何FrameworkElement。您似乎也对此方法的实际工作方式感到困惑,因为您 使用x:Reference中所需的Binding指令:

<Grid Margin="10">
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <DataGrid AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name"/>
            <DataGridTextColumn Header="Number" 
                Visibility="{Binding DataContext.IsPartnerColumnVisible, 
                Source={x:Reference FrameworkElement}}"/>    
        </DataGrid.Columns>
    </DataGrid>
    <FrameworkElement Name="someElement" Grid.Row="1" Visibility="Collapsed" />    
</Grid>

导致此问题是因为DataGridTextColumn 不是主视觉树的一部分。我们可以在这里使用x:Reference指令,因为它不依赖于源元素与它所使用的Binding在同一个可视树中。简而言之,我们只是使用这个{{1这里(可以是任何控件),这样我们就可以通过它从主视觉树中访问FrameworkElement