最近的一个项目,需要在部分用户登录的时候,隐藏DataGrid中的一列,但是常规的绑定不好使,在下面举个例子。
XAML部分代码
<Window x:Class="DataGridColumn.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridColumn"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Button Content="显示" Command="{Binding Button1Command}"/>
<Button Content="隐藏" Command="{Binding Button2Command}"/>
</StackPanel>
<DataGrid Grid.Row="1" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="列一"/>
<DataGridTextColumn Header="列二"/>
<DataGridTextColumn Header="列三" Visibility="{Binding DataContext.IsVisibility,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
XAML
ViewModel部分代码
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows; namespace DataGridColumn
{
public class MainWindowVM : INotifyPropertyChanged
{
public MainWindowVM()
{
IsVisibility = Visibility.Hidden;
}
public event PropertyChangedEventHandler PropertyChanged;
private void INotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
} private Visibility isVisibility; public Visibility IsVisibility
{
get { return isVisibility; }
set
{
isVisibility = value;
INotifyPropertyChanged("IsVisibility");
}
} private RelayCommand button1Command; public RelayCommand Button1Command
{
get
{
return button1Command = new RelayCommand(
() =>
{
IsVisibility = Visibility.Visible;
});
}
} private RelayCommand button2Command; public RelayCommand Button2Command
{
get
{
return button2Command = new RelayCommand(
() =>
{
IsVisibility = Visibility.Hidden;
});
}
}
}
}
ViewModel
显示效果如下
本该隐藏的第三列,没有隐藏,比较困惑,然后百度了一下,在两个网站上得到了答案,网站一,网站二
出现问题的原因是,DataGridTextColumn不属于Visual Tree
解决方案有两种:
一、采用代理(网站一)
1、添加一个FrameworkElement的代理
<Window.Resources>
<FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/>
</Window.Resources>
2、用一个不可见的ContentControl绑定上一步的FrameworkElement代理
<ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"/>
3、用代理做为Visibility的数据源
<DataGridTextColumn Header="列二" Visibility="{Binding DataContext.IsVisibility,Source={StaticResource ProxyElement}}"/>
二、使用Freezable(网站二)
根据MSDN里Freezable的相关文档,在Remarks下有这样的一句话
Detailed change notification: Unlike other DependencyObject objects, a Freezable object provides change notifications when sub-property values change.
大意就是和其他的DependencyObject相比,在子属性值更改时, Freezable 对象提供更改通知。个人认为应该是由于Freezable有这个特点,所以才能被用在这里。
代码如下
BindingProxy类
public class BindingProxy:Freezable
{
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
//throw new NotImplementedException();
} public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
}
BindingProxy
XAML引用BindingProxy
<local:BindingProxy x:Key="proxy" Data="{Binding}"/>
Visibility绑定
<DataGridTextColumn Header="列三" Visibility="{Binding Data.IsVisibility,Source={StaticResource proxy}}"/>
效果如下,列二用的是方法一,列三用的是方法二
作为新手,只能理解如此,希望有大神可以给好好的讲解一下,谢谢。