65.9K
CodeProject 正在变化。 阅读更多。
Home

PRISM 的 UIExtensionSites

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2010 年 8 月 4 日

CPOL

3分钟阅读

viewsIcon

30115

downloadIcon

281

用于向 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 接口的类,并提供 ComboBoxItems.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。但我认为以下代码可以很容易地进行修改以适应其他第三方组件。

我首先创建了 DXBarUIExtensionSiteDXBarUIExtensionSiteAdapter

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:第一个版本。
© . All rights reserved.