Flat Eric
Flat Eric

Reputation: 8111

Bind size and position of floating elements in AvalonDock with MVVM

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.

Upvotes: 0

Views: 2748

Answers (1)

Sheridan
Sheridan

Reputation: 69959

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.

Upvotes: 2

Related Questions