我正在尝试使用MVVM设计模式实现一个简单的WPF数据分析应用程序,其中可以使用几种不同的方法来分析某些数据(从文件中加载)。

在第一个屏幕中,用户应该能够选择他喜欢采用的方法。在他完成该操作并加载数据后,以前由方法选择屏幕占据的区域应由分析结果替换。

当前,我的MainWindowViewModel具有类型对象object的属性“CurrentViewModel”,可以将其设置为方法选择 View 模型或分析结果 View 模型中的一个,然后使用数据模板进行呈现。

我面临的问题是,我不知道不同的 View 模型应该如何通信。

  • 方法选择屏幕需要一个
    可用方法列表。
  • 主屏幕需要知道什么方法
    选择并选择合适的
    viewmodel显示结果。
  • 装入的数据需要以某种方式进入类中进行实际工作,并且结果viewmodel需要知道这一点才能知道从何处获取其数据。

  • 我能想到的所有内容都使MainWindowViewModel可以在不同的ViewModel和Model类之间进行所有协商。

    我将如何优化设计呢?

    最佳答案

    对于它的值(value),我帮助实现了一个用于类似Composite Application的模块。因此,以下内容基于轶事经验,

  • 首先,我们的应用程序或“ shell ”需要对“可用”方法进行显式枚举。我们可以提供任何希望的方式,无论是显式的(通过配置)还是隐式的(通过反射)。作为优先选择,我赞成前者,因为它不太“神奇”。
  • 第二点,除了显式枚举,我们的shell还必须维护从选择到实现的映射。同样,这可以实现多种方式,但通常我们枚举“类型”列表,当选择一个类型,我们要求该类型从工厂的实现。实现此模式的最简单方法是利用Control Inversion容器,例如CaSTLe Windsor,Unity,Ninject等。老实说,我不记得我们在内部使用的容器。

  • 例如,考虑
    // a simple Plain Old C Object that describes business methods.
    public class BusinessMethod
    {
        // user-friendly name
        public string Name { get; set; }
        // type that actually implements
        public Type ImplementationType { get; set; }
    }
    
    // ... meanwhile, back on the ranch ...
    public void OnBusinessMethodSelection ()
    {
        // 1. if selected
        if (BusinessMethodList.SelectedItem != null)
        {
    
            // 2. retrieve selected item
            BusinessMethod selected =
                (BusinessMethod)(BusinessMethodList.SelectedItem);
    
            // 3. request implementation of selected item from
            // IoC container
            object implementation =
                _container.Resolve (selected.ImplementationType);
        }
    }
    
  • 关于您的第三点,我们需要一种使不同零件进行通信的方法。不幸的是,我们不能依靠设计时方法(即命令和数据绑定(bind)),因此我们必须实现自己的事件聚合服务。基本上是一个了解订阅者和发布者的“单例”(例如在单个实例中不是静态类),最好是一个提供强类型参数的实现。对我们来说幸运的是,有很多大个子走在我们前面,我们可能会从他们的经验中受益。查看Kent Boogaart的Event Hub

  • 这是我们如何使用事件聚合器的示例
    // an example of a strongly typed subject. notice how subject
    // defines content. semanticly, when someone creates and publishes
    // an instance of this subject, they are requesting someone show
    // an analysis view based on data content,
    public class AnalysisSubject
    {
        // subject content, in this case a data result from
        // a business method
        public object Data { get; set; }
    }
    
    public class MainWindow : ISubscriber<AnalysisSubject> ...
    {
    
        // use whatever implementation of an IoC container we like
        // here i assume we abstract from implementation and use a
        // custom interface IContainer that exposes functionality
        // that we need
        private readonly IContainer _container = null;
        public class MainWindow ()
        {
            // we're teh r00tz! we create an instance of IoC
            // container for use throughout application
            IContainer _container = new CustomContainer ();
    
            // our container exposes both parameterized and
            // type-parameterized resolve methods
            IEventHub events = _container.Resolve<IEventHub> ();
            events.Subscribe<AnalysisSubject> (this);
        }
    
        #region ISubscriber<AnalysisSubject>
    
        // part of strongly typed subscriptions is that we
        // may now handle strongly typed publications! yay!
        public void Receive (AnalysisSubject subject)
        {
            // 1. request to display analysis of data
            Type analysisType = subject.Data.GetType ();
    
            // 2. get view control based on payload type
            //
            // NOTE: implicit usage below is not consistent
            // with previous invocations, here we are submitting
            // a type of something we already have, and actually
            // want back something that knows how to handle it.
            // most IoC containers can provide this functionality
            // through "facilities" add ons that accept a
            // parameter\discriminator like below, and produce
            // something in return.
            Control control = (Control)(_container.Resolve (analysisType));
    
            // [alternatively] if the above is too "magical" where
            // IAnalysisFactory is an interface we define for this
            // express purpose
            //IAnalysisFactory factory = _container.Resolve<IAnalysisFactory> ();
            //Control control = factory.GetAnalysisControlFor (analysisType);
    
            // 3. assign subject data to control
            Control.DataContext = subject.Data;
    
            // 4. display control
        }
    
        #endregion
    
    }
    

    和出版的例子
    public class SomeBusinessView
    {
    
        private readonly IEventHub _events = null;
    
        // we cannot function without an event aggregator of
        // some kind, so we declare our dependency as a contructor
        // dependency
        public SomeBusinessView (IEventHub events)
        {
            _events = events;
        }
    
        public void DoMyThang ()
        {
            // 1. do some business
            MyBusinessData data = SomeBusinessFunction ();
            // 2. publish complete event
            AnalysisSubject subject = new AnalysisSubject () { Data = data, };
            _events.Publish (subject);
        }
    
    }
    

    关于c# - MVVM:如何设计一个承载不同应用程序的窗口?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3864246/

    10-12 00:28
    查看更多