在AvalonDock中绑定layoutanchoritemvisibility
本文关键字:layoutanchoritemvisibility 绑定 AvalonDock | 更新日期: 2023-09-27 18:03:03
我试图将LayoutAnchorableItem
的Visibility
绑定到ViewModel中的布尔值,以便我可以以编程方式显示和隐藏可锚定的:
<UserControl.Resources>
<avalon:BoolToVisibilityConverter x:Key="btvc"/>
</UserControl.Resources>
<avalon:DockingManager>
<avalon:DockingManager.LayoutItemContainerStyleSelector>
<ws:WorkspaceStyleSelector>
<ws:WorkspaceStyleSelector.AnchorableStyle>
<Style TargetType="{x:Type avalon:LayoutAnchorableItem}">
<!-- ... -->
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Converter={StaticResource btvc}, Mode=TwoWay}"/>
</Style>
</ws:WorkspaceStyleSelector.AnchorableStyle>
</ws:WorkspaceStyleSelector>
</avalon:DockingManager.LayoutItemContainerStyleSelector>
<!-- ... -->
</avalon:DockingManager>
但是,每当我隐藏一个可锚定对象时,就会抛出一个异常:
对象引用未设置为实例。
at Xceed.Wpf.AvalonDock.Layout.LayoutContent.Close() in ...'Xceed.Wpf.AvalonDock'Layout'LayoutContent.cs:line 346
at Xceed.Wpf.AvalonDock.Controls.LayoutItem.OnVisibilityChanged() in ...'Xceed.Wpf.AvalonDock'Controls'LayoutItem.cs:line 310
at Xceed.Wpf.AvalonDock.Controls.LayoutAnchorableItem.OnVisibilityChanged() in ...'Xceed.Wpf.AvalonDock'Controls'LayoutAnchorableItem.cs:line 299
at Xceed.Wpf.AvalonDock.Controls.LayoutItem.OnVisibilityChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) in ...'Xceed.Wpf.AvalonDock'Controls'LayoutItem.cs:line 303
at Xceed.Wpf.AvalonDock.Controls.LayoutItem.<.cctor>b__1(DependencyObject s, DependencyPropertyChangedEventArgs e) in ...'Xceed.Wpf.AvalonDock'Controls'LayoutItem.cs:line 37
at System.Windows.PropertyChangedCallback.Invoke(DependencyObject d, DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
...
在注释掉绑定到可见性之后,锚定被隐藏。
br
需要在Binding中添加值为Visibility.Hidden
的ConverterParameter
:
<Setter Property="Visibility" Value="{Binding Model.IsVisible, ConverterParameter={x:Static Visibility.Hidden}, Converter={StaticResource btvc}, Mode=TwoWay}"/>
转换器参数为布尔值为false
时返回的Visibility
, Hidden
表示隐藏可锚定项。
完整的答案
如果我们看一下LayoutContent.Close()
,它被标记为注释:
请注意,锚定通常只是隐藏(不关闭)。默认情况下,当用户单击X按钮时,它只隐藏内容。
所以这个不应该被调用。看看堆栈跟踪,这是从:
// LayoutItem class.
protected virtual void OnVisibilityChanged()
{
if (LayoutElement != null &&
Visibility == System.Windows.Visibility.Collapsed)
LayoutElement.Close();
}
根据微软的说法,System.Windows.Visibility.Collapsed
意味着该项目是不可见的,并且在布局期间不为它保留空间。这听起来就像当我们点击X
隐藏锚点时发生的事情(这可能发生在视觉树的某个地方)。但是为什么评论说这通常不被称为主播呢?如果我们看LayoutAnchorableItem.OnVisibilityChanged()
:
protected override void OnVisibilityChanged()
{
if (_anchorable != null && _anchorable.Root != null)
{
if (_visibilityReentrantFlag.CanEnter)
{
using (_visibilityReentrantFlag.Enter())
{
if (Visibility == System.Windows.Visibility.Hidden)
_anchorable.Hide(false);
else if (Visibility == System.Windows.Visibility.Visible)
_anchorable.Show();
}
}
}
base.OnVisibilityChanged();
}
很明显,AvalonDock使用Visibility.Hidden
值来表示可锚定是隐藏的。(这对我来说有点困惑,因为微软说Hidden
隐藏了元素,但在布局中保留了空间,这不是当你隐藏它时锚定的行为。)那么为什么可见度是Collapsed
而不是Hidden
呢?答案就在BoolToVisibilityConverter
中。
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool && targetType == typeof(Visibility))
{
bool val = (bool)value;
if (val)
return Visibility.Visible;
else
if (parameter != null && parameter is Visibility)
return parameter;
else
return Visibility.Collapsed;
}
// ...
}
除非传递Visibility
类型的参数,否则当布尔值为false时使用Visibility.Collapsed
。我们想让false表示Visibility.Hidden
所以我们把它设置为ConverterParameter
<Setter Property="Visibility" Value="{Binding Model.IsVisible, ConverterParameter={x:Static Visibility.Hidden}, Converter={StaticResource btvc}, Mode=TwoWay}"/>