【发布时间】:2020-04-07 13:28:12
【问题描述】:
我必须将DataGrid 中列的Visibility 属性绑定到主用户控件的属性。 DataGrid 在单独的 ResourceDictionary 中写入的 DataTemplate 内。我使用了 this 帖子中描述的 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>
我该如何解决这个问题? 谢谢
【问题讨论】:
-
应该是相对来源:
"{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}" -
是的!改变了,用一个虚拟的 ContentControl 移动了 DockPanel 中的代理,现在就像一个魅力!非常感谢
标签: c# wpf xaml binding relativesource