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控件,其中显示了具有不同视图模型的不同视图。顺序为:

  1. 在控制器类
  2. 中创建视图模型
  3. 配置视图模型
  4. 将视图模型添加到控制器中的本地集合
  5. 将视图模型添加到区域

我正在寻找的缺失部分是如何使它发生,视图是"自动"创建的所有东西,如绑定等。我在本文中找到了一种方法(http://www.codeproject.com/Articles/229931/Understand-MVVM-Using-PRISM-by-Hello-World-Silverl)。我必须为视图和视图模型(IAnotherViewModel, IAnotherView)创建自己的接口。

另一种方法可以在这里找到:http://paulstovell.com/blog/viewmodel-first-prism

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*/