如何自动将布局加载到AvalonDock实例中?

时间:2013-01-29 14:45:13

标签: c# wpf mvvm avalondock

我已将AvalonDock 2.0集成到我的应用程序中。我将文档和可锚定的源绑定到我的视图模型,通过DataTemplate s使用适当的用户控件进行渲染。

我可以使用XmlLayoutSerializer加载和保存布局。我需要支持按需加载预定义的布局(通过ButtonICommand s)。这也有效。

我无法正常工作的是在DockingManager加载视图模型及其视图(用户控件)时自动加载序列化布局。

我已尝试在DockingManager.DataContextChanged上加载我的布局,但我认为它过早启动,因为布局会加载隐藏部分中的文档和可见部分中的重复文档。渲染的窗格不会反映加载的布局,并且当再次保存布局时,重复项将累积在隐藏的部分中。

<ad:DockingManager Name="DockingManager"
                   DataContext="{Binding Project}"
                   DataContextChanged="DockingManager_OnDataContextChanged"
                   ActiveContent="{Binding Active}"
                   AnchorablesSource="{Binding Anchorables}"
                   DocumentsSource="{Binding Documents}">
    <ad:DockingManager.Theme>
        <ad:AeroTheme/>
    </ad:DockingManager.Theme>

    <ad:DockingManager.LayoutItemTemplateSelector>
        <views:PanesTemplateSelector>
            <views:PanesTemplateSelector.ChartTemplate>
                <DataTemplate>
                    <views:Chart/>
                </DataTemplate>
            </views:PanesTemplateSelector.ChartTemplate>
            <views:PanesTemplateSelector.WorkspaceTemplate>
                <DataTemplate>
                    <Views:Workspace/>
                </DataTemplate>
            </views:PanesTemplateSelector.WorkspaceTemplate>
            ...
        </views:PanesTemplateSelector>
    </ad:DockingManager.LayoutItemTemplateSelector>

    <ad:DockingManager.LayoutItemContainerStyle>
        <Style TargetType="{x:Type ad:LayoutItem}">
            <Setter Property="Title" Value="{Binding Model.DisplayText}"/>
            <Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
        </Style>
    </ad:DockingManager.LayoutItemContainerStyle>

    <ad:LayoutRoot>
        <!--<ad:LayoutPanel>
            <ad:LayoutDocumentPane/>
            <ad:LayoutAnchorablePane/>
        </ad:LayoutPanel>-->
    </ad:LayoutRoot>
</ad:DockingManager>

...和代码隐藏......

private void SaveLayout() {
    if (this.DataContext == null)
        return;
    var xmlLayoutSerializer = new XmlLayoutSerializer(this.DockingManager);
    var stringBuilder = new StringBuilder();
    using (var textWriter = new StringWriter(stringBuilder))
        xmlLayoutSerializer.Serialize(textWriter);
    var serialized = stringBuilder.ToString();
    (this.DataContext as dynamic).XmlSerializedAndEscapedLayout = HttpUtility.HtmlEncode(serialized);
}
private void LoadLayout()
{
    if (DataContext == null)
        return;
    var encoded = (DataContext as dynamic).XmlSerializedAndEscapedLayout;
    var window = Window.GetWindow(this);
    window.Closing += (sender, args) => SaveLayout();
    if (String.IsNullOrWhiteSpace(encoded))
        return;
    var serialized = HttpUtility.HtmlDecode(encoded);
    var xmlLayoutSerializer = new XmlLayoutSerializer(DockingManager);
    using (var stringReader = new StringReader(serialized))
        xmlLayoutSerializer.Deserialize(stringReader);
}
private void DockingManager_OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue != null) // A type check here would be best, I know.
        LoadLayout();
}

......和视图模型......

public class ProjectViewModel
{
    public IModel Model { get; private set; }
    public String SerializedLayout { get; set; }
    public ViewModelBase Active { get; set; }
    private readonly ObservableCollection<ViewModelBase> documents;
    public ReadOnlyObservableCollection<ViewModelBase> Documents { get; private set; }
    private readonly ObservableCollection<ViewModelBase> anchorables;
    public ReadOnlyObservableCollection<ViewModelBase> Anchorables { get; private set; }

    public ProjectViewModel(String filePath, String serializedLayout)
    {
        SerializedLayout = serializedLayout;
        using (var fileStream = new FileStream(filePath, FileMode.Open))
        {
            IModelRepository modelRepository = Ioc.DependencyInjectionContainer.DefaultContainer.Resolve<IModelRepository>();
            Model = modelRepository.Load(fileStream);
        }
        documents = new ObservableCollection<ViewModelBase>();
        anchorables = new ObservableCollection<ViewModelBase>();
        documents.Add(new Workspace());
        anchorables.Add(new RiskLimitsViewModel(Model.RiskLimits));
        ...
        Documents = new ReadOnlyObservableCollection<ViewModelBase>(documents);
        Anchorables = new ReadOnlyObservableCollection<ViewModelBase>(anchorables);
    }
}

