Reputation: 121
I am aware that as DataGrid columns aren't part of the Visual Tree, you can't bind the visibility property of the columns directly to a boolean property in your VM. You have to do it another way. Below is the way I have done it:
public class LocalVm
{
public static ObservableCollection<Item> Items
{
get
{
return new ObservableCollection<Item>
{
new Item{Name="Test1", ShortDescription = "Short1"}
};
}
}
public static bool IsDetailsModeEnabled
{
get { return true; }
}
}
public class Item : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
private string _shortDescription;
public string ShortDescription
{
get
{
return _shortDescription;
}
set
{
_shortDescription = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<Window x:Class="Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DataContext="{d:DesignInstance Type=local:LocalVm}"
Title="MainWindow" Height="350" Width="525"
Name="MyWindow">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataGridTextColumn x:Key="ThatPeskyColumn"
Binding="{Binding Size}"
Visibility="{Binding DataContext.IsDetailsModeEnabled,
Source={x:Reference MyWindow},
Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
<Grid>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Items}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
<StaticResource ResourceKey="ThatPeskyColumn"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
However, in my xaml window, there is an error on the "visibility" property: "Object reference not set to an instance of an object". If I remove the source and converter part, the error goes but it doesn't bind properly. What I am doing wrong?
thanks in advance
Upvotes: 0
Views: 2708
Reputation: 1491
As I can see from the code you've provided, IsDetailsModeEnabled property is static. To bind to static property in that case, you may just create your VM as a static resource, bind to its static property and set it to Window DataContext later:
<Window.Resources>
<local:LocalVm x:Key="vm" />
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataGridTextColumn x:Key="ThatPeskyColumn"
Binding="{Binding ShortDescription}"
Visibility="{Binding Path = IsDetailsModeEnabled,
Source={StaticResource vm},
Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
<Window.DataContext>
<StaticResource ResourceKey="vm"/>
</Window.DataContext>
From the other hand, more classical approach in that case would be with a proxy Freezable object, described here:
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); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
XAML
<Window.Resources>
<local:BindingProxy x:Key="proxy" Data="{Binding}" />
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataGridTextColumn x:Key="ThatPeskyColumn"
Binding="{Binding ShortDescription}"
Visibility="{Binding Path=Data.IsDetailsModeEnabled,
Source={StaticResource proxy},
Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
Upvotes: 2