0

I am trying to bind the Width and Height properties of the floating (undocked) documents in AvalonDock. I am using MVVM pattern.
I want to save the properties (together with the docking state and the position of the window, if undocked) and be able to restore them. Using a XmlLayoutSerializer is not an option because this requires a reference to the docking manager which is not allowed in the ViewModel.

This is the XAML code:

<avalonDock:DockingManager DocumentsSource="{Binding Files}"
                           ActiveContent="{Binding ActiveDocument, Mode=TwoWay}">
    <avalonDock:DockingManager.LayoutItemContainerStyle>
        <Style TargetType="{x:Type avalonDock:LayoutDocumentItem}">
            <Setter Property="Title" Value="{Binding Model.Title}"/>
            <Setter Property="CanClose" Value="False" />
            <Setter Property="CanFloat" Value="True" />
        </Style>
    </avalonDock:DockingManager.LayoutItemContainerStyle>

    <avalonDock:LayoutRoot>
        <avalonDock:LayoutPanel>
            <avalonDock:LayoutDocumentPane>
            </avalonDock:LayoutDocumentPane>
        </avalonDock:LayoutPanel>
    </avalonDock:LayoutRoot>

The ViewModel:

private ObservableCollection<PaneViewModel> m_readonyFiles;
public ObservableCollection<PaneViewModel> Files
{
    get { return m_readonyFiles ?? (m_readonyFiles = 
             new ObservableCollection<PaneViewModel>()); }
}

private PaneViewModel _activeDocument = null;
public PaneViewModel ActiveDocument
{
    get { return _activeDocument; }
    set
    {
        if (_activeDocument != value)
        {
            _activeDocument = value;

            RaisePropertyChanged("ActiveDocument");
        }
    }
}

I tried to set a binding in the style of LayoutDocumentItem but the setter never gets called:

<Window.Resources>
    <Style TargetType="{x:Type avalonDock:LayoutDocumentItem}">
        <Setter Property="Width" Value="{Binding ActiveDocument.CurrentWidth, Mode=TwoWay}"></Setter>
        <Setter Property="Height" Value="{Binding ActiveDocument.CurrentHeigth, Mode=TwoWay}"></Setter>
    </Style>
</Window.Resources>

How can I save and restore the size and position of the floating documents without violating the MVVM pattern?


Solution Update >>>

I finally solved my problem with an idea from one of the articles @Sheridan linked to in his answer. I created a messenger that handles communication between my ViewModel and the CodeBehind of the View. There I get position and size of the documents and send them back to ViewModel. To restore, I use a ILayoutUpdateStrategy and in the function AfterInsertDocument, I restore the states.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
Flat Eric
  • 7,971
  • 9
  • 36
  • 45

1 Answers1

2

In WPF, we manipulate data elements rather than UI elements. So instead of attempting to save UI controls, along with their ridiculous amounts of properties, just save the relevant property values. Normally, the best way to do this is to declare a custom class that contains the required property types and values.

However, in the case of AvalonDock, there is a handy extension function of the DockingManager object that takes care of this for you:

/// <summary>
/// Event raised when the window is about to close.
/// </summary>
private void Window_Closing(object sender, CancelEventArgs e)
{
    ...

    //
    // When the window is closing, save AvalonDock layout to a file.
    //
    avalonDockHost.DockingManager.SaveLayout(LayoutFileName);
}

...

/// <summary>
/// Event raised when AvalonDock has loaded.
/// </summary>
private void avalonDockHost_AvalonDockLoaded(object sender, EventArgs e)
{
    if (System.IO.File.Exists(LayoutFileName))
    {
        //
        // If there is already a saved layout file, restore AvalonDock layout from it.
        //
        avalonDockHost.DockingManager.RestoreLayout(LayoutFileName);
    }
    else
    {
        //
        // ... no previously saved layout exists, need to load default layout ...
        //
    }
}

These examples were taken from the AvalonDock and MVVM page on Code Project, which you may find interesting for other reasons too. For further help on the topic, please refer to the Loading/Saving AvalonDock Layouts at Start-up/Shut-Down page on Code Project, or the Save/Load Layout & Content and AvalonDock 2.0 getting started guide PART 2 pages on the AvalonDock section of CodePlex.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • Thanks for your response. The DockingManager seems to have no function 'SaveLayout'. I'm using version 2.0.2000.0 – Flat Eric May 28 '14 at 09:18
  • If you had actually taken the time to read the linked articles, then you would have read that it is a behaviour, or extension method, that you have to define. Apologies for calling it 'built-in'. – Sheridan May 28 '14 at 09:34
  • I finally solved my problem with an idea from one of the articles you linked in the answer. I created a messenger that handles communication between my ViewModel and the CodeBehind of the View. There I get position and size of the documents and send them back to ViewModel. To restore, I use a 'ILayoutUpdateStrategy' and in the function 'AfterInsertDocument' I restore the states. – Flat Eric May 28 '14 at 12:21
  • Thanks for updating... I've added your comment into your question where it will be more easily seen. – Sheridan May 28 '14 at 12:35