c# - 绑定 AvalonDock LayoutAnchorable IsVisible 属性
问题描述
我正在尝试将 AvalonDock 绑定LayoutAnchorables
到 WPF 中它们各自的菜单项。如果在菜单中选中,anchorable 应该是可见的。如果未在菜单中选中,则应该隐藏可锚定对象。
两者IsChecked
和IsVisible
都是布尔值,所以我不希望需要转换器。我可以将LayoutAnchorable
IsVisible
属性设置为True
or False
,并且行为与设计视图中的预期一致。
但是,如果尝试如下实现绑定,则会收到错误消息
不能在“LayoutAnchorable”类型的“IsVisible”属性上设置“绑定”。只能在 DependencyObject 的 DependencyProperty 上设置“绑定”。
问题在这里:
<dock:LayoutAnchorable ContentId="content1" IsVisible="{Binding IsChecked, ElementName=mnuPane1}" x:Name="anchorable1" IsSelected="True">
我怎样才能做到这一点?
<Window x:Class="TestAvalonBinding.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dock="http://schemas.xceed.com/wpf/xaml/avalondock"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Menu -->
<Menu Height="18" HorizontalAlignment="Stretch" Name="menu1" VerticalAlignment="Top" Grid.Row="0">
<MenuItem Header="File">
<MenuItem Header="_Foo1" Name="mnuPane1" IsCheckable="True">
</MenuItem>
<MenuItem Header="Foo2" Name="mnuPane2" IsCheckable="True">
</MenuItem>
</MenuItem>
</Menu>
<!-- AvalonDock -->
<dock:DockingManager x:Name="Dockman" DockPanel.Dock="Left" Grid.Row="1" >
<dock:LayoutRoot x:Name="_layoutRoot">
<dock:LayoutPanel Orientation="Horizontal">
<dock:LayoutAnchorablePaneGroup Orientation="Vertical">
<dock:LayoutAnchorablePane FloatingWidth="150" FloatingHeight="150" FloatingLeft="100" FloatingTop="300">
<dock:LayoutAnchorable ContentId="content1" IsVisible="{Binding IsChecked, ElementName=mnuPane1}" x:Name="anchorable1" IsSelected="True">
<GroupBox Header="Foo1"/>
</dock:LayoutAnchorable>
</dock:LayoutAnchorablePane>
<dock:LayoutAnchorablePane FloatingWidth="150" FloatingHeight="150" FloatingLeft="100" FloatingTop="300">
<dock:LayoutAnchorable ContentId="content2" x:Name="anchorable2" IsSelected="True">
<GroupBox Header="Foo2"/>
</dock:LayoutAnchorable>
</dock:LayoutAnchorablePane>
</dock:LayoutAnchorablePaneGroup>
</dock:LayoutPanel>
</dock:LayoutRoot>
</dock:DockingManager>
</Grid>
</Window>
更新:
我对 BionicCode 答案的实现。我剩下的问题是,如果我关闭一个窗格,菜单项仍然处于选中状态。
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Menu -->
<Menu Height="18" HorizontalAlignment="Stretch" Name="menu1" VerticalAlignment="Top" Grid.Row="0">
<MenuItem Header="File">
<MenuItem Header="_Foo1" Name="mnuPane1" IsCheckable="True" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=local:MainWindow}, Path=IsAnchorable1Visible}"/>
<MenuItem Header="Foo2" Name="mnuPane2" IsCheckable="True" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=local:MainWindow}, Path=IsAnchorable2Visible}"/>
</MenuItem>
</Menu>
<!-- AvalonDock -->
<dock:DockingManager x:Name="Dockman" DockPanel.Dock="Left" Grid.Row="1" >
<dock:LayoutRoot x:Name="_layoutRoot">
<dock:LayoutPanel Orientation="Horizontal">
<dock:LayoutAnchorablePaneGroup Orientation="Vertical">
<dock:LayoutAnchorablePane FloatingWidth="150" FloatingHeight="150" FloatingLeft="100" FloatingTop="300">
<dock:LayoutAnchorable ContentId="content1" x:Name="anchorable1" IsSelected="True" >
<GroupBox Header="Foo1"/>
</dock:LayoutAnchorable>
</dock:LayoutAnchorablePane>
<dock:LayoutAnchorablePane FloatingWidth="150" FloatingHeight="150" FloatingLeft="100" FloatingTop="300">
<dock:LayoutAnchorable ContentId="content2" x:Name="anchorable2" IsSelected="True" >
<GroupBox Header="Foo2"/>
</dock:LayoutAnchorable>
</dock:LayoutAnchorablePane>
</dock:LayoutAnchorablePaneGroup>
</dock:LayoutPanel>
</dock:LayoutRoot>
</dock:DockingManager>
</Grid>
背后的代码
partial class MainWindow : Window
{
public static readonly DependencyProperty IsAnchorable1VisibleProperty = DependencyProperty.Register(
"IsAnchorable1Visible",
typeof(bool),
typeof(MainWindow),
new PropertyMetadata(default(bool), MainWindow.OnIsAnchorable1VisibleChanged));
public static readonly DependencyProperty IsAnchorable2VisibleProperty = DependencyProperty.Register(
"IsAnchorable2Visible",
typeof(bool),
typeof(MainWindow),
new PropertyMetadata(default(bool), MainWindow.OnIsAnchorable2VisibleChanged));
public bool IsAnchorable1Visible
{
get => (bool)GetValue(MainWindow.IsAnchorable1VisibleProperty);
set => SetValue(MainWindow.IsAnchorable1VisibleProperty, value);
}
public bool IsAnchorable2Visible
{
get => (bool)GetValue(MainWindow.IsAnchorable2VisibleProperty);
set => SetValue(MainWindow.IsAnchorable2VisibleProperty, value);
}
public MainWindow()
{
InitializeComponent();
this.IsAnchorable1Visible = true;
this.IsAnchorable2Visible = true;
}
private static void OnIsAnchorable1VisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as MainWindow).anchorable1.IsVisible = (bool)e.NewValue;
}
private static void OnIsAnchorable2VisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as MainWindow).anchorable2.IsVisible = (bool)e.NewValue;
}
}
解决方案
您的绑定有两个主要问题。
- 该
IsVisible
属性不是一个DependencyProperty
,而只是一个 CLR 属性,所以你不能绑定它 - A
LayoutAnochorable
不是可视树的一部分,因此ElementName
绑定RelativeSource
不起作用,您将在输出窗口中看到相应的绑定错误
我不确定是否有特定的设计选择或限制不使该IsVisible
属性成为依赖属性,但您可以通过创建附加属性来解决此问题。此属性可以绑定并在更改时设置 CLRIsVisible
属性LayoutAnchorable
。
public class LayoutAnchorableProperties
{
public static readonly DependencyProperty IsVisibleProperty = DependencyProperty.RegisterAttached(
"IsVisible", typeof(bool), typeof(LayoutAnchorableProperties), new PropertyMetadata(true, OnIsVisibleChanged));
public static bool GetIsVisible(DependencyObject dependencyObject)
{
return (bool)dependencyObject.GetValue(IsVisibleProperty);
}
public static void SetIsVisible(DependencyObject dependencyObject, bool value)
{
dependencyObject.SetValue(IsVisibleProperty, value);
}
private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is LayoutAnchorable layoutAnchorable)
layoutAnchorable.IsVisible = (bool)e.NewValue;
}
}
您可以在 XAML 中绑定此属性,但正如所说,这将不起作用,因为它LayoutAnchorable
不在可视树中。列也会出现同样的问题DataGrid
。在这篇相关文章中,您可以找到BindingProxy
我们将使用的类的解决方法。请将此类复制到您的项目中。
在您的DockingManager.Resources
. 它用于访问菜单项。
<dock:DockingManager x:Name="Dockman" DockPanel.Dock="Left" Grid.Row="1">
<dock:DockingManager.Resources>
<local:BindingProxy x:Key="mnuPane1Proxy" Data="{Binding ElementName=mnuPane1}"/>
</dock:DockingManager.Resources>
<!-- ...other XAML code. -->
</dock:DockingManager>
删除旧IsVisible
绑定。使用 . 将绑定添加到附加属性mnuPane1Proxy
。
<xcad:LayoutAnchorable ContentId="content1"
x:Name="anchorable1"
IsSelected="True"
local:LayoutAnchorableProperties.IsVisible="{Binding Data.IsChecked, Source={StaticResource mnuPane1Proxy}}">
最后,将IsChecked
菜单项中的默认状态设置为true
,因为这是默认状态,IsVisible
并且由于在附加属性中设置默认值,绑定不会在初始化时更新,这是为了防止InvalidOperationException
由于控件而引发的没有完全初始化。
<MenuItem Header="_Foo1" Name="mnuPane1" IsCheckable="True" IsChecked="True">
推荐阅读
- google-cloud-platform - GCP 端点与身份平台的集成
- scala - 遍历一个
并以自定义数据类型填充 Vector - node.js - npm 运行脚本未写入包中
- java - 从 Android USB 附件读取数据的更好方法
- javascript - 如何捕获度量(数字和/或单位)和度量的事项并始终确保相同的度量格式/模式?
- python - 使用 pygame 缩放像素艺术游戏的最佳方法是什么?
- stored-procedures - 如何在存储过程语法“调用 <
>.storedproceduretask() - c++ - Cuda 动态并行和递归性能
- python - 对 python is 运算符感到困惑
- cordova - 科尔多瓦的问题:屏幕闪烁,不显示 PNG 图像