Мне нужно связать свойство Visibility
столбца в DataGrid
со свойством основного usercontrol. DataGrid
находится внутри DataTemplate
, написанного отдельным ResourceDictionary
. Я использовал трюк с элементом ProxyFramework, как описано в этом посте. Проблема в том, что Binding внутри прокси-элемента возвращает объект типа System.Windows.Data.RelativeSource
, а не нужное мне значение.
Вот пример кода:
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>
Код позади
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>
Как мне решить эту проблему проблема ?? Спасибо