我正在尝试将Visibility
LayoutAnchorableItem
绑定到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)
...
在注释掉可见性的绑定后,可以按预期隐藏可锚定。
答案 0 :(得分:5)
您需要在绑定中添加ConverterParameter
值Visibility.Hidden
:
<Setter Property="Visibility" Value="{Binding Model.IsVisible, ConverterParameter={x:Static Visibility.Hidden}, Converter={StaticResource btvc}, Mode=TwoWay}"/>
转换器参数是布尔值为Visibility
时返回的false
,而Hidden
表示可锚定隐藏。
如果我们查看LayoutContent.Close()
,则会在评论中标记:
请注意,通常只能隐藏(不关闭)可锚定。默认情况下,当用户单击X按钮时,它仅隐藏内容。
所以这不应该被调用。查看堆栈跟踪,从:
调用// LayoutItem class.
protected virtual void OnVisibilityChanged()
{
if (LayoutElement != null &&
Visibility == System.Windows.Visibility.Collapsed)
LayoutElement.Close();
}
根据Microsoft的说法,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}"/>