我已经看到了一些关于SO的问题,但它们似乎都不适用于我.我希望能够使用带有Prism 4的伟大的
Avalondock 2.0.但是,所有的样本区域适配器都是针对Avalondock 1.x系列,我无法让它工作.
有没有人有关于如何为AvalonDock的LayoutDocumentPane和LayoutAnchorablePane创建Region Adapter的示例代码?
解决方法
不幸的是,据我所知,“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本身,请参考下面的代码,我提供了解释性注释
- #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,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
不要忘记在Bootstrapper中添加以下代码,以便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”.
健康长寿·繁荣昌盛!