我已经看到了一些关于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”.
健康长寿·繁荣昌盛!