非常感谢任何见解。谢谢!

2 个答案:

答案 0 :(得分:4)

我必须在XAML中添加它......

...
</ad:DockingManager.Theme>
<ad:DockingManager.LayoutUpdateStrategy>
    <views:LayoutUpdateStrategy/>
</ad:DockingManager.LayoutUpdateStrategy>

<ad:DockingManager.LayoutItemTemplateSelector>
...

...这在代码隐藏中......

class LayoutUpdateStrategy : ILayoutUpdateStrategy
{
    private bool BeforeInsertContent(LayoutRoot layout, LayoutContent anchorableToShow)
    {
        var viewModel = (ViewModelBase) anchorableToShow.Content;
        var layoutContent = layout.Descendents().OfType<LayoutContent>().FirstOrDefault(x => x.ContentId == viewModel.ContentId);
        if (layoutContent == null)
            return false;
        layoutContent.Content = anchorableToShow.Content;
        // Add layoutContent to it's previous container
        var layoutContainer = layoutContent.GetType().GetProperty("PreviousContainer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(layoutContent, null) as ILayoutContainer;
        if (layoutContainer is LayoutAnchorablePane)
            (layoutContainer as LayoutAnchorablePane).Children.Add(layoutContent as LayoutAnchorable);
        else if (layoutContainer is LayoutDocumentPane)
            (layoutContainer as LayoutDocumentPane).Children.Add(layoutContent);
        else
            throw new NotSupportedException();
        return true;
    }
    public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer)
    {
        return BeforeInsertContent(layout, anchorableToShow);
    }
    public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown) {}
    public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer)
    {
        return BeforeInsertContent(layout, anchorableToShow);
    }
    public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown) {}
}

答案 1 :(得分:0)

我用过这个:

XAML:

<avalonDock:DockingManager 
x:Name="dockManager" 
AllowMixedOrientation="True" 
DocumentClosing="dockManager_DocumentClosing" 
AnchorablesSource="{Binding ListUserPanelAnchorable}"
DocumentsSource="{Binding ListUserPanel}"
Theme="{Binding avalondockTheme}">

型号:

public ObservableCollection<UserPanel> _ListUserPanelAnchorable;
ReadOnlyObservableCollection<UserPanel> _readonyFiles = null;
public ReadOnlyObservableCollection<UserPanel> ListUserPanelAnchorable
{
    get
    {
        if (_readonyFiles == null)
            _readonyFiles = new ReadOnlyObservableCollection<UserPanel>(_ListUserPanelAnchorable);

        return _readonyFiles;
    }
}

xaml.cs:

private void loadLayout()
{
    //dockPanelModel.ListUserPanel.Clear();
    //dockPanelModel.ListUserPanelAnchorable.Clear();
    var serializer = new XmlLayoutSerializer(dockManager);
    serializer = new XmlLayoutSerializer(dockManager);
    serializer.LayoutSerializationCallback += (s, args) =>
    {
        args.Content = userPanel;
                dockPanelModel._ListUserPanelAnchorable.Add(userPanel);
    }
}

public AvaladonDockPanel()
{
    InitializeComponent();
    this.Loaded += AvaladonDockPanel_Loaded;                
}       

void AvaladonDockPanel_Loaded(object sender, RoutedEventArgs e)
{
    loadLayout();          
}

userpanel:

public class UserPanel
{
    public string Title { get; set; }
    public string ToolTip { get; set; }
    public string IconSource { get; set; }

    private Guid _contentGuid = Guid.NewGuid();
    public Guid ContentId
    {
        get { return _contentGuid; }
        set { _contentGuid = value; }
    }


    private UserControl _UserInterface;
    public UserControl UserInterface { get { return _UserInterface; } set { _UserInterface = value; NotifyPropertyChanged("UserInterface"); } }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            Debug.WriteLine(string.Format("PropertyChanged-> {0}", propertyName));
        }
    }
}

将avalon绑定到userpanel:

<avalonDock:DockingManager.LayoutItemContainerStyle>
    <Style TargetType="{x:Type avalonDock:LayoutItem}">
        <Setter Property="Title" Value="{Binding Model.Title}"/>
        <Setter Property="ToolTip" Value="{Binding Model.ToolTip}"/>
        <Setter Property="IconSource" Value="{Binding Model.IconSource}" />
        <Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
    </Style>
</avalonDock:DockingManager.LayoutItemContainerStyle>
<avalonDock:DockingManager.LayoutItemTemplate >
    <DataTemplate >
        <ContentPresenter Content="{Binding UserInterface}"  />
    </DataTemplate>
</avalonDock:DockingManager.LayoutItemTemplate>
相关问题