0

I am working on MDI application with documents tabs and panels (like in Visual Studio), using AvalonDock 2 + Caliburn.Micro + Fody.PropertyChanged. I want to expand LayoutAnchorable from code (like this works in Visual Studio when you start search in project: panel with search results in bottom of screen expands automatically).

According to MVVM approach I made behavior, bound IsActive property of LAyoutAnchorable - and it doesn't work. More precisely, it works only in one direction: I received notification in ViewModel (when panel opened by user click), but I'm not able to open panel from code. Here is the code. Thanks.

View:

<xcad:LayoutRoot.BottomSide>
    <xcad:LayoutAnchorSide>
        <xcad:LayoutAnchorGroup>
                <xcad:LayoutAnchorable x:Name="ErrorsListPanel" Title="Errors List" AutoHideHeight="300">

                    <i:Interaction.Behaviors>
                        <behaviors:LayoutAnchorableBehaviour IsLayoutActive="{Binding IsErrorsListActive,
                                                            Mode=OneWay,
                                                            UpdateSourceTrigger=PropertyChanged}"/>

                    </i:Interaction.Behaviors>


                    <ListView caliburn:Message.Attach="[Event SelectionChanged] = [Action BrowseError($this)]" ItemsSource="{Binding ErrorsList}">

                        <ListView.Resources>
                            <Style TargetType="{x:Type GridViewColumnHeader}">
                                <Setter Property="HorizontalContentAlignment" Value="Left" />
                            </Style>
                        </ListView.Resources>

                        <ListView.View>
                            <GridView>

                                <GridViewColumn Width="500"
                                            DisplayMemberBinding="{Binding Path=File.RelPath}"
                                            Header="File" />

                                <GridViewColumn Width="500"
                                            DisplayMemberBinding="{Binding Path=Message}"
                                            Header="Description" />
                                <GridViewColumn Width="50"
                                            DisplayMemberBinding="{Binding Path=Line}"
                                            Header="Line" />
                                <GridViewColumn Width="50"
                                            DisplayMemberBinding="{Binding Path=Column}"
                                            Header="Column" />
                            </GridView>
                        </ListView.View>
                    </ListView>

                </xcad:LayoutAnchorable>
...
....

Behavior:

public sealed class LayoutAnchorableBehaviour : Behavior<LayoutAnchorable>
{
    public static readonly DependencyProperty IsLayoutActiveProperty =
        DependencyProperty.Register("IsLayoutActive", typeof(bool), typeof(LayoutAnchorableBehaviour),
        new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
            (dependencyObject, dependencyPropertyChangedEventArgs) =>
            {
                var behavior = dependencyObject as LayoutAnchorableBehaviour;
                var layout = behavior?.AssociatedObject as LayoutAnchorable;
                if (layout == null) return;
                layout.IsActive = (bool) dependencyPropertyChangedEventArgs.NewValue;

            }));

    public bool IsLayoutActive
    {
        get { return (bool)GetValue(IsLayoutActiveProperty); }
        set { SetValue(IsLayoutActiveProperty, value); }
    }


    protected override void OnAttached()
    {
        base.OnAttached();
        if (AssociatedObject != null)
        {
            AssociatedObject.IsActiveChanged += AssociatedObject_IsActiveChanged;
        }
    }

    private void AssociatedObject_IsActiveChanged(object sender, EventArgs e)
    {
        var layout = sender as LayoutAnchorable;
        if (layout != null)
        {
            IsLayoutActive = layout.IsActive;
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        if (AssociatedObject != null)
        {
            AssociatedObject.IsActiveChanged -= AssociatedObject_IsActiveChanged;
        }
    }
}

ViewModel:

[ImplementPropertyChanged]
public class ProjectViewModel : Screen
{
    public bool IsErrorsListActive { get; set; }
    ...
    public void BrowseErrorsCommand()
    {
        IsErrorsListActive = true;
    }
}

UPD1: lambda-function in dependency property IsLayoutActiveProperty not calls by IsErrorsListActive = true in ViewModel. Maybe this can help.

TimeCoder
  • 175
  • 1
  • 8
  • Maybe it's stupid but did you try to change Mode=OneWay to Mode=TwoWay ? – Quentin Roger Sep 14 '16 at 09:55
  • Yep, I did. The same. – TimeCoder Sep 14 '16 at 09:57
  • So maybe `LayoutAnchorable` can't be opened like this and you should get the `DocumentManager` instance and call `layout.Show(dockManager);` when `dependencyPropertyChangedEventArgs.NewValue` is true – Quentin Roger Sep 14 '16 at 10:05
  • It is strange. By the way, just for test I've added button and wrote in code-behind event this code: SomeNameOfLayoutAnchorableObject.IsActive = true; It works fine. Why very similar thing doesn't work inside behavior? I know half of answer: because IsActive doesn't populated inside behavior. Lambda-function in dependency property IsLayoutActiveProperty not fired on IsErrorsListActive = true; in ViewModel. But why? – TimeCoder Sep 14 '16 at 10:12
  • 1
    In the [doc](https://xceed.com/wp-content/documentation/xceed-toolkit-plus-for-wpf/Xceed.Wpf.AvalonDock~Xceed.Wpf.AvalonDock.Layout.LayoutDocument_properties.html) IsActive property have only a getter (Gets whether the content is active). So maybe you can try with another property like IsEnabled. But it's really weird that is working with the code-behind you tried – Quentin Roger Sep 14 '16 at 10:18
  • LayoutDocument - this is another class, not LayoutAnchorable. If its IsActive wouldn't have setter, my code not compiled. – TimeCoder Sep 14 '16 at 10:24
  • Can you try to implement INotifyPropertyChanged manually without [ImplementPropertyChanged] and try to put a breakpoint inside the setter ? – Quentin Roger Sep 14 '16 at 11:38

0 Answers0