Reputation: 8111
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
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