c# - MVVM:如何设计托管不同应用程序的窗口?

标签 c# wpf mvvm

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

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

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

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

  • 方法选择屏幕需要一个
    可用方法列表。
  • 主屏幕需要知道是什么方法
    选择并选择合适的
    viewmodel 来显示结果。
  • 以某种方式加载的数据需要进入执行实际工作的类,结果 View 模型需要知道这一点才能知道从哪里获取数据。

  • 我能想到的一切都让 MainWindowViewModel 完成不同 View 模型和模型类之间的所有协商。

    我将如何优化设计这个?

    最佳答案

    对于它的值(value),我帮助实现了一个类似复合应用程序的模块。所以以下是基于轶事经验,

  • 首先,我们的应用程序或“shell”需要“可用”方法的显式枚举。我们可以以任何我们希望的方式提供它,无论是显式(通过配置)还是隐式(通过反射)。作为偏好,我更喜欢前者,因为它不那么“神奇”。
  • 对于第二点,除了显式枚举之外,我们的 shell 还必须维护从选择到实现的映射。 Again, this may be accomplished any number of ways, but typically our enumeration is a list of "Types", and when a type is selected we request an implementation of that type from a factory.实现此模式的最简单方法是利用控制反转容器,例如 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/

    相关文章:

    c# - WPF MVVM 触发代码基于 Tab SelectedValue,而不是 SelectedIndex

    C# 能力?

    c# - GMail SMTP 通过 C# .Net 所有端口上的错误

    wpf - WPF 中高效的实时日志查看器

    c# - 提交 ViewModel 中当前 WPF GUI 元素的编辑

    c# - 将 ViewModel 连接到模型

    c# - 模拟 IConfiguration 的 GetChildren() 以返回 List<string>?

    wpf - 像飘落的雪花一样移动元素

    c# - 从 ObservableConcurrentCollection 中删除项目

    wpf - 将 DataGrid 中的文本框聚焦在 CheckBox 的选中事件上