之前寫過的一遍文章,在這裏直接貼出來。
場景:根據配置文件顯示DataGrid中的某些列。
問題:Columns集合只是DataGrid的一個屬性,這個集合在邏輯樹或視覺樹中是看不到的,也不會繼承DataContext屬性。
通過網上查閱各種資料,方法可以歸結以下幾種,下面將一一展示。
方法一:對DataGridColumn附加DataContext屬性
該方法需要用到一個幫助類(需要創建一個全局實例),具體內容如下:
public class DataGridContextHelper
{
static DataGridContextHelper()
{
DependencyProperty dp = FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
FrameworkElement.DataContextProperty.OverrideMetadata(typeof(DataGrid),
new FrameworkPropertyMetadata
(null, FrameworkPropertyMetadataOptions.Inherits,
new PropertyChangedCallback(OnDataContextChanged)));
}
public static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGrid grid = d as DataGrid;
if (grid != null)
{
foreach (DataGridColumn col in grid.Columns)
{
col.SetValue(FrameworkElement.DataContextProperty, e.NewValue);
}
}
}
}
前臺綁定示例
<DataGridTextColumn x:Name="col2" Header="TestColumn" Visibility="{Binding (FrameworkElement.DataContext).Show,RelativeSource={RelativeSource Self},Converter={StaticResource cc}}">
</DataGridTextColumn>
後臺綁定示例
var binding = new Binding();
binding.Mode = BindingMode.OneWay;
binding.RelativeSource=new RelativeSource(RelativeSourceMode.Self);
binding.Converter = new BooleanToVisibilityConverter();
binding.Path=new PropertyPath("(FrameworkElement.DataContext).Show");
BindingOperations.SetBinding(obj, DataGridColumn.VisibilityProperty, binding);
方法二:通過Source直接與Vm綁定
示例代碼:
var binding = new Binding();
binding.Mode = BindingMode.OneWay;
binding.Source = vm;
binding.Converter = new BooleanToVisibilityConverter();
binding.Path = new PropertyPath("Show");
BindingOperations.SetBinding(obj, DataGridColumn.VisibilityProperty, binding);
方法三:通過Source與VM的一個代理類進行綁定
代理類
Freezable可以繼承DataContext即使它們不在視覺樹或邏輯樹中
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 x:Name="dg" HorizontalAlignment="Left" VerticalAlignment="Top" Height="253" Width="436" ItemsSource="{Binding Persons}"
AutoGenerateColumns="False">
<DataGrid.Resources>
<dgTest:BindingProxy x:Key="proxy" Data="{Binding}"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn x:Name="col1" Header="TestColumn" Binding="{Binding Name}"></DataGridTextColumn>
<DataGridTextColumn x:Name="col2" Header="TestColumn"
Visibility="{Binding (FrameworkElement.DataContext).Show,RelativeSource={RelativeSource Self},Converter={StaticResource cc}}"></DataGridTextColumn>
<DataGridTextColumn x:Name="col3" Header="TestColumn"
Visibility="{Binding Data.Show,Source={StaticResource proxy},Converter={StaticResource cc}}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
方法四:通過一個代理控件來實現
代理控件與代理對象的解決方式類似,都是因爲其可以繼承DataContext屬性,只是一個在邏輯樹中看的到,一個看不到。示例如下:
<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>