AvalonDock DockingManager does not load layout
Asked Answered
A

1

6

In order to save and load my layout I followed the instructions here, but it didn't work for me.

I've got this XAML inside the MainWindow:

<StackPanel Orientation="Vertical">
    <Button Content="Save"
            Click="SaveButton_Click"/>
    <Button Content="Load"
            Click="LoadButton_Click"/>
    <ad:DockingManager x:Name="myDM">
        <ad:LayoutRoot>
            <ad:LayoutPanel>
                <ad:LayoutDocumentPane>
                    <ad:LayoutDocument Title="Document">
                        <TextBox />
                    </ad:LayoutDocument>
                </ad:LayoutDocumentPane>
            </ad:LayoutPanel>
            <ad:LayoutRoot.LeftSide>
                <ad:LayoutAnchorSide>
                    <ad:LayoutAnchorGroup>
                        <ad:LayoutAnchorable Title="Left">
                            <TextBox/>
                        </ad:LayoutAnchorable>
                    </ad:LayoutAnchorGroup>
                </ad:LayoutAnchorSide>
            </ad:LayoutRoot.LeftSide>
        </ad:LayoutRoot>
    </ad:DockingManager>
</StackPanel>

And these are the event handlers for the button clicks:

private void SaveButton_Click(object sender, RoutedEventArgs e)
{
    XmlLayoutSerializer layoutSerializer = new XmlLayoutSerializer(myDM);
    using (var writer = new StreamWriter("test"))
    {
        layoutSerializer.Serialize(writer);
    }
}

private void LoadButton_Click(object sender, RoutedEventArgs e)
{
    XmlLayoutSerializer layoutSerializer = new XmlLayoutSerializer(myDM);
    using (var reader = new StreamReader("test"))
    {
        layoutSerializer.Deserialize(reader);
    }
}

After the window is shown and I click save the content of the "test" file is:

<?xml version="1.0" encoding="utf-8"?>
<LayoutRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <RootPanel Orientation="Horizontal">
    <LayoutDocumentPane>
      <LayoutDocument Title="Document" IsSelected="True" IsLastFocusedDocument="True" LastActivationTimeStamp="04/12/2013 14:50:38" />
    </LayoutDocumentPane>
  </RootPanel>
  <TopSide />
  <RightSide />
  <LeftSide>
    <LayoutAnchorGroup>
      <LayoutAnchorable AutoHideMinWidth="100" AutoHideMinHeight="100" Title="Left" />
    </LayoutAnchorGroup>
  </LeftSide>
  <BottomSide />
  <FloatingWindows />
  <Hidden />
</LayoutRoot>

Here comes the problem - after I click the load button the document and the anchorable disappear and all I can see in the window are the 2 buttons and an empty rectangle where my layout should be. At this point when I click the save button this is what is written to the "test" file:

<?xml version="1.0" encoding="utf-8"?>
<LayoutRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <RootPanel Orientation="Horizontal">
    <LayoutDocumentPane />
  </RootPanel>
  <TopSide />
  <RightSide />
  <LeftSide>
    <LayoutAnchorGroup Id="d3710e74-e6b5-4541-8b6f-554197c29dd6" />
  </LeftSide>
  <BottomSide />
  <FloatingWindows />
  <Hidden>
    <LayoutAnchorable AutoHideMinWidth="100" AutoHideMinHeight="100" Title="Left" IsSelected="True" LastActivationTimeStamp="04/12/2013 14:53:56" PreviousContainerId="d3710e74-e6b5-4541-8b6f-554197c29dd6" PreviousContainerIndex="0" />
  </Hidden>
</LayoutRoot>

I am using AvalonDock 2.0.1746.0. Anyone knows how to fix it?

Anility answered 12/4, 2013 at 12:1 Comment(0)
W
22

Edit:

I tried your code out, and compared it's output to mine, and found that your serialized file is missing the ContentId property for your LayoutDocument and LayoutAnchorable. This property is what AvalonDock uses internally to match up the existing DockingManager panels with the serialized versions, and without it, as you have seen, nothing works.

