1

当我们需要通过某种条件隐藏 DataGrid 的列时,我们都遇到了问题。至少有两种方法可以解决这个问题。两种方法都需要代理元素。我使用这两种方法。如您所见,使用 ofFreezableProxy作为代理元素不需要ContentControl,但需要指定附加类 ( FreezableProxy)。使用 ofFrameworkElement作为代理不需要指定额外的类(如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;
    }
}

两种方法看起来非常相似。建议我们使用第二种方法(使用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了属性。FrameworkElement

4

2 回答 2

3

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

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


现在,区分两种方法:

FreezableProxy 方法

实际来源参考在这里。Freezable 背后的魔法在这里定义,所以引用同一个链接:

Freezable 类的主要目的是定义具有可修改和只读状态的对象,但在我们的例子中有趣的特性是Freezable 对象可以继承 DataContext ,即使它们不在可视树或逻辑树中。

因此,您不需要任何 ContentControl 或任何代理控件,因为使用可冻结的位置,我们会自动获得继承的 DataContext。


FrameworkElement + ContentControl 方法

DataContext 属性用 flag 声明FrameworkMetadataOptions.Inherits。这意味着子控件会自动从其父元素继承它,除非为子控件显式设置。

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

<FrameworkElement x:Key="FrameworkElement"/>

另一种方法是按照我回答x:Reference中的描述使用。

于 2014-08-26T12:15:19.740 回答
0

你误会了。使用的元素不必a ContentControl,也可以是 any FrameworkElement。您似乎也对该方法的实际工作方式感到困惑,因为您没有在以下内容中使用 requiredx: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使用。简而言之,我们只是在FrameworkElement这里使用 this(可以是任何控件),以便我们可以DataContext通过它从主视觉树访问。

于 2014-08-26T12:05:02.540 回答