PRISM:如何向区域添加视图模型并自动创建视图
本文关键字:视图 模型 创建 添加 区域 PRISM | 更新日期: 2023-09-27 18:08:31
我是PRISM的新手,正在尝试一些东西。我对MVVM有点纠结
将视图与视图模型"连接"的方式很清楚:
-
统一注入,或
-
手动设置数据上下文(ServiceLocator)
如果我添加一个视图到一个区域(视图模型是自动创建的),一切都很好。但这不是用例。
让我们看一下这个例子:
public class MyViewModel : NotificationObject
{
public ObservableCollection<AnotherViewModel> OrderModel { get; private set; }
}
我必须创建视图模型并将它们添加到集合中。这个视图模型必须在一个区域(OrderRegion)中显示(AnotherView)。我的问题是,我如何才能实现,现在的视图是创建时,我添加一个视图模型到一个区域。这个区域是TabControl,所以可能会出现必须显示不同视图的情况。
我已经看了PRISM快速入门和StockTrader示例。我要找的东西与
非常相似 virtual protected void StartOrder(string tickerSymbol, TransactionType transactionType)
{
if (String.IsNullOrEmpty(tickerSymbol))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.StringCannotBeNullOrEmpty, "tickerSymbol"));
}
this.ShowOrdersView();
IRegion ordersRegion = _regionManager.Regions[RegionNames.OrdersRegion];
var orderCompositeViewModel = ServiceLocator.Current.GetInstance<IOrderCompositeViewModel>();
orderCompositeViewModel.TransactionInfo = new TransactionInfo(tickerSymbol, transactionType);
orderCompositeViewModel.CloseViewRequested += delegate
{
OrderModels.Remove(orderCompositeViewModel);
commandProxy.SubmitAllOrdersCommand.UnregisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelAllOrdersCommand.UnregisterCommand(orderCompositeViewModel.CancelCommand);
commandProxy.SubmitOrderCommand.UnregisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelOrderCommand.UnregisterCommand(orderCompositeViewModel.CancelCommand);
ordersRegion.Remove(orderCompositeViewModel);
if (ordersRegion.Views.Count() == 0)
{
this.RemoveOrdersView();
}
};
ordersRegion.Add(orderCompositeViewModel);
OrderModels.Add(orderCompositeViewModel);
commandProxy.SubmitAllOrdersCommand.RegisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelAllOrdersCommand.RegisterCommand(orderCompositeViewModel.CancelCommand);
commandProxy.SubmitOrderCommand.RegisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelOrderCommand.RegisterCommand(orderCompositeViewModel.CancelCommand);
ordersRegion.Activate(orderCompositeViewModel);
}
视图模型在代码中创建并添加到区域中。整个regestring类型是通过"ViewExportAttribute"发生的,所以很难理解它背后的模式。
编辑:我已经找到了一种手动执行此操作的方法,但它不是很好:
var view = (FrameworkElement) ServiceLocator.Current.GetInstance<AnotherView>();
var model = ServiceLocator.Current.GetInstance<AnotherViewModel>();
view.DataContext = model;
regionManager.Regions["OrderRegion"].Add(view, null, true);
regionManager.Regions["OrderRegion"].Activate(view);
罗马EDIT2:
嗨,我很抱歉,也许我没听清楚。
我的目标是创建一个视图模型,然后像上面StockTrader的例子那样配置它:订阅事件、命令等。之后,我想将这个视图模型添加到区域,这样它就可以显示了。该区域可能是一个tab控件,其中显示了具有不同视图模型的不同视图。顺序为:
- 在控制器类 中创建视图模型
- 配置视图模型
- 将视图模型添加到控制器中的本地集合
- 将视图模型添加到区域
我正在寻找的缺失部分是如何使它发生,视图是"自动"创建的所有东西,如绑定等。我在本文中找到了一种方法(http://www.codeproject.com/Articles/229931/Understand-MVVM-Using-PRISM-by-Hello-World-Silverl)。我必须为视图和视图模型(IAnotherViewModel, IAnotherView)创建自己的接口。
另一种方法可以在这里找到:http://paulstovell.com/blog/viewmodel-first-prism
是否有理由不使用隐式DataTemplates
?
它们是定义DataType
属性的DataTemplates
,而不是Key
属性,并且它们在WPF试图绘制指定DataType的对象时使用
<TabControl ItemsSource="{Binding MyViewModelCollection}"
SelectedItem="{Binding SelectedViewModel}">
<!-- This could also go elsewhere, like Application.Resources -->
<TabControl.Resources>
<DataTemplate DataType="{x:Type local:ViewModelA}">
<local:ViewA />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelB}">
<local:ViewB />
</DataTemplate>
</TabControl.Resources>
</TabControl>
如果TabControl
显示的是ViewModelA
类型的对象,它将使用ViewA
来绘制,如果它显示的是ViewModelB
,它将使用ViewB
来绘制
如果你正在使用MEF,那么你可以使用属性自动注册你的视图:
/*YOUR VIEW*/
[ExportViewToRegion("MyView", "MyRegion")]
[Export(typeof(MyView))]
public partial class MyView : UserControl
{
....
}
/*IMPLEMENTATION*/
public interface IExportViewToRegionMetadata
{
string ViewName { get; }
string TargetRegion { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = false)]
public class ExportViewToRegionAttribute : ExportAttribute
{
public ExportViewToRegionAttribute(string viewName, string targetRegion)
: base(typeof(UserControl))
{
ViewName = viewName;
TargetRegion = targetRegion;
}
public string ViewName { get; private set; }
public string TargetRegion { get; private set; }
}
[Export(typeof(IFluentRegionManager))]
public class FluentRegionManager : IFluentRegionManager, IPartImportsSatisfiedNotification
{
public IRegionManager RegionManager { get; set; }
[ImportingConstructor]
public FluentRegionManager(IRegionManager regionManager)
{
RegionManager = regionManager;
}
/*This Import will find all views in the assembly with attribute [ExportViewToRegion("ViewName", "RegionName")]*/
[ImportMany(AllowRecomposition = true)]
public Lazy<UserControl, IExportViewToRegionMetadata>[] Views { get; set; }
private readonly List<string> _processedViews = new List<string>();
private Lazy<UserControl, IExportViewToRegionMetadata> _GetViewInfo(string viewName)
{
return (from v in Views where v.Metadata.ViewTypeForRegion.Equals(viewName) select v).FirstOrDefault();
}
public IExportViewToRegionMetadata this[string viewName]
{
get
{
return (from v in Views
where v.Metadata.ViewName.Equals(viewName, StringComparison.InvariantCultureIgnoreCase)
select v.Metadata).FirstOrDefault();
}
}
public void ExportViewToRegion(string viewName)
{
if (viewName==null)
{
throw new ArgumentNullException("viewName");
}
var viewInfo = _GetViewInfo(viewName);
string targetRegion;
UserControl _view;
if (viewInfo != null)
{
targetRegion = viewInfo.Metadata.TargetRegion;
_view = viewInfo.Value;
}
if (string.IsNullOrEmpty(targetRegion) || _processedViews.Contains(viewName)) return;
RegionManager.RegisterViewWithRegion(targetRegion, _view.GetType());
_processedViews.Add(viewName);
}
/*All required views has been discovered and imported */
/*Loop true collection and register view with the region */
public void OnImportsSatisfied()
{
foreach (var viewName in from view in Views where !_processedViews.Contains(view.Metadata.ViewName)
select view.Metadata.ViewName)
{
ExportViewToRegion(viewName);
}
}
}
/* finally call IFluentRegionManager import in the bootstrapper to kick off registration*/