2015-06-05 35 views
3

注册事件处理程序从硬件层传播事件到数据层到UI层的推荐位置在哪里?情况如下:使用ServiceLocator引导程序在MVVM应用程序中注册事件处理程序的正确位置?

  • 在C#的应用/ .NET
  • MVVM图案用于
  • 引导程序被实施,使用具有微软统一框架实现的服务定位

简化,有是三层,用汇编分隔:

  • UI.dll(UI层,包含ViewModel和View)
  • Data.dll(模型层)
  • HardwareAbstraction.dll(硬件层)

入口点是starter.exe,含有该引导程序和设置的ServiceLocator。其他库使用该ServiceLocator。 UI.dll然后从ServiceLocator获取数据接口。

在ViewModel中,需要显示一些数据,数据一到达硬件即可。数据流是:扫描仪像硬件 - > HardwareAbstraction.dll - > Data.dll - > UI.dll。从一个DLL到下一个,会触发一个事件通知监听器新数据已到达。

在这些事件中注册事件处理程序的最佳位置在哪里?

在应用程序中,目前没有真正的概念,很多是在构造函数中完成的,但它对我来说似乎不正确。让他们在构造函数中,经常打破我的单元测试(在现有应用程序中引入单元测试)和设计时间ViewModels(使用C#而不是Xaml)。

回答

1

一般来说,我尽量避免使用全球服务定位器。我认为这是一种反模式。不要在viewModels中使用它。它会使测试成为一个熊。只需在构造函数中传递依赖关系即可。每个应用程序都有一个主IoC容器:我的主引导程序。然后我在一些工厂注册的人少得多。我从不暴露容器。这个计划是在多年的战斗中失踪和过时的依赖。

viewModel级别应该使用PropertyChanged和ObservableCollection的东西来暴露它的事件。如果你能够帮助,没有人应该以编程方式注册这些人;它们应该全部用于UI级别的绑定。硬件抽象只是模型级实体的另一种形式。它是(数据的来源)。您可以有多个数据/模型图层。

在(viewModel或模型管理器)构造函数中注册模型级事件是正确的。在Dispose中清理它们。我已经做了一件事,使其更清洁一点就是在有人注册时在模型中触发事件。它看起来像这样:

class ModelManager: IModelManager { 
    ... 
    private Action<IModel> _modelAdded = delegate {}; 
    public event Action<IModel> ModelAdded { 
    add { 
     _modelAdded = Delegate.Combine(_modelAdded, value); 
     foreach(var model in Models) 
      value.Invoke(model); 
    } 
    remove { ... } 
    } 
    ... 
} 

class ModelManagerVM: ViewModelBase { 
    public ModelManagerVM(IModelManager mgr, IModelVMFactory factory) { 
     _factory = factory; 
     _mgr = mgr; 
     _mgr.ModelAdded += OnModelAdded; // triggers on subscribe 
    } 
    private void OnModelAdded(IModel model) { // never virtual 
     // use a dispatcher to push this to the UI thread 
     var existing = _modelVMs.FirstOrDefault(m => m.ID == model.ID); 
     if (existing != null) existing.Model = model; 
     else _modelVMs.Add(_factory.Create(model)); 
    } 
    public void Dispose() { 
     _mgr.ModelAdded -= OnModelAdded; // always unsubscribe on passed-in deps 
    } 
} 
相关问题