[2.0 Hints] Save/Load Layout & Content

Jan 7, 2013 at 4:05 AM
Edited Jan 7, 2013 at 4:05 AM

So I was banging my head against the wall trying to get things to work correctly with save and load. I could get the layout to load but all the content was empty.  In order for content to load correct your content must have a Name.  The serialize doesn't check for valid names so make sure it is Alphanumeric, there are a few other symbols you can use like _ also.

Also you must call the Load function after your the window is loaded and all you content has been assigned. It is my understanding that all the Avalon Dock XmlLayoutSerializer does is resize the windows for the existing content.

This is my save Method:

private void SaveSettings()
{
	//Update Avalon Layout
	using (var memoryStream = new MemoryStream())
	{
		new XmlLayoutSerializer(dockingManager_main).Serialize(memoryStream);
		memoryStream.Seek(0, SeekOrigin.Begin);
		var layout = new StreamReader(memoryStream).ReadToEnd();
		Settings.Default.AvalonDockLayout = layout;
	}

	//TODO: Use/moveTo lib.FileSystem???
	FileStream fs = new FileStream(settingsFile, FileMode.Create);
	IFormatter formatter = new BinaryFormatter();
	try { formatter.Serialize(fs, Settings); }
	catch (SerializationException e)
	{
		Console.WriteLine("Failed to serialize Settings file: " + e.Message);
		throw;
	}
	finally { fs.Close(); }

	Console.WriteLine("Layout Saved: " + settingsFile);
}

 

This is my Load Method:

private void LoadSettings()
{
	//TODO: Use lib.FileSystem???
	FileStream fs = new FileStream(settingsFile, FileMode.Open);
	try
	{
		BinaryFormatter formatter = new BinaryFormatter();
		Settings = (WPFSettings)formatter.Deserialize(fs);
	}
	catch (SerializationException e)
	{
		Console.WriteLine("Failed to deserialize Settings file: " + e.Message);
		throw;
	}
	finally { fs.Close(); }

	// Get Avalon Layout
	var currentContentsList = dockingManager_main.Layout.Descendents().OfType<LayoutContent>().Where(c => c.ContentId != null).ToArray();
	string layout = Settings.Default.AvalonDockLayout;
	var bytes = Encoding.Default.GetBytes(layout);
	MemoryStream memoryStream = new MemoryStream();
	memoryStream.Write(bytes, 0, bytes.Length);
	memoryStream.Seek(0, SeekOrigin.Begin);
	XmlLayoutSerializer layoutSerializer = new XmlLayoutSerializer(dockingManager_main);
	layoutSerializer.LayoutSerializationCallback += (obj, arg) =>
	{
		var prevContent = currentContentsList.FirstOrDefault(c => c.ContentId == arg.Model.ContentId);
		if (prevContent != null) { arg.Content = prevContent.Content; }
	};
	layoutSerializer.Deserialize(memoryStream);

	Console.WriteLine("Layout Loaded: " + settingsFile);
}

I store my data in a settings file and use a binary serializer but you don't need to do that.   I grab part of the functionality from another questions that was on here, and there is probably a better way to do this, but it works.

Hopefully this helps some people out, if you have question let me know. If you know of a better way to do these things I am always open to learning and improvement.

Sep 17, 2013 at 10:08 AM
Edited Sep 17, 2013 at 10:11 AM
Hi Noctys

Settings.Default.AvalonDockLayout is a string?

I did the same, but in user.config the xml tag aren't saved

for example:

<setting name="DockingLayout" serializeAs="String">
            <value>&lt;?xml version="1.0"?&gt;&lt;
......
thank's all
Jan 5 at 3:12 PM
@Noctys - thanks, works out of the box.

@mirkomassi - yes, Settings.Default.AvalonDockLayout is propably a string - and it should work with that (since the StreamReader.ReadToEnd() returns a string - see the inline comment below):
using (var ms = new MemoryStream())
{
    var serializer = new XmlLayoutSerializer(DockingManager);
    serializer.Serialize(ms);
    ms.Seek(0, SeekOrigin.Begin);
    var layout = new StreamReader(ms).ReadToEnd(); // <-- Returns a string
    Properties.Settings.Default.DockingManagerLayout = layout;
    Properties.Settings.Default.Save();
}
However, to save a line or two, you could use a StringWriter instead of a MemoryStream for serialization, like this:
using (var sw = new StringWriter(new StringBuilder()))
{
    var serializer = new XmlLayoutSerializer(DockingManager);
    serializer.Serialize(sw);
    Properties.Settings.Default.DockingManagerLayout = sw.GetStringBuilder().ToString();
    Properties.Settings.Default.Save();
}
Hope that helps ;)
Jan 8 at 11:19 AM
Edited Jan 8 at 11:28 AM
Nothing, is the same.

I think because in user.config

<setting name="DockingLayout" serializeAs="String">
<value><?xml version="1.0"?>
................


instead
<setting name="DockingLayout" serializeAs="Xml">

How can i set this in project of the Settings.settings?