PRISM 5 MEF AvalonDock 2.0数据适配器注册视图和父视图被选中
本文关键字:视图 注册 适配器 MEF AvalonDock 数据 PRISM | 更新日期: 2023-09-27 18:18:40
我正在尝试使用PRISM 5构建一个MVVM Windows应用程序,我已经用AvalonDock(下面的包装代码)包装了我的主要内容窗口。
using Microsoft.Practices.Prism.Regions;
using Xceed.Wpf.AvalonDock;
using System.Collections.Specialized;
using System.Windows;
using Xceed.Wpf.AvalonDock.Layout;
namespace Central.Adapters
{
using System.Linq;
public class AvalonDockRegionAdapter : RegionAdapterBase<DockingManager>
{
/// <summary>
/// This ties the adapter into the base region factory.
/// </summary>
/// <param name="factory">The factory that determines where the modules will go.</param>
public AvalonDockRegionAdapter(IRegionBehaviorFactory factory)
: base(factory)
{
}
/// <summary>
/// Since PRISM does not support the Avalon DockingManager natively this adapter provides the needed support.
/// </summary>
/// <param name="region">This is the region that resides in the DockingManager.</param>
/// <param name="regionTarget">The DockingManager that needs the window added.</param>
protected override void Adapt(IRegion region, DockingManager regionTarget)
{
region.Views.CollectionChanged += (sender, e) =>
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
AddAnchorableDocument(regionTarget, e);
break;
case NotifyCollectionChangedAction.Remove:
break;
}
};
}
/// <summary>
/// This adds the window as an anchorable document to the Avalon DockingManager.
/// </summary>
/// <param name="regionTarget">The DockingManager instance.</param>
/// <param name="e">The new window to be added.</param>
private static void AddAnchorableDocument(DockingManager regionTarget, NotifyCollectionChangedEventArgs e)
{
foreach (FrameworkElement element in e.NewItems)
{
var view = element as UIElement;
var documentPane = regionTarget.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
if ((view == null) || (documentPane == null))
{
continue;
}
var newContentPane = new LayoutAnchorable
{
Content = view,
Title = element.ToolTip.ToString(),
CanHide = true,
CanClose = false
};
documentPane.Children.Add(newContentPane);
}
}
/// <summary>
/// This returns the region instance populated with all of its contents.
/// </summary>
/// <returns>DockingManager formatted region.</returns>
protected override IRegion CreateRegion()
{
return new AllActiveRegion();
}
}
}
然后我以这种方式在引导程序中注册这个适配器:
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
var mappings = base.ConfigureRegionAdapterMappings();
if (mappings == null)
{
return null;
}
mappings.RegisterMapping(typeof(DockingManager), new AvalonDockRegionAdapter(ConfigureDefaultRegionBehaviors()));
return mappings;
}
我面临的问题是,其他区域UI元素将需要某些LayoutAnchorable窗口成为活动和选择的窗口。我提供给LayoutAnchorable对象的内容是一个ContentControl。
在我的视图的ViewModel我有一个属性,我成功地设置使用另一个UI元素的交互。然而,我无法使连接从ViewModel(属性)-> ContentContro(视图)-> LayoutAnchorable(视图的父)。IsSelected或IsActive.
我知道如何绑定到父对象,但这消耗了属性,不允许我将它绑定到ViewModel属性。我也没有问题绑定到ViewModel属性,但这是无用的,除非我能让它设置父属性。我也尝试过基于视图的事件。这样做的问题是,一旦视图加载,它就不喜欢调用自己的事件了,除非它是由用户直接与该视图交互引起的。
简而言之,我只是想在需要时根据程序另一部分的交互显示适当的窗口。也许我把它弄得太复杂了。如有任何帮助,我将不胜感激。
谢谢詹姆斯。
当我从问题中休息时,我从另一个角度来看待它。为了解决这个问题,我决定将包含视图的内容窗格的实例存储到一个单例字典类中:
using System;
using System.Collections.Generic;
using Xceed.Wpf.AvalonDock.Layout;
namespace Central.Services
{
public class DockinWindowChildObjectDictionary
{
private static Dictionary<string, LayoutAnchorable> _contentPane = new Dictionary<string, LayoutAnchorable>();
private static readonly Lazy<DockinWindowChildObjectDictionary> _instance =
new Lazy<DockinWindowChildObjectDictionary>(()=> new DockinWindowChildObjectDictionary(), true);
public static DockinWindowChildObjectDictionary Instance
{
get
{
return _instance.Value;
}
}
/// <summary>
/// Causes the constructor to be private allowing for proper use of the Singleton pattern.
/// </summary>
private DockinWindowChildObjectDictionary()
{
}
/// <summary>
/// Adds a Content Pane instance to the dictionary.
/// </summary>
/// <param name="title">The title given to the Pane during instantiation.</param>
/// <param name="contentPane">The object instance.</param>
public static void Add(string title, LayoutAnchorable contentPane)
{
_contentPane.Add(title, contentPane);
}
/// <summary>
/// If a window needs to be removed from the dock this should be used
/// to also remove it from the dictionary.
/// </summary>
/// <param name="title">The title given to the Pane during instantiation.</param>
public static void Remove(string title)
{
_contentPane.Remove(title);
}
/// <summary>
/// This will return the instance of the content pane that holds the view.
/// </summary>
/// <param name="title">The title given to the Pane during instantiation.</param>
/// <returns>The views Parent Instance.</returns>
public static LayoutAnchorable GetInstance(string title)
{
return _contentPane[title];
}
}
}
在适配器中,我修改了以下代码:
private static void AddAnchorableDocument(DockingManager regionTarget, NotifyCollectionChangedEventArgs e)
{
foreach (FrameworkElement element in e.NewItems)
{
var view = element as UIElement;
var documentPane = regionTarget.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
if ((view == null) || (documentPane == null))
{
continue;
}
var newContentPane = new LayoutAnchorable
{
Content = view,
Title = element.ToolTip.ToString(),
CanHide = true,
CanClose = false
};
DockinWindowChildObjectDictionary.Add(element.ToolTip.ToString(),** newContentPane);
documentPane.Children.Add(newContentPane);
}
}
然后我添加以下内容到ViewModel以获得我想要的效果:
public void OnNavigatedTo(NavigationContext navigationContext)
{
var viewParentInstance = DockinWindowChildObjectDictionary.GetInstance("Belt Plan");
viewParentInstance.IsSelected = true;
}
跨过一个障碍,进入下一个。这篇文章中所有信息的基础是ViewSwitchingNavigation。PRISM 5.0下载中包含的sln将帮助您入门。如果你想知道在适配器注册中引用的ConfigureDefaultRegionBehaviors(),我从StockTraderRI_Desktop中得到了它。示例下载中的SLN。
我希望这篇文章能帮助到那些发现自己和这个技术三明治一样的人。
真诚詹姆斯。