There are also 2 methods that can be used to set the ContentId property, either explicitly as a property of the specific AvalonDock panel, or implicitly by setting the Name property on the immediate child of the panel. Here is your revised main window XAML code with both ways used.

<StackPanel Orientation="Vertical">
    <Button Content="Save"
    Click="SaveButton_Click"/>
    <Button Content="Load"
    Click="LoadButton_Click"/>
    <ad:DockingManager x:Name="myDM">
        <ad:LayoutRoot>
            <ad:LayoutPanel>
                <ad:LayoutDocumentPane>
                    <ad:LayoutDocument Title="Document" ContentId="IHaveContent">
                        <TextBox />
                    </ad:LayoutDocument>
                </ad:LayoutDocumentPane>
            </ad:LayoutPanel>
            <ad:LayoutRoot.LeftSide>
                <ad:LayoutAnchorSide>
                    <ad:LayoutAnchorGroup>
                        <ad:LayoutAnchorable Title="Left">
                            <TextBox x:Name="IAmTextBoxContent"/>
                        </ad:LayoutAnchorable>
                    </ad:LayoutAnchorGroup>
                </ad:LayoutAnchorSide>
            </ad:LayoutRoot.LeftSide>
        </ad:LayoutRoot>
    </ad:DockingManager>
</StackPanel>

If you use the Save and Load buttons now, you will see the ContentId properties are now set in the test file, as below.

<?xml version="1.0" encoding="utf-8"?>
<LayoutRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <RootPanel Orientation="Horizontal">
    <LayoutDocumentPane>
      <LayoutDocument Title="Document" 
          IsSelected="True" 
          IsLastFocusedDocument="True" 
          ContentId="IHaveContent" 
          LastActivationTimeStamp="04/17/2013 09:13:35" />
    </LayoutDocumentPane>
  </RootPanel>
  <TopSide />
  <RightSide />
  <LeftSide>
    <LayoutAnchorGroup>
      <LayoutAnchorable AutoHideMinWidth="100" 
          AutoHideMinHeight="100" 
          Title="Left" 
          ContentId="IAmTextBoxContent" />
    </LayoutAnchorGroup>
  </LeftSide>
  <BottomSide />
  <FloatingWindows />
  <Hidden />
</LayoutRoot>

For future reference on how to debug this issue, I did actually use the callback below in order to debug and check the values returned by the deserialization process, where the e parameter contains the deserialized version of the AvalonDock panel in the Model property, (which in your case was originally null), and if the ContentId property is correct, will contain you panel's content in its Content property (this was also null due to the null value in the ContentId property of the Model).

The s in the callback handler contains the XmlLayoutSerializer reference, which also contains a reference to the DockingManager, through which you can inspect the current items contained within it.

Old:

I remember having a similar issue with an earlier version of the AvalonDock, but I think what fixed it for me was upgrading to the latest version (which you already have), as there was an internal part not deserializing properly.

However, to try find the issue with the deserialization process you could try putting a breakpoint in the LayoutSerializer callback. Hopefully that will give you more information as to what the particular issue is.

layoutSerializer.LayoutSerializationCallback += (s, e) =>
{
    object o = e.Content;
};
Wieldy answered 15/4, 2013 at 23:19 Comment(5)
Thank you for your answer. Do you mean I have to get the AvalonDock source and debug it?Anility
,Thanks for your answer. There's been an issue that popped-up which has higher priority and I've been working on it. When I have the time for this problem I'll look into it and possibly accept your answer.Anility
Thank you for your input. I accept your answer. Alternatively, I found another way to make it work as expected. It doesn't set ContentId or Name of the content. I just subscribe to the LayoutSerializationCallback event with empty method right before deserialization.Anility
Good to know there is more than one way to do it, as there seems to be with most things .NET related... I'll give that one a go, sounds a little easier to manage. Thanks.Wieldy
I think your approach is much cleaner, as the other one is too hacky. Anyway setting a few ContentIds isn't that much of a burden.Anility

© 2022 - 2024 — McMap. All rights reserved.