我想使用PrismV4,MEF,Ribbon开始开发新应用程序。 但现在,我有一个问题。如何动态创建功能区的选项卡? 应用程序中的每个模块都可以在功能区中创建自己 每个标签可能有很多组。
怎么做? 我需要在哪里放置每个组的定义(使用哪些控件(按钮,文本框,组合框等)和命令绑定以及如何?
我是否需要在Module中的某处编写XAML,或者可以通过代码完成所有操作? 最后一个问题,如何通知Ribbon(在Shell中)将这些选项卡添加到功能区?我应该使用EventAggregator从Module与Shell进行通信吗?或?
答案 0 :(得分:3)
我认为您必须使用区域适配器(用于处理非标准(不支持的开箱即用控件作为区域)
http://msdn.microsoft.com/en-us/library/dd458901.aspx
以上链接可以是一个很好的起点。 然后你可以将你的标签注册为视图(我不确定,因为我没有使用过功能区)。
否则,您可以公开不同模块在其构造函数中使用的服务IRibbonService,然后您可以调用AddTab / AddGroup等方法。
答案 1 :(得分:3)
对于非上下文选项卡,我最喜欢的解决此问题的方法是动态加载组件(例如通过反射),其中包括绑定到命令的XAML和包含命令实现的VM(或控制器)并执行该命令绑定。
对于上下文选项卡,我最喜欢的方法是包含Model to ViewModel映射的字典,然后按名称激活/停用上下文选项卡,使用上述方法加载(并将正确的数据上下文传递给它们 - 视图模型)。
伪代码应该或多或少像这样(取决于你的框架实现了什么以及你必须自己实现的内容):
// Deserialize UI controllers from configuration files
// Each controller should act as view-model for its UI elements
// Register controllers with UI Manager
foreach controller in config.UiControllers uiManager.AddController(controller);
void UiManager.AddController(UiController controller)
{
// Load controller's tool windows
foreach toolWindow in contoller.toolWindows
{
toolWindow.LoadResources();
toolWindow.DataContext = controller;
mainWindow.AddToolWindow(toolWindow, contoller.PreferedUiRegion);
}
// Load controller's toolbars
foreach toolBar in controller.ToolBars
{
toolBar.DataContext = controller;
mainWindow.AddToolBar(toolBar);
}
// Load controller's contextual toolbar groups
foreach group in controller.ContextualToolBarGroups
{
group.DataContext = controller;
mainWindow.AddContextualToolBarGroupr(group);
}
// Load view models for specific model types
foreach item in controller.ViewModelsDictionary
{
this.RegisterViewModelType(item.ModelType, item.ViewModelType, item.ViewType);
}
}
void UiManager.OnItemSelected(Object selectedItem)
{
var viewModelType = GetViewModelTypeFromDictionary(selectedItem);
var viewType = GetViewTypeFromDictionary(selectedItem) ?? typeof(ContentPresentor);
var viewModel = Reflect.CreateObject(viewModelType);
var view = Reflection.CreateObject(viewType);
viewModel.Model = selectItem;
view.DataContext = viewModel;
// Enable activation of contextual tab group on activate of view (if user clicks on it)
view.OnActivatedCommandParameter = viewModel.ContextualTabGroupName;
// This command should ask mainWindow to find contextual tab group, by name, and activate it
view.OnActivatedCommand = ModelActivatedCommand;
mainWindow.DocumentArea.Content = view;
}
答案 2 :(得分:1)
为功能区选项卡创建视图: 视图:
<!-- See code-behind for implementation of IRegionMemberLifetime interface. This interface
causes the RibbonTab to be unloaded from the Ribbon when we switch views. -->
<!--<ribbon:RibbonGroup Header="Group B1">
<ribbon:RibbonButton LargeImageSource="Images\LargeIcon.png" Label="Button B1" />
<ribbon:RibbonButton SmallImageSource="Images\SmallIcon.png" Label="Button B2" />
<ribbon:RibbonButton SmallImageSource="Images\SmallIcon.png" Label="Button B3" />
<ribbon:RibbonButton SmallImageSource="Images\SmallIcon.png" Label="Button B4" />
</ribbon:RibbonGroup>-->
CS:
using Microsoft.Practices.Prism.Regions;
//using Microsoft.Windows.Controls.Ribbon;
namespace Prism4Demo.ModuleB.Views
{
/// <summary>
/// Interaction logic for ModuleBRibbonTab.xaml
/// </summary>
public partial class ModuleBRibbonTab : IRegionMemberLifetime
{
#region Constructor
public ModuleBRibbonTab()
{
InitializeComponent();
}
#endregion
#region IRegionMemberLifetime Members
public bool KeepAlive
{
get { return false; }
}
#endregion
}
}
模块类:
public class ModuleC : IModule
{
#region IModule Members
/// <summary>
/// Initializes the module.
/// </summary>
public void Initialize()
{
/* We register always-available controls with the Prism Region Manager, and on-demand
* controls with the DI container. On-demand controls will be loaded when we invoke
* IRegionManager.RequestNavigate() to load the controls. */
// Register task button with Prism Region
var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
regionManager.RegisterViewWithRegion("TaskButtonRegion", typeof(ModuleBTaskButton));
/* View objects have to be registered with Unity using the overload shown below. By
* default, Unity resolves view objects as type System.Object, which this overload
* maps to the correct view type. See "Developer's Guide to Microsoft Prism" (Ver 4),
* p. 120. */
// Register other view objects with DI Container (Unity)
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
container.RegisterType<Object, ModuleBRibbonTab>("ModuleBRibbonTab");
container.RegisterType<Object, ModuleBNavigator>("ModuleBNavigator");
container.RegisterType<Object, ModuleBWorkspace>("ModuleBWorkspace");
}