diff --git a/source/.idea/.idea.AvalonDock/.idea/.gitignore b/source/.idea/.idea.AvalonDock/.idea/.gitignore
new file mode 100644
index 00000000..ad8aa732
--- /dev/null
+++ b/source/.idea/.idea.AvalonDock/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/modules.xml
+/.idea.AvalonDock.iml
+/contentModel.xml
+/projectSettingsUpdater.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/source/.idea/.idea.AvalonDock/.idea/.name b/source/.idea/.idea.AvalonDock/.idea/.name
new file mode 100644
index 00000000..d257d125
--- /dev/null
+++ b/source/.idea/.idea.AvalonDock/.idea/.name
@@ -0,0 +1 @@
+AvalonDock
\ No newline at end of file
diff --git a/source/.idea/.idea.AvalonDock/.idea/aws.xml b/source/.idea/.idea.AvalonDock/.idea/aws.xml
new file mode 100644
index 00000000..b63b642c
--- /dev/null
+++ b/source/.idea/.idea.AvalonDock/.idea/aws.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/.idea/.idea.AvalonDock/.idea/encodings.xml b/source/.idea/.idea.AvalonDock/.idea/encodings.xml
new file mode 100644
index 00000000..df87cf95
--- /dev/null
+++ b/source/.idea/.idea.AvalonDock/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/source/.idea/.idea.AvalonDock/.idea/indexLayout.xml b/source/.idea/.idea.AvalonDock/.idea/indexLayout.xml
new file mode 100644
index 00000000..7b08163c
--- /dev/null
+++ b/source/.idea/.idea.AvalonDock/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/.idea/.idea.AvalonDock/.idea/misc.xml b/source/.idea/.idea.AvalonDock/.idea/misc.xml
new file mode 100644
index 00000000..1d8c84d0
--- /dev/null
+++ b/source/.idea/.idea.AvalonDock/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/.idea/.idea.AvalonDock/.idea/vcs.xml b/source/.idea/.idea.AvalonDock/.idea/vcs.xml
new file mode 100644
index 00000000..6c0b8635
--- /dev/null
+++ b/source/.idea/.idea.AvalonDock/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/AvalonDock.sln.DotSettings b/source/AvalonDock.sln.DotSettings
new file mode 100644
index 00000000..5693e73d
--- /dev/null
+++ b/source/AvalonDock.sln.DotSettings
@@ -0,0 +1,3 @@
+
+ True
+ True
\ No newline at end of file
diff --git a/source/Components/AvalonDock.Themes.Aero/AvalonDock.Themes.Aero.csproj b/source/Components/AvalonDock.Themes.Aero/AvalonDock.Themes.Aero.csproj
index d1698281..049fd762 100644
--- a/source/Components/AvalonDock.Themes.Aero/AvalonDock.Themes.Aero.csproj
+++ b/source/Components/AvalonDock.Themes.Aero/AvalonDock.Themes.Aero.csproj
@@ -1,7 +1,7 @@
AvalonDock.Themes
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
sn.snk
true
diff --git a/source/Components/AvalonDock.Themes.Expression/AvalonDock.Themes.Expression.csproj b/source/Components/AvalonDock.Themes.Expression/AvalonDock.Themes.Expression.csproj
index a27eb523..61b82fbd 100644
--- a/source/Components/AvalonDock.Themes.Expression/AvalonDock.Themes.Expression.csproj
+++ b/source/Components/AvalonDock.Themes.Expression/AvalonDock.Themes.Expression.csproj
@@ -1,7 +1,7 @@
AvalonDock.Themes
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
sn.snk
true
diff --git a/source/Components/AvalonDock.Themes.Metro/AvalonDock.Themes.Metro.csproj b/source/Components/AvalonDock.Themes.Metro/AvalonDock.Themes.Metro.csproj
index 14703b6c..074363cd 100644
--- a/source/Components/AvalonDock.Themes.Metro/AvalonDock.Themes.Metro.csproj
+++ b/source/Components/AvalonDock.Themes.Metro/AvalonDock.Themes.Metro.csproj
@@ -1,7 +1,7 @@
AvalonDock.Themes
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
sn.snk
true
diff --git a/source/Components/AvalonDock.Themes.VS2010/AvalonDock.Themes.VS2010.csproj b/source/Components/AvalonDock.Themes.VS2010/AvalonDock.Themes.VS2010.csproj
index d466dd1a..1bc2d6ac 100644
--- a/source/Components/AvalonDock.Themes.VS2010/AvalonDock.Themes.VS2010.csproj
+++ b/source/Components/AvalonDock.Themes.VS2010/AvalonDock.Themes.VS2010.csproj
@@ -1,7 +1,7 @@
AvalonDock.Themes
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
sn.snk
true
diff --git a/source/Components/AvalonDock.Themes.VS2013/AvalonDock.Themes.VS2013.csproj b/source/Components/AvalonDock.Themes.VS2013/AvalonDock.Themes.VS2013.csproj
index 00e53323..d5bb6832 100644
--- a/source/Components/AvalonDock.Themes.VS2013/AvalonDock.Themes.VS2013.csproj
+++ b/source/Components/AvalonDock.Themes.VS2013/AvalonDock.Themes.VS2013.csproj
@@ -1,7 +1,7 @@
AvalonDock.Themes
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
sn.snk
true
diff --git a/source/Components/AvalonDock/AvalonDock.csproj b/source/Components/AvalonDock/AvalonDock.csproj
index 64cd7486..9836e302 100644
--- a/source/Components/AvalonDock/AvalonDock.csproj
+++ b/source/Components/AvalonDock/AvalonDock.csproj
@@ -1,7 +1,7 @@
AvalonDock
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
true
sn.snk
diff --git a/source/Components/AvalonDock/Layout/ILayoutPaneSerializable.cs b/source/Components/AvalonDock/Layout/ILayoutPaneSerializable.cs
index e8fcc66c..9f541559 100644
--- a/source/Components/AvalonDock/Layout/ILayoutPaneSerializable.cs
+++ b/source/Components/AvalonDock/Layout/ILayoutPaneSerializable.cs
@@ -1,4 +1,4 @@
-/************************************************************************
+/************************************************************************
AvalonDock
Copyright (C) 2007-2013 Xceed Software Inc.
@@ -10,7 +10,7 @@ This program is provided to you under the terms of the Microsoft Public
namespace AvalonDock.Layout
{
/// Interface definition for a layout pane that can be identified by a unique id.
- internal interface ILayoutPaneSerializable
+ public interface ILayoutPaneSerializable
{
/// Gets/sets the unique id for this layout pane.
string Id { get; set; }
diff --git a/source/Components/AvalonDock/Layout/ILayoutPositionableElement.cs b/source/Components/AvalonDock/Layout/ILayoutPositionableElement.cs
index 29f8ddc6..277cb81d 100644
--- a/source/Components/AvalonDock/Layout/ILayoutPositionableElement.cs
+++ b/source/Components/AvalonDock/Layout/ILayoutPositionableElement.cs
@@ -1,4 +1,4 @@
-/************************************************************************
+/************************************************************************
AvalonDock
Copyright (C) 2007-2013 Xceed Software Inc.
@@ -12,7 +12,7 @@ This program is provided to you under the terms of the Microsoft Public
namespace AvalonDock.Layout
{
/// Defines a layout element that can be positioned in a Grid like environment.
- internal interface ILayoutPositionableElement : ILayoutElement, ILayoutElementForFloatingWindow
+ public interface ILayoutPositionableElement : ILayoutElement, ILayoutElementForFloatingWindow
{
/// Gets/sets the of the dock width for this positionable layout element.
GridLength DockWidth { get; set; }
@@ -52,7 +52,7 @@ internal interface ILayoutPositionableElement : ILayoutElement, ILayoutElementFo
}
/// Defines a layout element that supports actual width and height properties.
- internal interface ILayoutPositionableElementWithActualSize : ILayoutPositionableElement
+ public interface ILayoutPositionableElementWithActualSize : ILayoutPositionableElement
{
/// Gets/sets the actual width the positionable layout element.
double ActualWidth { get; set; }
@@ -62,7 +62,7 @@ internal interface ILayoutPositionableElementWithActualSize : ILayoutPositionabl
}
/// Defines a layout element that supports position properties for a floating window.
- internal interface ILayoutElementForFloatingWindow
+ public interface ILayoutElementForFloatingWindow
{
/// Invoke this method to raise the FloatingPropertiesUpdated event to inform subscribers of the change.
void RaiseFloatingPropertiesUpdated();
diff --git a/source/Components/AvalonDock/Layout/ILayoutPreviousContainer.cs b/source/Components/AvalonDock/Layout/ILayoutPreviousContainer.cs
index afab0935..fae84019 100644
--- a/source/Components/AvalonDock/Layout/ILayoutPreviousContainer.cs
+++ b/source/Components/AvalonDock/Layout/ILayoutPreviousContainer.cs
@@ -1,4 +1,4 @@
-/************************************************************************
+/************************************************************************
AvalonDock
Copyright (C) 2007-2013 Xceed Software Inc.
@@ -9,7 +9,7 @@ This program is provided to you under the terms of the Microsoft Public
namespace AvalonDock.Layout
{
- internal interface ILayoutPreviousContainer
+ public interface ILayoutPreviousContainer
{
ILayoutContainer PreviousContainer { get; set; }
diff --git a/source/Components/AvalonDock/Layout/Serialization/AsyncXmlLayoutSerializer.cs b/source/Components/AvalonDock/Layout/Serialization/AsyncXmlLayoutSerializer.cs
new file mode 100644
index 00000000..849ebf7e
--- /dev/null
+++ b/source/Components/AvalonDock/Layout/Serialization/AsyncXmlLayoutSerializer.cs
@@ -0,0 +1,146 @@
+/************************************************************************
+ AvalonDock
+
+ Copyright (C) 2007-2013 Xceed Software Inc.
+
+ This program is provided to you under the terms of the Microsoft Public
+ License (Ms-PL) as published at https://opensource.org/licenses/MS-PL
+ ************************************************************************/
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Serialization;
+
+namespace AvalonDock.Layout.Serialization
+{
+ ///
+ /// Implements a layout serialization/deserialization method of the docking framework.
+ ///
+ ///
+ ///
+ /// private void Serialize()
+ /// {
+ /// // The serialization is not done async as the XmlSerializer used is not having async overloads
+ /// var serializer = new AvalonDock.Layout.Serialization.AsyncXmlLayoutSerializer(dockManager);
+ /// serializer.Serialize(@".\AvalonDock.config");
+ /// }
+ ///
+ ///
+ ///
+ ///
+ /// private async Task DeserializeAsync(AvalonDock.DockingManager dockManager)
+ /// {
+ /// using (var serializer = new AvalonDock.Layout.Serialization.AsyncXmlLayoutSerializer(dockManager))
+ /// {
+ /// serializer.LayoutRestore += async (s, args) =>
+ /// {
+ /// // Emulate an async operation for this
+ /// await Task.Delay(1000);
+ /// // Required for each interaction with actual AvalonDock, as these are STA components
+ /// await Dispatcher.InvokeAsync(() => args.Content = args.Content);
+ /// };
+ /// if (File.Exists(@".\AvalonDock.config"))
+ /// await serializer.DeserializeAsync(@".\AvalonDock.config");
+ /// }
+ /// }
+ ///
+ ///
+ public class AsyncXmlLayoutSerializer : LayoutSerializerBase
+ {
+ #region Constructors
+
+ ///
+ /// Class constructor from instance.
+ ///
+ ///
+ public AsyncXmlLayoutSerializer(DockingManager manager)
+ : base(manager)
+ {
+ }
+
+ #endregion Constructors
+
+
+ #region Private Methods
+
+ /// Performs all required actions for deserialization.
+ ///
+ /// A function, receiving the ,
+ /// that is supposed to call a deserialize method.
+ ///
+ private Task DeserializeCommonAsync(Func function)
+ => base.DeserializeCommonAsync(() =>
+ {
+ var serializer = XmlSerializer.FromTypes(new[] {typeof(LayoutRoot)}).First();
+ return function(serializer);
+ });
+
+ #endregion
+
+ #region Public Methods
+
+ /// Serialize the layout into a .
+ ///
+ public void Serialize(XmlWriter writer)
+ {
+ var serializer = new XmlSerializer(typeof(LayoutRoot));
+ serializer.Serialize(writer, Manager.Layout);
+ }
+
+ /// Serialize the layout into a .
+ ///
+ public void Serialize(TextWriter writer)
+ {
+ var serializer = new XmlSerializer(typeof(LayoutRoot));
+ serializer.Serialize(writer, Manager.Layout);
+ }
+
+ /// Serialize the layout into a .
+ ///
+ public void Serialize(Stream stream)
+ {
+ var serializer = new XmlSerializer(typeof(LayoutRoot));
+ serializer.Serialize(stream, Manager.Layout);
+ }
+
+ /// Serialize the layout into a file using a .
+ ///
+ public void Serialize(string filepath)
+ {
+ using (var stream = new StreamWriter(filepath))
+ {
+ Serialize(stream);
+ }
+ }
+
+ /// Deserialize the layout a file from a .
+ ///
+ public Task DeserializeAsync(Stream stream)
+ => DeserializeCommonAsync((xmlSerializer) => (LayoutRoot) xmlSerializer.Deserialize(stream));
+
+ /// Deserialize the layout a file from a .
+ ///
+ public Task DeserializeAsync(TextReader reader)
+ => DeserializeCommonAsync((xmlSerializer) => (LayoutRoot) xmlSerializer.Deserialize(reader));
+
+ /// Deserialize the layout a file from a .
+ ///
+ public Task DeserializeAsync(XmlReader reader)
+ => DeserializeCommonAsync((xmlSerializer) => (LayoutRoot) xmlSerializer.Deserialize(reader));
+
+ /// Deserialize the layout from a file using a .
+ ///
+ public async Task DeserializeAsync(string filepath)
+ {
+ using (var stream = new StreamReader(filepath))
+ {
+ await DeserializeAsync(stream);
+ }
+ }
+
+ #endregion Public Methods
+ }
+}
\ No newline at end of file
diff --git a/source/Components/AvalonDock/Layout/Serialization/LayoutRestoreEventArgs.cs b/source/Components/AvalonDock/Layout/Serialization/LayoutRestoreEventArgs.cs
new file mode 100644
index 00000000..d97dbf31
--- /dev/null
+++ b/source/Components/AvalonDock/Layout/Serialization/LayoutRestoreEventArgs.cs
@@ -0,0 +1,76 @@
+/************************************************************************
+ AvalonDock
+
+ Copyright (C) 2007-2013 Xceed Software Inc.
+
+ This program is provided to you under the terms of the Microsoft Public
+ License (Ms-PL) as published at https://opensource.org/licenses/MS-PL
+ ************************************************************************/
+
+using System.ComponentModel;
+
+namespace AvalonDock.Layout.Serialization
+{
+ ///
+ /// Implements an event that can be used to communicate between deserialization method
+ /// and client application that a new item (LayoutAnchorable or Document) is about to
+ /// be constructed and should be attached to a corresponding viewmodel.
+ ///
+ /// The client application can use this event to Cancel reloading the item or
+ /// attach (a viewmodel) content to the view item that is about to be reloaded and presented in the UI.
+ ///
+ /// Use the Cancel property to indicate the case in which an item should not be deserialized.
+ ///
+ public class LayoutRestoreEventArgs
+ {
+ #region constructors
+
+ ///
+ /// Class constructor from and object.
+ ///
+ /// The model of the view that has been deserialized.
+ /// The content if it was available in previous layout.
+ public LayoutRestoreEventArgs(LayoutContent model, object previousContent)
+ {
+ Cancel = false; // reloading an item is not by cancelled by default
+ Handled = false; // an item is not handled by default
+ Model = model;
+ Content = previousContent;
+ }
+
+ #endregion constructors
+
+ #region Properties
+
+ ///
+ /// Gets or sets a value indicating whether the event should be canceled.
+ ///
+ public bool Cancel
+ {
+ get; private set;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the event should continue processing.
+ ///
+ public bool Handled
+ {
+ get; private set;
+ }
+
+ ///
+ /// Gets the model of the view that is about to be deserialized.
+ ///
+ public LayoutContent Model
+ {
+ get; private set;
+ }
+
+ ///
+ /// Gets/sets the content for the that is about to be deserialized.
+ ///
+ public object Content { get; set; }
+
+ #endregion Properties
+ }
+}
\ No newline at end of file
diff --git a/source/Components/AvalonDock/Layout/Serialization/LayoutSerializationCallbackEventArgs.cs b/source/Components/AvalonDock/Layout/Serialization/LayoutSerializationCallbackEventArgs.cs
index 976d1d0e..cb8d48bc 100644
--- a/source/Components/AvalonDock/Layout/Serialization/LayoutSerializationCallbackEventArgs.cs
+++ b/source/Components/AvalonDock/Layout/Serialization/LayoutSerializationCallbackEventArgs.cs
@@ -1,4 +1,4 @@
-/************************************************************************
+/************************************************************************
AvalonDock
Copyright (C) 2007-2013 Xceed Software Inc.
@@ -7,6 +7,7 @@ This program is provided to you under the terms of the Microsoft Public
License (Ms-PL) as published at https://opensource.org/licenses/MS-PL
************************************************************************/
+using System;
using System.ComponentModel;
namespace AvalonDock.Layout.Serialization
@@ -21,6 +22,7 @@ namespace AvalonDock.Layout.Serialization
///
/// Use the Cancel property to indicate the case in which an item should not be deserialized.
///
+ [Obsolete("The class utilizing this event got replaced.")]
public class LayoutSerializationCallbackEventArgs : CancelEventArgs
{
#region constructors
diff --git a/source/Components/AvalonDock/Layout/Serialization/LayoutSerializerBase.cs b/source/Components/AvalonDock/Layout/Serialization/LayoutSerializerBase.cs
new file mode 100644
index 00000000..285359e0
--- /dev/null
+++ b/source/Components/AvalonDock/Layout/Serialization/LayoutSerializerBase.cs
@@ -0,0 +1,325 @@
+/************************************************************************
+ AvalonDock
+
+ Copyright (C) 2007-2013 Xceed Software Inc.
+
+ This program is provided to you under the terms of the Microsoft Public
+ License (Ms-PL) as published at https://opensource.org/licenses/MS-PL
+ ************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Threading;
+
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable MemberCanBeProtected.Global
+
+namespace AvalonDock.Layout.Serialization
+{
+ /// Implements a base class for the layout serialization/deserialization of the docking framework.
+ public abstract class LayoutSerializerBase : IDisposable
+ {
+ #region Properties
+
+ #region PreviousAnchorables
+
+ protected IEnumerable PreviousAnchorables => _previousAnchorables;
+ private readonly LayoutAnchorable[] _previousAnchorables = null;
+
+ #endregion PreviousAnchorables
+
+ #region PreviousDocuments
+
+ protected IEnumerable PreviousDocuments => _previousDocuments;
+ private readonly LayoutDocument[] _previousDocuments = null;
+
+ #endregion PreviousDocuments
+
+ #endregion fields
+
+ #region Constructors
+
+ ///
+ /// Class constructor from instance.
+ ///
+ ///
+ protected LayoutSerializerBase(DockingManager manager) : this(manager, Application.Current.Dispatcher)
+ {
+ }
+
+ ///
+ /// Class constructor from instance.
+ ///
+ ///
+ /// A that dispatches to the STA thread.
+ protected LayoutSerializerBase(DockingManager manager, Dispatcher staDispatcher)
+ {
+ Manager = manager ?? throw new ArgumentNullException(nameof(manager));
+ Manager.SuspendDocumentsSourceBinding = true;
+ Manager.SuspendAnchorablesSourceBinding = true;
+
+ _previousAnchorables = Manager.Layout.Descendents().OfType().ToArray();
+ _previousDocuments = Manager.Layout.Descendents().OfType().ToArray();
+ _layoutRestore = new List();
+ Dispatcher = staDispatcher;
+ }
+
+ #endregion Constructors
+
+ #region Delegates
+
+ ///
+ /// Method descriptor for .
+ ///
+ /// The layout serializer.
+ /// An instance of that allows to cancel the creation and/or the further processing.
+ ///
+ public delegate Task LayoutRestoreDelegate(object sender, LayoutRestoreEventArgs e);
+
+ #endregion
+
+ #region Events
+
+ ///
+ /// Raises an event when the layout serializer is about to deserialize an item to ask the
+ /// client application whether the item should be deserialized and re-displayed and what content
+ /// should be used if so.
+ ///
+ public event LayoutRestoreDelegate LayoutRestore
+ {
+ add => _layoutRestore.Add(value);
+ remove => _layoutRestore.Remove(value);
+ }
+
+ private readonly List _layoutRestore;
+
+ #endregion Events
+
+ #region Properties
+
+ ///
+ /// Gets the root of the docking library.
+ ///
+ public DockingManager Manager { get; }
+
+ protected Dispatcher Dispatcher { get; }
+
+ #endregion Properties
+
+ #region Private Methods
+
+
+ private static IEnumerable GetDescendentsWithPreviousContainerId(LayoutRoot layoutRoot)
+ {
+ return layoutRoot
+ .Descendents()
+ .OfType()
+ .Where(lc => lc.PreviousContainerId != null);
+ }
+ private static IEnumerable GetDescendentsWithoutContent(LayoutRoot layout)
+ where T : LayoutContent
+ {
+ return layout
+ .Descendents()
+ .OfType()
+ .Where(lc => lc.Content == null);
+ }
+
+ private async Task HandleLayoutRestoreFallbackAsync(
+ LayoutContent previousContent,
+ LayoutContent lcToFix,
+ Action onPreviousContentNull)
+ {
+ if (previousContent == null)
+ {
+ await Dispatcher.InvokeAsync(onPreviousContentNull);
+ }
+ else
+ {
+ lcToFix.Content = previousContent.Content;
+ lcToFix.IconSource = previousContent.IconSource;
+ }
+ }
+
+ private Task HandleLayoutRestoreFallbackOfAnchorableAsync(
+ LayoutAnchorable previousAnchorable,
+ LayoutAnchorable lcToFix)
+ => HandleLayoutRestoreFallbackAsync(
+ previousAnchorable,
+ lcToFix,
+ () => lcToFix.Hide(false));
+ private Task HandleLayoutRestoreFallbackOfDocument(
+ LayoutDocument previousAnchorable,
+ LayoutDocument lcToFix)
+ => HandleLayoutRestoreFallbackAsync(
+ previousAnchorable,
+ lcToFix,
+ // ReSharper disable once ConvertClosureToMethodGroup
+ () => lcToFix.Close());
+
+ private async Task TryHandleLayoutRestoreByUserCallbackAsync(
+ LayoutContent previousContent,
+ LayoutContent lcToFix,
+ Action onNoContentAvailable)
+ {
+ if (!_layoutRestore.Any())
+ return false;
+ // Ask client application via callback if item should be deserialized
+ var eventArgs = await RaiseLayoutRestoreAsync(lcToFix, previousContent);
+ // Close anchorable if client app decided to cancel it
+ if (eventArgs.Cancel)
+ {
+ await Dispatcher.InvokeAsync(lcToFix.Close);
+ }
+ // update anchorable content if client provided content
+ else if (eventArgs.Content != null)
+ {
+ await Dispatcher.InvokeAsync(() => lcToFix.Content = eventArgs.Content);
+ }
+ // If client has not provided any content and
+ // has not explicitly set the content on the LayoutContent
+ // then hide the anchorable
+ else if (eventArgs.Model.Content != null)
+ {
+ await Dispatcher.InvokeAsync(onNoContentAvailable);
+ }
+
+ return true;
+ }
+
+ private Task TryHandleLayoutRestoreOfAnchorableByUserCallbackAsync(
+ LayoutAnchorable previousAnchorable,
+ LayoutAnchorable lcToFix)
+ => TryHandleLayoutRestoreByUserCallbackAsync(
+ previousAnchorable,
+ lcToFix,
+ () => lcToFix.Hide(false));
+ private Task TryHandleLayoutRestoreOfDocumentByUserCallbackAsync(
+ LayoutDocument previousDocument,
+ LayoutDocument lcToFix)
+ => TryHandleLayoutRestoreByUserCallbackAsync(
+ previousDocument,
+ lcToFix,
+ // ReSharper disable once ConvertClosureToMethodGroup
+ () => lcToFix.Close());
+
+
+ private LayoutAnchorable GetPreviousAnchorableByContentIdOrDefault(string contentId)
+ => contentId != null
+ ? _previousAnchorables.FirstOrDefault(a => a.ContentId == contentId)
+ : null;
+ private LayoutDocument GetPreviousDocumentByContentIdOrDefault(string contentId)
+ => contentId != null
+ ? _previousDocuments.FirstOrDefault(a => a.ContentId == contentId)
+ : null;
+
+ #endregion Private Methods
+
+ #region Protected Methods
+
+ protected async Task RaiseLayoutRestoreAsync(
+ LayoutContent layoutContent,
+ object content)
+ {
+ var eventArgs = new LayoutRestoreEventArgs(layoutContent, content);
+ foreach (var callback in _layoutRestore)
+ {
+ await callback(this, eventArgs);
+ if (eventArgs.Cancel || eventArgs.Handled)
+ {
+ break;
+ }
+ }
+
+ return eventArgs;
+ }
+
+ /// Performs all required actions for deserialization.
+ ///
+ /// A function, returning the deserialized ,
+ /// that is supposed to call a deserialize method.
+ ///
+ protected async Task DeserializeCommonAsync(Func function)
+ {
+ var layout = function();
+ await FixupLayoutAsync(layout);
+ Manager.Layout = layout;
+ }
+
+ protected virtual void Dispose()
+ {
+ Manager.SuspendDocumentsSourceBinding = false;
+ Manager.SuspendAnchorablesSourceBinding = false;
+ }
+
+ ///
+ /// Fixes the reference after
+ /// deserializing the to point towards the matching container again.
+ ///
+ ///
+ /// Uses first occurrence where
+ /// is equivalent to .
+ ///
+ ///
+ protected virtual async Task FixupPreviousContainerReferenceAsync(LayoutRoot layoutRoot)
+ {
+ foreach (var lcToAttach in GetDescendentsWithPreviousContainerId(layoutRoot))
+ {
+ var paneContainerToAttach = layoutRoot.Descendents()
+ .OfType()
+ .FirstOrDefault(lps => lps.Id == lcToAttach.PreviousContainerId);
+ if (!(paneContainerToAttach is ILayoutContainer layoutContainer))
+ {
+ throw new ArgumentException($"Unable to find a pane with id ='{lcToAttach.PreviousContainerId}'");
+ }
+
+ await Dispatcher.InvokeAsync(() => lcToAttach.PreviousContainer = layoutContainer);
+ }
+ }
+
+ protected virtual async Task ReapplyAnchorablesContentAsync(LayoutRoot layout)
+ {
+ foreach (var lcToFix in GetDescendentsWithoutContent(layout)
+ .ToArray())
+ {
+ var previousAnchorable = GetPreviousAnchorableByContentIdOrDefault(lcToFix.ContentId);
+
+ if (await TryHandleLayoutRestoreOfAnchorableByUserCallbackAsync(previousAnchorable, lcToFix))
+ continue;
+ await HandleLayoutRestoreFallbackOfAnchorableAsync(previousAnchorable, lcToFix);
+ }
+ }
+
+ protected virtual async Task ReapplyDocumentsContentAsync(LayoutRoot layout)
+ {
+ foreach (var lcToFix in GetDescendentsWithoutContent(layout)
+ .ToArray())
+ {
+ var previousDocument = GetPreviousDocumentByContentIdOrDefault(lcToFix.ContentId);
+ if (await TryHandleLayoutRestoreOfDocumentByUserCallbackAsync(lcToFix, previousDocument))
+ continue;
+ await HandleLayoutRestoreFallbackOfDocument(previousDocument, lcToFix);
+ }
+ }
+
+ protected virtual async Task FixupLayoutAsync(LayoutRoot layout)
+ {
+ await FixupPreviousContainerReferenceAsync(layout);
+ await ReapplyAnchorablesContentAsync(layout);
+ await ReapplyDocumentsContentAsync(layout);
+
+ await Dispatcher.InvokeAsync(layout.CollectGarbage);
+ }
+
+ #endregion Methods
+
+ #region IDisposable
+
+ void IDisposable.Dispose() => this.Dispose();
+
+ #endregion IDisposable
+ }
+}
\ No newline at end of file
diff --git a/source/Components/AvalonDock/Layout/Serialization/XmlLayoutSerializer.cs b/source/Components/AvalonDock/Layout/Serialization/XmlLayoutSerializer.cs
index d883b82d..25b303e6 100644
--- a/source/Components/AvalonDock/Layout/Serialization/XmlLayoutSerializer.cs
+++ b/source/Components/AvalonDock/Layout/Serialization/XmlLayoutSerializer.cs
@@ -7,6 +7,7 @@ This program is provided to you under the terms of the Microsoft Public
License (Ms-PL) as published at https://opensource.org/licenses/MS-PL
************************************************************************/
+using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
diff --git a/source/MLibTest/MLibTest_Components/ServiceLocator/ServiceLocator.csproj b/source/MLibTest/MLibTest_Components/ServiceLocator/ServiceLocator.csproj
index df8ec47c..6b233fe7 100644
--- a/source/MLibTest/MLibTest_Components/ServiceLocator/ServiceLocator.csproj
+++ b/source/MLibTest/MLibTest_Components/ServiceLocator/ServiceLocator.csproj
@@ -1,7 +1,7 @@
- netcoreapp3.0;net5.0;net45
+ netcoreapp3.0;net5.0;net452
diff --git a/source/MVVMTestApp/MVVMTestApp.csproj b/source/MVVMTestApp/MVVMTestApp.csproj
index 79c5b073..3d59990e 100644
--- a/source/MVVMTestApp/MVVMTestApp.csproj
+++ b/source/MVVMTestApp/MVVMTestApp.csproj
@@ -2,7 +2,7 @@
WinExe
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
diff --git a/source/MVVMTestApp/MainWindow.xaml.cs b/source/MVVMTestApp/MainWindow.xaml.cs
index 61e03632..9d20f739 100644
--- a/source/MVVMTestApp/MainWindow.xaml.cs
+++ b/source/MVVMTestApp/MainWindow.xaml.cs
@@ -1,4 +1,5 @@
using System.IO;
+using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
@@ -22,21 +23,50 @@ public MainWindow()
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
+ {
+ Deserialize();
+ // await DeserializeAsync();
+ }
+
+ private void Deserialize()
{
var serializer = new AvalonDock.Layout.Serialization.XmlLayoutSerializer(dockManager);
- serializer.LayoutSerializationCallback += (s, args) =>
- {
- args.Content = args.Content;
- };
+ serializer.LayoutSerializationCallback += (s, args) => { args.Content = args.Content; };
if (File.Exists(@".\AvalonDock.config"))
serializer.Deserialize(@".\AvalonDock.config");
}
+ private async Task DeserializeAsync()
+ {
+ using (var serializer = new AvalonDock.Layout.Serialization.AsyncXmlLayoutSerializer(dockManager))
+ {
+ serializer.LayoutRestore += async (s, args) =>
+ {
+ // Emulate an async operation for this
+ await Task.Delay(1000);
+ // Required for each interaction with actual AvalonDock, as these are STA components
+ await Dispatcher.InvokeAsync(() => args.Content = args.Content);
+ };
+
+ if (File.Exists(@".\AvalonDock.config"))
+ await serializer.DeserializeAsync(@".\AvalonDock.config");
+ }
+ }
private void MainWindow_Unloaded(object sender, RoutedEventArgs e)
+ {
+ Serialize();
+ }
+
+ private void Serialize()
{
var serializer = new AvalonDock.Layout.Serialization.XmlLayoutSerializer(dockManager);
serializer.Serialize(@".\AvalonDock.config");
+
+ // AsyncXmlLayoutSerializer may also be used here, as the serialization is not done async
+ // due to the XmlSerializer used not having async overloads
+ // var serializer = new AvalonDock.Layout.Serialization.AsyncXmlLayoutSerializer(dockManager);
+ // serializer.Serialize(@".\AvalonDock.config");
}
#region LoadLayoutCommand
diff --git a/source/TestApp/TestApp.csproj b/source/TestApp/TestApp.csproj
index 95ac2e62..0b192fb3 100644
--- a/source/TestApp/TestApp.csproj
+++ b/source/TestApp/TestApp.csproj
@@ -1,7 +1,7 @@
TestApp
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
true
diff --git a/source/WinFormsTestApp/WinFormsTestApp.csproj b/source/WinFormsTestApp/WinFormsTestApp.csproj
index 05171c25..88163458 100644
--- a/source/WinFormsTestApp/WinFormsTestApp.csproj
+++ b/source/WinFormsTestApp/WinFormsTestApp.csproj
@@ -2,7 +2,7 @@
WinExe
- netcoreapp3.0;net5.0-windows;net40
+ netcoreapp3.0;net5.0-windows;net452
true
true
AvalonDock.WinFormsTestApp.Program