绑定到AvalonDock 2中的LayoutAnchorableItem可见性

时间:2014-05-12 19:55:23

标签: c# wpf avalondock

我正在尝试将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)
...

在注释掉可见性的绑定后,可以按预期隐藏可锚定。

1 个答案:

答案 0 :(得分:5)

TL;博士

您需要在绑定中添加ConverterParameterVisibility.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}"/>