简体   繁体   English

使用MVVM在AvalonDock中绑定浮动元素的大小和位置

[英]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 . 我正在尝试在AvalonDock绑定浮动(未停靠)文档的WidthHeight属性。 I am using MVVM pattern. 我正在使用MVVM模式。
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. 不能使用XmlLayoutSerializer因为这需要引用对接管理器,而ViewModel是不允许的。

This is the XAML code: 这是XAML代码:

<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: 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: 我试图以LayoutDocumentItem的样式设置绑定,但从未调用setter:

<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? 如何在不违反MVVM模式的情况下保存和恢复浮动文档的大小和位置?


Solution Update >>> 解决方案更新>>>

I finally solved my problem with an idea from one of the articles @Sheridan linked to in his answer. 我终于用@Sheridan的一篇文章中的一个想法解决了我的问题,链接到他的答案中。 I created a messenger that handles communication between my ViewModel and the CodeBehind of the View. 我创建了一个Messenger,用于处理ViewModel和View的CodeBehind之间的通信。 There I get position and size of the documents and send them back to ViewModel. 在这里,我得到了文档的位置和大小,然后将它们发送回ViewModel。 To restore, I use a ILayoutUpdateStrategy and in the function AfterInsertDocument , I restore the states. 要还原,我使用ILayoutUpdateStrategy并在AfterInsertDocument函数中还原状态。

In WPF, we manipulate data elements rather than UI elements . 在WPF中,我们操纵数据元素而不是UI元素 So instead of attempting to save UI controls, along with their ridiculous amounts of properties, just save the relevant property values. 因此,不要尝试保存UI控件及其可笑的属性数量,而只需保存相关的属性值即可。 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: 但是,对于AvalonDock, DockingManager对象有一个方便的扩展功能,可以为您解决这一问题:

/// <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. 这些示例摘自Code Project上的AvalonDock和MVVM页面,由于其他原因,您可能也会发现它们很有趣。 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. 有关该主题的更多帮助,请参阅Code Project上“ 启动/关闭”页面上的“ 加载/保存AvalonDock布局 ”,或“ AvalonDock”部分的“ 保存/加载布局和内容以及AvalonDock 2.0入门指南”第2部分。 CodePlex。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM