【发布时间】:2011-02-09 21:09:19
【问题描述】:
我的 Prism 应用需要将来自多个模块的按钮插入到 Shell 区域。按钮将垂直堆叠,就像 Outlook 2010 中的导航按钮(邮件、日历等)。我使用自定义控件作为按钮,所以我不需要担心模板——我的问题与如果我插入的是普通单选按钮。
如何设置区域以使按钮垂直堆叠?感谢您的帮助。
【问题讨论】:
-
您是否尝试过将 StackPanel 用作区域?
标签: prism
我的 Prism 应用需要将来自多个模块的按钮插入到 Shell 区域。按钮将垂直堆叠,就像 Outlook 2010 中的导航按钮(邮件、日历等)。我使用自定义控件作为按钮,所以我不需要担心模板——我的问题与如果我插入的是普通单选按钮。
如何设置区域以使按钮垂直堆叠?感谢您的帮助。
【问题讨论】:
标签: prism
在考虑垂直堆叠项目时,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
从那里您只需在引导程序的 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
【讨论】:
为什么不直接使用 ItemsControl 作为区域?它垂直堆叠项目,Prism 有内置的区域适配器。我不明白您为什么要将 StackPanel 用于除布局之外的任何内容。
默认情况下,ItemsControl 使用包含 StackPanel 的 ItemsPanel,因此它等同于已经提供的答案,但没有不必要的代码。
【讨论】:
来自 NVenhola 的 comment in the Fill My Prism Region, Please article,有一个简单、适应性强的解决方案:
<ItemsControl cal:RegionManager.RegionName="XXRegionNameXX">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
【讨论】:
Matt 的解决方案在第 189-191 页的“Microsoft Prism 开发人员指南”(V4) 中进行了说明。
对于研究此问题的 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();
}
}
}
对于引导程序,这里是 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;
}
【讨论】:
只使用正在做你想做的事情的 itemscontrol 怎么样。默认情况下,ItemsControl 将使用 stackpanel 来呈现模块视图。
【讨论】:
还要非常小心 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();
【讨论】: