WPF DataGridColumn Visibility
本文关键字:Visibility DataGridColumn WPF | 更新日期: 2023-09-27 18:19:23
当我们需要根据某些条件隐藏DataGrid的列时,我们都遇到了问题。至少有两种方法可以解决这个问题。这两种方法都需要代理元素。这两种方法我都用。如您所见,使用FreezableProxy
作为代理元素不需要ContentControl
,但需要指定额外的类(FreezableProxy
)。使用FrameworkElement
作为代理不需要指定额外的类(如FreezableProxy
),但需要将ContentControl
添加到标记中。
<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>
为什么这不起作用?
FrameworkElement
的DataContext
属性。问题是DataGridColumns不位于相同的可视化树作为它的父dataGrid。因此,绑定不能工作,因为DataContext不是继承的,不能使用RelativeSource找到,因为它依赖于Visual Tree。
所以,所有提到的方法都是将DataContext传递给列。
现在,两种方法的区别:
FreezableProxy方法:
实际的源代码参考是这里。Freezable背后的魔力是在这里定义的,所以引用相同的链接:
Freezable类的主要目的是定义具有可修改和只读状态,但是我们的情况是可冻结的对象可以继承DataContext,即使它们不在可视或逻辑树
所以,你不需要任何ContentControl或任何代理控件因为有了freezable,我们会自动继承DataContext。
FrameworkElement + ContentControl方法:
DataContext属性用标志 FrameworkMetadataOptions.Inherits
声明。除非为子控件显式地设置,否则子控件将自动从父元素继承它。
所以ContentControl自动从Grid继承DataContext,而ContentControl的子元素将从ContentControl继承它。这就是为什么FrameworkElement从ContentControl继承它。(无需手动绑定DataContext)。
<FrameworkElement x:Key="FrameworkElement"/>
另一种方法是使用 x:Reference
,如我在回答中所描述的。
你错了。所使用的元素不一定是ContentControl
,可以是任何FrameworkElement
。您似乎也对这种方法的实际工作方式感到困惑,因为您而不是在Binding
中使用所需的x:Reference
指令:
<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
(它可以是任何控件),这样我们就可以通过它从主视觉树访问DataContext
。