视图,ViewModels,“WindowViewModels”......我在这里缺少什么?

时间:2013-07-11 21:16:36

标签: c# wpf mvvm architecture inversion-of-control

在表示逻辑层(PLL)中,我有所谓的“视图模型”类,它们实现/扩展业务逻辑层(BLL)中定义的接口,如下所示:

namespace BLL.Abstract.POCO
{
    // also implemented in data access layer (DAL) by data model entities
    public interface ISomeDomainModelEntity
    {
        string Name { get; set; }
        string Description { get; set; }
    }
}

namespace PLL.Abstract.ViewModels
{
    public interface ISomeDomainModelEntityViewModel 
                     : ISomeDomainModelEntity, INotifyPropertyChanged
    {
        bool IsSelected { get; set; }
    }     
}

namespace PLL.Concrete.ViewModels
{
    public class SomeDomainModelEntityViewModel 
                 : ViewModelBase, ISomeDomainModelEntityViewModel
    {
        private string _name;
        private string _description;
        private bool _isSelected;

        public string Name { get { return _name; } set { _name = value; NotifyPropertyChanged(() => Name); } }
        public string Description { get { return _description; } set { _description = value; NotifyPropertyChanged(() => Description); } }
        public bool IsSelected { get { return _isSelected; } set { _isSelected = value; NotifyPropertyChanged(() => IsSelected); } }
    }
}

请注意,ViewModelBase是一个抽象类,允许这种强烈的强类型INotifyPropertyChanged实现。

上述实现的IsSelected属性显然只在表示层中显示(可视化列表中显示的几个这些对象,其中ItemTemplate具有绑定其ListBox的{​​{1}} IsChecked属性IsSelected),表示逻辑在返回业务逻辑层之前知道如何使用它。

我遇到的问题是,我发现名称“ViewModel”与此冲突:

namespace PLL.Abstract.ViewModels // hmmm...
{
    public interface ISomeWindowViewModel
    {
        ObservableCollection<ISomeDomainModelEntityViewModel> SomeItems { get; }
    }
}

ISomeWindowViewModel的实施最终分配给视图的DataContext属性:

namespace PLL.Concrete.ViewModels
{
    public class SomeWindowViewModel : WindowViewModelBase, ISomeWindowViewModel
    {
        private readonly ObservableCollection<ISomeDomainModelEntityViewModel> _items;

        public SomeWindowViewModel(IView view, ObservableCollection<ISomeDomainModelEntityViewModel> items)
            : base(view)
        {
            _items = items;
        }

        public ObservableCollection<ISomeDomainModelEntityViewModel> SomeItems { get { return _items; } set { _items = value; } }
    }
}

namespace PLL.Abstract
{
    public abstract class WindowViewModelBase : ViewModelBase
    {
        public IView View { get; private set; }

        protected WindowViewModelBase(IView view)
        {
            View = view;
            View.DataContext = this;
        }
    }
}

这是我在阅读了Mark Seeman的 .NET中的依赖注入中如何将DI应用于WPF之后开始的重大重构的结果(迄今为止的优秀阅读,尚未完成)虽然起初将View实现注入到ViewModel中似乎有些倒退,但我可以理解通过处理视图的显示和关闭获得的控制/简单性。在重构之前,我有一个带有BLL的工作应用程序,它与DAL和PLL紧密耦合;现在BLL没有任何依赖关系,而且非常棒。

我仍然在重新配置组合根目录(使用Ninject.Extension.Conventions),所以在一天结束时我可能会意识到我需要进行一些调整才能使其全部工作。 ..它可能会受伤,但我已经准备好了!

所以问题如下:

  • 我觉得我的接口太多了,但我使用常规的DI配置完全是绿色的(好吧,完全是绿色的DI一起!);当类型实现接口时,按照惯例配置IoC容器似乎要容易得多......但这有点过分吗?
  • “ViewModel”一词在这里被滥用吗?或者更确切地说,“ViewModel”和“WindowViewModel”之间的区别是保证还是我遗漏了什么? ViewModel“包含”其他ViewModel是否正常?如果没有,是否可以为在View中用作DataContext的ViewModel提供一些“WindowViewModel”名称?
  • 这里是否有任何明显的建筑缺陷会最终导致代码库陷入混乱?我的想法是尽可能使用DI实现MVVM,但我想我还有很多需要学习的东西。
  • 来自去年的
  • This question出现在我输入这篇文章的“类似问题”列表中,并且真正开始在我的脑海中进一步模糊 - 接受的答案和其他评论与我的内容完全相反最近一直在读。具体来说,一个ViewModel类应该注入一些IView实现 - 这个问题/答案+注释正好相反,这就是我首先提到的(一个注入了一些IViewModel实现的View)。看起来这两种方式都是完全可以接受的,这只是个人偏好的问题?

1 个答案:

答案 0 :(得分:1)

  1. 在我看来,太多了。架构应该是灵活的,当你闻到什么东西时,你可能不会像IOC那样坚持使用其中一种技术。一方面我没有看到ISomeDomainModelEntityViewModel,ISomeWindowViewModel和IObservableCollection的好处,每个接口只有一个类,除了DI,另一方面,接口对于DI不是必需的。我想你可以看看Prism的例子,看看他们如何使用DI构建ViewModel以及何时使用接口。通常,如果要使用DI构建ViewModel,ViewModel的所有依赖项都是在接口中定义的服务,并使用IOC来解析这些服务。由于这些服务具有外部依赖性,因此模拟这些接口以进行测试很容易。但是,大多数ViewModel都没有接口,因为它们主要由View和其他ViewModel使用。

  2. 我认为ViewModel可以包含其他ViewModel,例如主ViewModel包含每个页面的子项。

  3. 不明显。除了接口之外,我个人认为将IObservableCollection放入IOC并不是一个好方法。

  4. 我个人认为注入IView会破坏MVVM,因为ViewModel不应该知道View。即使是IView,ViewModel也可以引用View。但是在某些情况下,如果ViewModel有一个IView可以让很多事情变得更容易,为什么不呢?正如我所说,架构应该是灵活的。

  5. 希望它可以提供帮助。

相关问题