【问题标题】:AvalonDock with Prism Region Adapter带 Prism 区域适配器的 AvalonDock
【发布时间】:2012-06-05 21:27:36
【问题描述】:

我看到了一些关于 SO 的问题,但它们似乎都不适合我。我希望能够将出色的Avalondock 2.0 与 Prism 4 一起使用。但是,所有示例区域适配器都适用于 Avalondock 1.x 系列,我无法让它工作。

有人有关于如何为 AvalonDock 的 LayoutDocumentPane 和 LayoutAnchorablePane 创建区域适配器的示例代码吗?

【问题讨论】:

    标签: c# wpf prism avalondock


    【解决方案1】:

    不幸的是,据我所知,“LayoutDocumentPane”和“LayoutAnchorablePane”都不允许包含/创建 RegionAdapters,但是“DockingManager”可以。一种解决方案是为 DockingManager 创建一个 RegionAdapter,然后管理可视化树中“LayoutDocuments”的实例化。

    xaml 如下所示:

    <ad:DockingManager Background="AliceBlue" x:Name="WorkspaceRegion" prism:RegionManager.RegionName="WorkspaceRegion">
                            <ad:LayoutRoot>
                                <ad:LayoutPanel>
                                    <ad:LayoutDocumentPaneGroup>
                                        <ad:LayoutDocumentPane>
    
                                        </ad:LayoutDocumentPane>
                                    </ad:LayoutDocumentPaneGroup>
                                </ad:LayoutPanel>
                            </ad:LayoutRoot>
                        </ad:DockingManager>
    

    请注意,该区域是在 DockingManager 标记中定义的,并且在 LayoutPanel 下存在一个 LayoutDocumentPaneGroup。 LayoutDocumentPaneGroup 下的 LayoutDocumentPane 将托管与要添加到“WorkspaceRegion”的视图相关联的 LayoutDocuments。

    至于 RegionAdapter 本身,请参考下面我提供的解释性 cmets 代码

    #region Constructor
    
            public AvalonDockRegionAdapter(IRegionBehaviorFactory factory)
                : base(factory)
            {
            }
    
            #endregion  //Constructor
    
    
            #region Overrides
    
            protected override IRegion CreateRegion()
            {
                return new AllActiveRegion();
            }
    
            protected override void Adapt(IRegion region, DockingManager regionTarget)
            {
                region.Views.CollectionChanged += delegate(
                    Object sender, NotifyCollectionChangedEventArgs e)
                    {
                        this.OnViewsCollectionChanged(sender, e, region, regionTarget);
                    };
    
                regionTarget.DocumentClosed += delegate(
                                Object sender, DocumentClosedEventArgs e)
                {
                    this.OnDocumentClosedEventArgs(sender, e, region);
                };
            }
    
            #endregion  //Overrides
    
    
            #region Event Handlers
    
            /// <summary>
            /// Handles the NotifyCollectionChangedEventArgs event.
            /// </summary>
            /// <param name="sender">The sender.</param>
            /// <param name="e">The event.</param>
            /// <param name="region">The region.</param>
            /// <param name="regionTarget">The region target.</param>
            void OnViewsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e, IRegion region, DockingManager regionTarget)
            {
                if (e.Action == NotifyCollectionChangedAction.Add)
                {
                    foreach (FrameworkElement item in e.NewItems)
                    {
                        UIElement view = item as UIElement;
    
                        if (view != null)
                        {
                            //Create a new layout document to be included in the LayoutDocuemntPane (defined in xaml)
                            LayoutDocument newLayoutDocument = new LayoutDocument();
                            //Set the content of the LayoutDocument
                            newLayoutDocument.Content = item;
    
                            ViewModelBase_2 viewModel = (ViewModelBase_2)item.DataContext;
    
                            if (viewModel != null)
                            {
                                //All my viewmodels have properties DisplayName and IconKey
                                newLayoutDocument.Title = viewModel.DisplayName;
                                //GetImageUri is custom made method which gets the icon for the LayoutDocument
                                newLayoutDocument.IconSource = this.GetImageUri(viewModel.IconKey);
                            }
    
                            //Store all LayoutDocuments already pertaining to the LayoutDocumentPane (defined in xaml)
                            List<LayoutDocument> oldLayoutDocuments = new List<LayoutDocument>();
                            //Get the current ILayoutDocumentPane ... Depending on the arrangement of the views this can be either 
                            //a simple LayoutDocumentPane or a LayoutDocumentPaneGroup
                            ILayoutDocumentPane currentILayoutDocumentPane = (ILayoutDocumentPane)regionTarget.Layout.RootPanel.Children[0];
    
                            if (currentILayoutDocumentPane.GetType() == typeof(LayoutDocumentPaneGroup))
                            {
                                //If the current ILayoutDocumentPane turns out to be a group
                                //Get the children (LayoutDocuments) of the first pane
                                LayoutDocumentPane oldLayoutDocumentPane = (LayoutDocumentPane)currentILayoutDocumentPane.Children.ToList()[0];
                                foreach (LayoutDocument child in oldLayoutDocumentPane.Children)
                                {
                                    oldLayoutDocuments.Insert(0, child);
                                }
                            }
                            else if (currentILayoutDocumentPane.GetType() == typeof(LayoutDocumentPane))
                            {
                                //If the current ILayoutDocumentPane turns out to be a simple pane
                                //Get the children (LayoutDocuments) of the single existing pane.
                                foreach (LayoutDocument child in currentILayoutDocumentPane.Children)
                                {
                                    oldLayoutDocuments.Insert(0, child);
                                }
                            }
    
                            //Create a new LayoutDocumentPane and inserts your new LayoutDocument
                            LayoutDocumentPane newLayoutDocumentPane = new LayoutDocumentPane();
                            newLayoutDocumentPane.InsertChildAt(0, newLayoutDocument);
    
                            //Append to the new LayoutDocumentPane the old LayoutDocuments
                            foreach (LayoutDocument doc in oldLayoutDocuments)
                            {
                                newLayoutDocumentPane.InsertChildAt(0, doc);
                            }
    
                            //Traverse the visual tree of the xaml and replace the LayoutDocumentPane (or LayoutDocumentPaneGroup) in xaml
                            //with your new LayoutDocumentPane (or LayoutDocumentPaneGroup)
                            if (currentILayoutDocumentPane.GetType() == typeof(LayoutDocumentPane))
                                regionTarget.Layout.RootPanel.ReplaceChildAt(0, newLayoutDocumentPane);
                            else if (currentILayoutDocumentPane.GetType() == typeof(LayoutDocumentPaneGroup))
                            {
                                currentILayoutDocumentPane.ReplaceChild(currentILayoutDocumentPane.Children.ToList()[0], newLayoutDocumentPane);
                                regionTarget.Layout.RootPanel.ReplaceChildAt(0, currentILayoutDocumentPane);
                            }
                            newLayoutDocument.IsActive = true;
                        }
                    }
                }
            }
    
            /// <summary>
            /// Handles the DocumentClosedEventArgs event raised by the DockingNanager when
            /// one of the LayoutContent it hosts is closed.
            /// </summary>
            /// <param name="sender">The sender</param>
            /// <param name="e">The event.</param>
            /// <param name="region">The region.</param>
            void OnDocumentClosedEventArgs(object sender, DocumentClosedEventArgs e, IRegion region)
            {
                region.Remove(e.Document.Content);
            }
    
            #endregion  //Event handlers
    

    不要忘记在您的引导程序中添加以下代码,以便 Prism 知道您的 RegionAdapter 的存在

    protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
            {
                // Call base method
                var mappings = base.ConfigureRegionAdapterMappings();
                if (mappings == null) return null;
    
                // Add custom mappings
                mappings.RegisterMapping(typeof(DockingManager),
                    ServiceLocator.Current.GetInstance<AvalonDockRegionAdapter>());
    
                // Set return value
                return mappings;
            }
    

    瞧。我知道这不是最干净的解决方案,但它应该可以工作。同样的方法可以很容易地应用于“LayoutAnchorablePane”。

    长命百岁!

    【讨论】:

    • 我有 LayoutAnchorablePane 和 LayoutAnchorableDocument 的适配器,有时它会注册适配器。有时没有。非常令人沮丧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 2013-06-05
    • 2013-07-12
    • 2017-11-12
    • 1970-01-01
    • 2012-07-25
    相关资源
    最近更新 更多