【问题标题】:Avoiding fatter view models in MVVM避免在 MVVM 中使用更胖的视图模型
【发布时间】:2014-03-17 09:57:59
【问题描述】:

我正在开发一个遵循 MVVM 模式的 WPF 应用程序。尽管将验证转移到服务中,但我最终得到了一个运行多行代码的胖视图模型(在我的例子中接近 1000 行)。 我在这里添加了视图模型的接口。我有一些作为组合公开的集合,并且基于组合选择,我必须执行验证/调用服务/将过滤应用于其他组合

public interface ISampleViewModel         {
        ObservableCollection<InstrumentDto> Collection1 { get; set; }
        ObservableCollection<TenderViewConfigDetailViewModel> Collection2 { get; set; }
        ObservableCollection<TenderViewConfigDetailViewModel> Collection3 { get; set; }
        ObservableCollection<TenderViewConfigDetailViewModel> Collection4 { get; set; }
        ObservableCollection<TenderViewConfigDetailViewModel> Collection5 { get; set; }
        TenderViewConfigDetailViewModel SelectedViewConfigDetail { get; set; }
        int SelectedTenderViewIndex { get; set; }
        int SelectedInstrumentsViewIndex { get; set; }
        SortableCollection<TenderViewToInstrumentViewModel> CurrentInstruments { get; set; }
        TenderViewToInstrumentViewModel SelectedInstrumentForTenderView { get; set; }
        InstrumentDto SelectedInstrument { get; set; }
        bool IsAllInstrumentsFocused { get; set; }
        ICommand ApplyChangesCommand { get; }
        ICommand AddTenderPanelViewCommand { get; }
        ICommand DeleteTenderPanelViewCommand { get; }
        ICommand ModifyTenderViewVisiblityCommand { get; }
        ICommand AddInstrumentsToPanelViewCommand { get; }
        ICommand DeleteInstrumentsFromPanelViewCommand { get; }
        ICommand MoveUpTenderListViewCommand { get; }
        ICommand MoveDownTenderListViewCommand { get; }
        ICommand MoveUpInstrumentsCommand { get; }
        ICommand MoveDownInstrumentsCommand { get; }
        bool IsValidModel { get; }
        void PublishTenderViewConfigChanges(TenderViewConfigDetailViewModel viewModel,EventActionType actionType);
    }

上述一组功能使我的视图模型变得更庞大。我怎样才能避免它?我想不出将功能分解成更小的控件,因为它们是依赖的?我在这里遗漏了什么吗?

【问题讨论】:

  • 为什么你的视图模型很胖?能给我举个例子吗?假设它解决了一个简单的问题,那么 1000 行视图模型没有任何问题。如果您使用单个视图模型覆盖 10 个基础,那么可能是时候重构了

标签: wpf mvvm prism-4


【解决方案1】:

如果你在ViewModel中存储了可以隔离在单独类中的属性,最好将它们移动到单独的Model中。大量属性漂亮地加载ViewModel,对于每种类型的属性,您应该创建您的Model。虽然在这个场合有一些争论,但我相信如果在ViewModel 中将链接到几个Models 并没有错。关于这个主题,您可以看到以下答案:

In MVVM, is every ViewModel coupled to just one Model?

使用单独模型的示例:

Model

public class MainMenuModel : NotificationObject // Here also implemented INotifyPropertyChanged interface
{
    private bool _buttonIsEnabled = true;

    public bool ButtonIsEnabled
    {
        get
        {
            return _buttonIsEnabled;
        }

        set
        {
            _buttonIsEnabled = value;
            NotifyPropertyChanged("ButtonIsEnabled");
        }
    }     
}

ViewModel

public class MainMenuViewModel
{
    private MainMenuModel _mainMenuModel = null;

    public MainMenuModel MainMenuModel
    {
        get
        {
            return _mainMenuModel;
        }

        set
        {
            _mainMenuModel = value;
        }
    }

    ...

    public MainMenuViewModel() 
    {
        MainMenuModel = new MainMenuModel();
    }
}

View

<Button IsEnabled="{Binding Path=MainMenuModel.ButtonIsEnabled}" ... />

唯一可以留在ViewModel边上的东西,它的Commands和IDataErrorInfo接口实现,虽然IDataErrorInfo的实现也可以移到Model边上。

另外,如果 Command 的实现占用大量空间,您可以创建单独的函数/过程,可以调用例如 Helper 并放置在合适的类中。其次,在Command中没有写完整的实现,有必要参考这个方法。

例如:

private ICommand _findCommand = null;

public ICommand FindCommand
{
    get
    {
        if (_findCommand == null)
        {
            _findCommand = new RelayCommand(param => this.Find(), null);
        }

        return _findCommand;
    }
}

private void Find()
{
    // Here instead of writing large code, 
    // moving find logic to separate static class

    SomeHelper.FindPerson(MainModel.SearchName);
}

因此,本例中的 Command 是 ViewModel 中调用方法的包装器。

【讨论】:

  • 感谢您的解决方案。您的意思是说将功能移动到较小的视图模型中并将其公开在主/父视图模型中。在这里,我可以看到实现 NotificationObject 的模型并不理想。通常,通知应该保存在 viewmodel 而不是 model
  • @Hunter: I can see a model implementing a NotificationObject which is not ideal. - 每个人选择在哪里实现它,这不是很重要。我建议将单独的Model中的属性移动,不要将它们都写在ViewModel中。引用单个对象比引用十个属性要容易得多。我还添加了一些关于命令的想法,请参阅我的编辑。
  • 是应该是 POCO 的模型。如果我们决定在服务中使用相同的模型,会有问题吗?
  • @Hunter:是的,模型可以是 POCO。我认为模型是MVVM 中最抽象的部分之一,如果这是正确定义的抽象,我认为在服务中使用这些模型时不会出现问题。
猜你喜欢
  • 2010-10-25
  • 2013-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-04
  • 2018-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多