I have to bind the Visibility property of a column in a DataGrid to a property of the main usercontrol. The DataGrid is inside a DataTemplate written in a separate ResourceDictionary. I've used the ProxyFramework element trick as described in this post.
The problem is that the Binding inside the proxy element returns an object of type System.Windows.Data.RelativeSource and not the value I need.
Here the code example:
MainWindow.xaml
<Window
x:Class="TestRelativeSource.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:local="clr-namespace:TestRelativeSource"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="WinRoot"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:DerivedResource />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TabControl
Name="MainTabControl"
ContentTemplate="{StaticResource MyDataTemplate}"
ItemsSource="{Binding Path=MyList, ElementName=WinRoot, diag:PresentationTraceSources.TraceLevel=High}">
</TabControl>
<Button
x:Name="button"
Grid.Column="1"
Width="72"
Margin="0,10,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Click="Button_Click"
Content="Test" />
<Button
x:Name="buttonVisible"
Grid.Column="1"
Width="72"
Margin="0,35,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Click="ButtonVisible_Click"
Content="TestVisible" />
</Grid>
</Window>
Code behind
namespace TestRelativeSource
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
}
private ObservableCollection<MyCollections> myList;
public ObservableCollection<MyCollections> MyList
{
get { return myList; }
set { myList = value; OnPropertyChanged(); }
}
private bool visible;
public bool MyVisible
{
get { return visible; }
set { visible = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MyList = new ObservableCollection<MyCollections>();
var coll = new MyCollections();
coll.Name = "Test";
coll.Items = new ObservableCollection<MyItem>();
coll.Items.Add(new MyItem() { Name = "name1", TrueFalse = true });
coll.Items.Add(new MyItem() { Name = "name2", TrueFalse = false });
coll.Items.Add(new MyItem() { Name = "name3", TrueFalse = true });
coll.Items.Add(new MyItem() { Name = "name4", TrueFalse = false });
MyList.Add(coll);
}
private void ButtonVisible_Click(object sender, RoutedEventArgs e)
{
MyVisible= !MyVisible;
}
}
public class MyCollections : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged(); }
}
private ObservableCollection<MyItem> myVar;
public ObservableCollection<MyItem> Items
{
get { return myVar; }
set { myVar = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{
return Name;
}
}
public class MyItem : INotifyPropertyChanged
{
private string _name;
private bool _trueFalse;
public string Name { get => _name; set { _name = value; OnPropertyChanged(); } }
public bool TrueFalse { get => _trueFalse; set { _trueFalse = value; OnPropertyChanged(); } }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
DerivedResource.xaml
<ResourceDictionary
x:Class="TestRelativeSource.DerivedResource"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:local="clr-namespace:TestRelativeSource"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataTemplate x:Key="MyDataTemplate">
<DockPanel>
<DataGrid
x:Name="MyDataGrid"
AutoGenerateColumns="False"
CanUserDeleteRows="False"
ItemsSource="{Binding Items, Mode=OneWay}">
<DataGrid.Resources>
************** this binding returns a System.Windows.Data.RelativeSource instead Window***************
<FrameworkElement x:Key="ElementTabTypeProxyElement" DataContext="{Binding Source={RelativeSource AncestorType={x:Type Window}}}" />
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn
Binding="{Binding Name, Mode=OneWay, FallbackValue='---'}"
Header="Name"
/>
<DataGridCheckBoxColumn
Binding="{Binding TrueFalse, Mode=OneWay, FallbackValue=false}"
Header="TrueFalse"
************Here I want a boolean to convert to visibility from the property MyVisible***************
Visibility="{Binding Source={StaticResource ElementTabTypeProxyElement}, Path=DataContext.MyVisible, Converter={StaticResource BoolToVis}, diag:PresentationTraceSources.TraceLevel=High}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</DataTemplate>
</ResourceDictionary>
How can I address this issue?? Thanks