棱镜:在一个区域堆叠控件?

时间:2011-02-09 21:09:20

标签: prism

My Prism应用程序需要将多个模块中的按钮插入Shell区域。这些按钮将垂直堆叠,如Outlook 2010中的导航按钮(邮件,日历等)。我使用自定义控件作为按钮,因此我不需要担心模板 - 我的问题与如果我插入普通单选按钮。

如何设置区域以使按钮垂直堆叠?谢谢你的帮助。

6 个答案:

答案 0 :(得分:6)

当考虑垂直堆叠项目时,StackPanel会立即跳到脑海。不幸的是,Prism不支持StackPanel成为开箱即用的区​​域。幸运的是,你可以创建一个RegionAdapter来解决这个问题。

Public Class StackPanelRegionAdapter
Inherits RegionAdapterBase(Of StackPanel)

    Public Sub New(ByVal behaviorFactory As IRegionBehaviorFactory)
        MyBase.New(behaviorFactory)
    End Sub

    Protected Overrides Sub Adapt(ByVal region As IRegion, ByVal regionTarget As StackPanel)
        AddHandler region.Views.CollectionChanged, Sub(sender As Object, e As NotifyCollectionChangedEventArgs)
            If e.Action = NotifyCollectionChangedAction.Add Then
                For Each element As FrameworkElement In e.NewItems
                    regionTarget.Children.Add(element)
                Next
            Else
            If e.Action = NotifyCollectionChangedAction.Remove Then
                For Each element In e.OldItems
                    If regionTarget.Children.Contains(element) Then
                        regionTarget.Children.Remove(element)
                    End If
                Next
            End If
        End Sub
    End Sub

    Protected Overrides Function CreateRegion() As Microsoft.Practices.Prism.Regions.IRegion
        Return New AllActiveRegion
    End Function
End Class

从那里你只需要在你的bootstrapper中的ConfigureRegionAdapterMappings Override中添加映射。

Protected Overrides Function ConfigureRegionAdapterMappings() As Microsoft.Practices.Prism.Regions.RegionAdapterMappings
    Dim mappings = MyBase.ConfigureRegionAdapterMappings()
    mappings.RegisterMapping(GetType(Grid), Container.Resolve(Of PrismExtensions.GridRegionAdapter))
    mappings.RegisterMapping(GetType(StackPanel), Container.Resolve(Of PrismExtensions.StackPanelRegionAdapter))
    Return mappings
End Function

编辑:找到我最初从中获取代码的John Papa链接。 (在C#中,如果你正在使用的话)Fill My Prism Region, Please

答案 1 :(得分:6)

Matt的解决方案在“Microsoft Prism开发人员指南”(V4)第189-191页中有所解释。

对于研究此问题的C#开发人员,这是Matt适配器到C#的翻译:

using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Prism.Regions;

namespace FsNoteMaster3.Shell.Views.Utility
{
    /// <summary>
    /// Enables use of a StackPanel in a Prism region.
    /// </summary>
    /// <remarks> See stackoverflow.com/questions/4950464/prism-stacking-controls-in-a-region</remarks>
    public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
    {
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="behaviorFactory">Allows the registration of the default set of RegionBehaviors.</param>
        public StackPanelRegionAdapter(IRegionBehaviorFactory behaviorFactory) : base(behaviorFactory)
        {
        }

        /// <summary>
        /// Adapts a ContentControl to an IRegion. 
        /// </summary>
        /// <param name="region">The new region being used.</param>
        /// <param name="regionTarget">The object to adapt.</param>
        protected override void Adapt(IRegion region, StackPanel regionTarget)
        {
            region.Views.CollectionChanged += (sender, e) =>
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                        foreach (FrameworkElement element in e.NewItems) 
                        {
                            regionTarget.Children.Add(element);
                        }
                        break;

                    case NotifyCollectionChangedAction.Remove:
                        foreach (UIElement elementLoopVariable in e.OldItems) 
                        {
                            var element = elementLoopVariable;
                            if (regionTarget.Children.Contains(element)) 
                            {
                                regionTarget.Children.Remove(element);
                            }
                        }
                        break;
                }
            };
        }

        /// <summary>
        /// Template method to create a new instance of IRegion that will be used to adapt the object. 
        /// </summary>
        /// <returns>A new instance of IRegion.</returns>
        protected override Microsoft.Practices.Prism.Regions.IRegion CreateRegion()
        {
            return new AllActiveRegion();
        }
    }
}

对于Bootstrapper,这里是C#中的ConfigureRegionAdapterMappings()覆盖,为Prism 4更新:

/// <summary>
/// Configures the default region adapter mappings to use in the application.
/// </summary>
/// <returns>The RegionAdapterMappings instance containing all the mappings.</returns>
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
    var mappings = base.ConfigureRegionAdapterMappings();
    mappings.RegisterMapping(typeof(StackPanel), ServiceLocator.Current.GetInstance<StackPanelRegionAdapter>());
    return mappings;
}

答案 2 :(得分:6)

来自NVenhola的comment in the Fill My Prism Region, Please article,有一个简单,适应性强的解决方案:

<ItemsControl cal:RegionManager.RegionName="XXRegionNameXX">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

答案 3 :(得分:5)

为什么不将ItemsControl用作区域?它垂直堆叠项目,Prism为它构建了内置区域适配器。我不明白你为什么要把StackPanel用于布局以外的任何东西。

默认情况下,ItemsControl使用包含StackPanel的ItemsPanel,因此它等同于已提供的答案,但没有不必要的代码。

答案 4 :(得分:1)

如何使用刚刚做你想做的itemscontrol。默认情况下,ItemsControl将使用stackpanel呈现模块视图。

答案 5 :(得分:0)

还要非常小心Bootstrapper.cs中的RegionAdapterMapping实例: 这样写:

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
    //this is the correct way
    RegionAdapterMappings regionAdapterMappings = base.ConfigureRegionAdapterMappings(); 
    regionAdapterMappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackPanelRegionAdapter>());
    return regionAdapterMappings;
 }

花了我几个小时才发现你不能写:

//RegionAdapterMappings regionAdapterMappings = new RegionAdapterMappings();