带棱镜区域适配器的 AvalonDock



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

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

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

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"的视图关联的布局文档。

至于区域适配器本身,请参阅下面我提供解释性注释的代码

#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"。

长寿,繁荣昌盛!

最新更新