Dirkster99 / AvalonDock

Our own development branch of the well known WPF document docking library
Microsoft Public License
1.41k stars 320 forks source link

LayoutRoot.ActiveContent is null after adding an anchored document #335

Open Khaos66 opened 2 years ago

Khaos66 commented 2 years ago

There seems to be a problem with LayoutRoot.ActiveContent beeing null after adding an anchored doc.

This is what I know so far: DockingManager.AnchorablesSourceElementsChanged will create a new LayoutPanel to host both inner docs and anchored docs.

This results in this call stack

AvalonDock.dll!AvalonDock.Layout.LayoutElement.OnRootChanged(AvalonDock.Layout.ILayoutRoot oldRoot, AvalonDock.Layout.ILayoutRoot newRoot) Line 129 C#
AvalonDock.dll!AvalonDock.Layout.LayoutElement.Parent.set(AvalonDock.Layout.ILayoutContainer value) Line 81 C#
AvalonDock.dll!AvalonDock.Layout.LayoutRoot.RootPanel.set(AvalonDock.Layout.LayoutPanel value) Line 103 C#
AvalonDock.dll!AvalonDock.Layout.LayoutRoot.RemoveChild(AvalonDock.Layout.ILayoutElement element) Line 313  C#
AvalonDock.dll!AvalonDock.Layout.LayoutGroup<AvalonDock.Layout.ILayoutPanelElement>.Children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 228   C#
[External Code] 
AvalonDock.dll!AvalonDock.DockingManager.AnchorablesSourceElementsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 2444   C#

In LayoutElement.OnRootChanged the element is removed from the old root. One of the elements had to be ActiveContent on the old root. After removing the element from the old root the ActiveContent property is null, which is correct. But when adding the previous element to new new root it is not "activated" correctly, so ActiveContent will stay on its initial value of null after this.

All of this results in ActiveContext beeing null for the LayoutRoot and ActiveContextChanged not beeing fired correctly, when selecting another tab

Khaos66 commented 2 years ago

Not sure if its the best solution but this is what fixed it for me:

Replace RootPanel in LayoutRoot with this:

/// <summary>Gets/sets the root layout panel that contains the <see cref="LayoutDocumentPane"/>.</summary>
public LayoutPanel RootPanel
{
    get => _rootPanel;
    set
    {
        if (_rootPanel == value) return;
        RaisePropertyChanging(nameof(RootPanel));

        var activeContent = ActiveContent;
        var activeRoot = activeContent?.Root;

        if (_rootPanel != null && _rootPanel.Parent == this) _rootPanel.Parent = null;
        _rootPanel = value ?? new LayoutPanel(new LayoutDocumentPane());
        _rootPanel.Parent = this;

        if (ActiveContent == null && activeRoot == this && activeContent != null)
        {
            ActiveContent = activeContent;
            if (ActiveContent != activeContent)
            {
                ActiveContent = activeContent;
            }
        }

        RaisePropertyChanged(nameof(RootPanel));
    }
}

Not sure why, but setting ActiveContent once is not enough. It still is null after the first time. When called twice however the value is correctly set. I suppose some relation with DockingManager.OnLayoutRootPropertyChanged

Khaos66 commented 2 years ago

oh btw. to produce this issue you just have to add an anchorable via code to the AnchorableSource. This should trigger the issue

leo-schick commented 1 year ago

@Dirkster99 can this issue be closed? It seems to be that the PR should have fixed this issue - even tho the solution might be not so nice...

Khaos66 commented 1 year ago

Yes it's all good now đź‘Ť