I'm attempting to implement layout serialization, without breaking MVVM. I've got an implementation that's *mostly* working, but can't quite get all the nuts and bolts in place, so I wonder if I'm barking up the wrong tree. The idea is to use a Behavior to subscribe to any event that will change the layout, and provide the serialized layout string as a DependencyProperty. Here's the code:
public class LayoutSerializationBehavior : Behavior<DockSite>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.WindowActivated += AssociatedObject_LayoutUpdated;
AssociatedObject.WindowDeactivated += AssociatedObject_LayoutUpdated;
AssociatedObject.WindowsDragged += AssociatedObject_LayoutUpdated;
}
/// <summary>
/// Anytime the ToolWindow layout changes, report it to the DependencyProperty.
/// </summary>
void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
{
DockingWindow window = ((DockingWindowEventArgs)e).Window;
if ( !(window is ToolWindow) ) return;
DockSiteLayoutSerializer layoutSerializer = new DockSiteLayoutSerializer();
layoutSerializer.SerializationBehavior = DockSiteSerializationBehavior.ToolWindowsOnly;
layoutSerializer.DocumentWindowDeserializationBehavior = DockingWindowDeserializationBehavior.Discard;
layoutSerializer.ToolWindowDeserializationBehavior = DockingWindowDeserializationBehavior.Discard;
string layout = layoutSerializer.SaveToString(AssociatedObject);
SetValue(LayoutXmlProperty, layout);
}
public string LayoutXml
{
//Return the most recently deserialized XML
get
{
return (string)GetValue(LayoutXmlProperty);
}
//When we set, update DependencyProperty AND restore the layout to the DockSite
set
{
DockSiteLayoutSerializer layoutSerializer = new DockSiteLayoutSerializer();
layoutSerializer.SerializationBehavior = DockSiteSerializationBehavior.ToolWindowsOnly;
layoutSerializer.DocumentWindowDeserializationBehavior = DockingWindowDeserializationBehavior.Discard;
layoutSerializer.ToolWindowDeserializationBehavior = DockingWindowDeserializationBehavior.Discard;
layoutSerializer.LoadFromString(value, AssociatedObject);
SetValue(LayoutXmlProperty, value);
}
}
public static readonly DependencyProperty LayoutXmlProperty = DependencyProperty.Register("LayoutXml", typeof(string),
typeof(LayoutSerializationBehavior), new FrameworkPropertyMetadata(null){BindsTwoWayByDefault = true});
}
Then bind to it like:
<i:Interaction.Behaviors>
<local:LayoutSerializationBehavior LayoutXml="{Binding LayoutXml}"/>
</i:Interaction.Behaviors>
And at last the ViewModel can serialize/deserialize without needing a reference to the DockSite itself. The problem I have is getting it to update when needed, but not more. The actual LayoutUpdated event fires constantly, so serializing/deserializing with such frequency is obviously out of the question. However, I haven't been able to find a set of events that can fully handle this - for instance, when resizing a toolwindow.
So my question: is there any way to accomplish something like this in a way that doesn't result in excessive/constant serialization? In reality I don't need it to deserialize everytime the layout changes, but this is the only approach I could think of to avoid needing a reference to the DockSite in my ViewModel...
Thanks in advance :)