PRISM 的 UIExtensionSites





5.00/5 (1投票)
用于向 PRISM 添加类似 UIExtensionSites 机制的类。
引言
PRISM 是一个用于开发 WPF 和 Silverlight 应用程序的优秀库。然而,从 CAB (Microsoft Composite UI Application Blocks) 库开始,我一直缺少 UIExtensionSites 功能。由于 PRISM 没有提供它,而我需要它,所以我决定自己编写它(然后分享它)。
源代码
该解决方案是一个 VS2010 解决方案。注意:要编译代码,您必须首先从 CodePlex 安装 PRISM 库。
该代码由四个类组成
UIExtensionSiteManager
:这是主类,包含添加附加属性的代码,并跟踪UIExtensionSite
。IUIExtensionSiteAdapter
:实现此接口的类“适配”控件到UIExtensionSite
。UIExtensionSiteMappings
:包含控件类型和IUIExtensionSiteAdapter
之间的映射。IUIExtensionSite
:实现此接口的类允许将控件添加到UIExtensionSite
。
UIExtensionSiteManager
UIExtensionSiteManager
定义了 'UIExtensionSite
' 附加属性
public static readonly DependencyProperty UIExtensionSiteProperty =
DependencyProperty.RegisterAttached(
"UIExtensionSite",
typeof(string),
typeof(UIExtensionSiteManager),
new PropertyMetadata(OnSetUIExtensionSiteCallback));
public static void SetUIExtensionSite(DependencyObject siteTarget, string siteName)
{
siteTarget.SetValue(UIExtensionSiteProperty, siteName);
}
public static string GetUIExtensionSite(DependencyObject siteTarget)
{
return siteTarget.GetValue(UIExtensionSiteProperty) as string;
}
private static void OnSetUIExtensionSiteCallback(DependencyObject element,
DependencyPropertyChangedEventArgs args)
{
if (!IsInDesignMode(element))
{
IServiceLocator locator = ServiceLocator.Current;
UIExtensionSiteManager manager =
locator.GetInstance<UIExtensionSiteManager>();
UIExtensionSiteMappings mappings =
locator.GetInstance<UIExtensionSiteMappings>();
IUIExtensionSiteAdapter adapter = mappings.GetMapping(element.GetType());
IUIExtensionSite site = adapter.Adapt(element);
manager.AddUIExtensionSite(
(string)element.GetValue(UIExtensionSiteProperty), site);
}
}
WPF/Silverlight 中的所有控件都可以使用 UIExtensionSiteManager.UIExtensionSite
属性来定义一个扩展站点。
管理器 的第二个作用是跟踪扩展站点。方法 'GetUIExtensionSite
' 允许您检索一个扩展站点。
UIExtensionSiteManager
必须在应用程序开始时在 Unity 容器中注册。一个好地方是在 Unity 引导程序的 ConfigureContainer
方法中
protected override void ConfigureContainer()
{
Container.RegisterType<UIExtensionSiteManager>(
new Microsoft.Practices.Unity.ContainerControlledLifetimeManager(),
new Microsoft.Practices.Unity.InjectionMember[] {});
base.ConfigureContainer();
}
IUIExtensionSiteAdapter
IUIExtensionSiteAdapter
是一个接口,定义了适配器必须实现的操作。只有一个方法:Adapt
。此方法接受一个 DependencyObject
并返回一个实现 IUIExtensionSite
的对象。Adapt
方法必须检查给定的 DependencyObject
的类型是否与可以适配的类型匹配。
必须为每个必须声明为 UIExtensionSite
的控件定义一个匹配的 IUIExtensionSiteAdapter
。
例如,如果您想将 ComboBox
定义为 UIExtensionSite
,您必须提供一个 IUIExtensionSiteAdapter
,它将 ComboBox
“适配”到一个合适的 IUIExtensionSite
对象。
public class ComboBoxUIExtensionSiteAdapter : IUIExtensionSiteAdapter
{
public IUIExtensionSite Adapt(DependencyObject element)
{
if (element is ComboBox)
return new ComboBoxUIExtensionSite(element as ComboBox);
else
throw new ArgumentException("ComboBoxUIExtensionSiteAdapter " +
"can only adapt ComboBox objects !");
}
}
UIExtensionSiteMappings
此类是类型及其匹配的 IUIExtensionSiteAdapter
的集合。应该为每个 IUIExtensionSiteAdapter
提供一个映射。
例如,如果您想将 ComboBox
定义为 UIExtensionSite
,您必须为 ComboBox
及其匹配的 IUIExtensionSiteAdapter
添加一个映射。这在您的 PRISM 应用程序的 UnityBootstrapper 中完成。
protected override void ConfigureContainer()
{
Container.RegisterType<UIExtensionSiteManager>(
new Microsoft.Practices.Unity.ContainerControlledLifetimeManager(),
new Microsoft.Practices.Unity.InjectionMember[] {});
ConfigureUIExtensionSiteAdapterMappings();
base.ConfigureContainer();
}
protected void ConfigureUIExtensionSiteAdapterMappings()
{
UIExtensionSiteMappings mappings = new UIExtensionSiteMappings();
Container.RegisterInstance(mappings,
new Microsoft.Practices.Unity.ContainerControlledLifetimeManager());
mappings.RegisterMapping(typeof(System.Windows.Controls.ComboBox),
this.Container.Resolve<ComboBoxUIExtensionSiteAdapter>());
}
IUIExtensionSite
扩展站点必须实现此接口。它定义了 DependencyObject
(即扩展站点)周围的“包装器”,并定义了一个方法:Add
。此方法中的代码应该将给定的 FrameworkElement
添加到扩展站点。
例如,如果您想将 ComboBox
定义为 UIExtensionSite
,您必须创建一个实现 IUIExtensionSite
接口的类,并提供 ComboBox
的 Items.Add()
方法的包装器。
public class ComboBoxUIExtensionSite : IUIExtensionSite
{
private ComboBox _combo;
public ComboBoxUIExtensionSite(ComboBox combo)
{
this._combo = combo;
}
public void Add(FrameworkElement element)
{
_combo.Items.Add(element);
}
public DependencyObject Target
{
get { return _combo; }
}
}
使用 UIExtensionSites
您可以通过将附加属性添加到您的控件来使用 UIExtensionSite
。例如,如果您想将 ComboBox
定义为 UIExtensionSite
<ComboBox uiext:UIExtensionSiteManager.UIExtensionSite="ProjectCombo"></ComboBox>
在您的模块中,您所要做的就是检索对 UIExtensionSite
的引用并将其项目添加到其中。例如,将项目添加到先前定义的 ComboBox
UIExtensionSiteManager manager = container.Resolve<UIExtensionSiteManager>();
manager.GetUIExtensionSite("ProjectCombo").Add(new ComboBoxItem() { Content = "Project A" });
manager.GetUIExtensionSite("ProjectCombo").Add(new ComboBoxItem() { Content = "Project B" });
manager.GetUIExtensionSite("ProjectCombo").Add(new ComboBoxItem() { Content = "Project C" });
一个使用 DevExpress Silverlight 工具栏的示例
由于我正在使用 DevExpress 组件,因此我为 DevExpress 工具栏创建了一个 UIExtensionSite
。但我认为以下代码可以很容易地进行修改以适应其他第三方组件。
我首先创建了 DXBarUIExtensionSite
和 DXBarUIExtensionSiteAdapter
public class DXBarUIExtensionSite : IUIExtensionSite
{
private DevExpress.Xpf.Bars.Bar _bar;
public DXBarUIExtensionSite(DevExpress.Xpf.Bars.Bar bar)
{
if (bar == null)
throw new ArgumentException("DXBarUIExtensionSite must " +
"be initialized with a valid Bar object !");
_bar = bar;
}
public void Add(FrameworkElement element)
{
if (!(element is DevExpress.Xpf.Bars.BarItem))
throw new ArgumentException("element should be of type BarItem !");
DevExpress.Xpf.Bars.BarItem item = element as DevExpress.Xpf.Bars.BarItem;
DevExpress.Xpf.Bars.BarManager barmanager = _bar.Manager;
if (!barmanager.Items.Contains(item))
barmanager.Items.Add(item);
_bar.ItemLinks.Add(item);
}
public DependencyObject Target
{
get { return _bar; }
}
}
public class DXBarUIExtensionSiteAdapter : IUIExtensionSiteAdapter
{
public IUIExtensionSite Adapt(DependencyObject element)
{
return new DXBarUIExtensionSite(element as DevExpress.Xpf.Bars.Bar);
}
}
下一步是在我的 Shell 中将工具栏定义为 UIExtensionSite
(在 XAML 中)
<dxb:BarManager Name="barManager" CreateStandardLayout="True">
<dxb:BarManager.Items>
</dxb:BarManager.Items>
<dxb:BarManager.Bars>
<dxb:Bar Caption="MainMenu" x:Name="MainMenu"
IsMainMenu="True" UseWholeRow="True"
uiext:UIExtensionSiteManager.UIExtensionSite="MainMenu">
<dxb:Bar.DockInfo>
<dxb:BarDockInfo ContainerType="Top"/>
</dxb:Bar.DockInfo>
</dxb:Bar>
</dxb:BarManager.Bars>
</dxb:BarManager>
最后一步是将按钮添加到我的 UIExtensionSite
。请注意,此示例还包括对 Command 的绑定
DelegateCommand<string> openrepositorycmd = new DelegateCommand<string>(
s => regionManager.RegisterViewWithRegion("MainTab", () =>
container.Resolve<RepositoryListPresenter>().View));
Binding binding = new Binding();
binding.Source = openrepositorycmd;
System.Windows.Media.Imaging.BitmapImage image =
new System.Windows.Media.Imaging.BitmapImage(
new Uri("/RepositoryModule;component/Img/anchor16.png", UriKind.Relative));
DevExpress.Xpf.Bars.BarButtonItem button = new DevExpress.Xpf.Bars.BarButtonItem()
{
Content="Go !",
Hint="This is a testbutton",
Glyph=image
};
button.SetBinding(DevExpress.Xpf.Bars.BarButtonItem.CommandProperty, binding);
DevExpress.Xpf.Bars.BarSubItem repMenu = new DevExpress.Xpf.Bars.BarSubItem()
{
Content = "Repository"
};
repMenu.ItemLinks.Add(button);
UIExtensionSiteManager manager = container.Resolve<UIExtensionSiteManager>();
manager.GetUIExtensionSite("MainMenu").Add(repMenu);
历史
- 2010-08-04:第一个版本。