使用 MVVM 模式时,与属性更改相关的代码应该放在 setter 中还是事件中?

发布于 2024-09-24 03:00:28 字数 1762 浏览 2 评论 0原文

寻找有关在何处放置取决于属性更改的代码的指导。

例如,我有一个视图模型,用于保存应用程序设置的状态

public SettingsViewModel(ISettingsRepository settings)
{
    _settings = settings;
    // ...
}

对于设置属性的每次更改,我们都必须将此更改保存到存储库,并且在某些属性上,其他属性会受到影响,因此需要额外的代码。

我一开始只是将此逻辑添加到设置器中

public ProjectCollection Projects
{
    get { return _projects; }
    set
    {
        if (_projects == value) return;
        _projects = value;
        RaisePropertyChanged("Projects");

        // Extra work needed when collection of projects change
        _settings.SaveProjects(_projects);
        Startable = _projects != null && _projects.Count > 0;
    }
}

,但随后切换到为 INotifyPropertyChanged 连接 PropertyChanged 事件,并从属性设置器中删除了附加

public SettingsViewModel(ISettingsRepository settings)
{
    _settings = settings;
    // ...
    PropertyChanged += onPropertyChanged;
}

void onPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "Projects":
            _settings.SaveProjects(Projects);
            Startable = Projects != null && Projects.Count > 0;
            break;
        // ...
    }
}

public ProjectCollection Projects
{
    get { return _projects; }
    set
    {
        if (_projects == value) return;
        _projects = value;
        RaisePropertyChanged("Projects");
    }
}

代码setter 意味着要编写的代码更少,连接错误属性名称的错误机会也更少(单元测试应该会发现这一点),并且速度会稍微快一些,尽管可能微不足道。

将逻辑连接到事件似乎是一种更易于维护的方法,只要方法被适当命名,就应该更容易遵循代码,并且意味着设置器除了设置属性之外不做其他工作。我猜测它也可能提供更大的灵活性,使用上面的示例,如果需求发生变化,从而使另一个事件发生的更改(例如“保存”按钮单击而不是属性更改)发生,那么代码应该更容易更改。

我明白这是一个主观问题,但我对 MVVM 模式很陌生(尽管我猜它可能适用于任何 setter 逻辑?),所以在我决定采用一种方法之前,我正在寻找其他原因。谢谢!

Looking for guidance on where to place code which is dependent upon changes to a property.

For example, I have a view model which is used to hold state for an applications settings

public SettingsViewModel(ISettingsRepository settings)
{
    _settings = settings;
    // ...
}

For each change to a settings property we have to persist this change to the repository, and on some properties, other properties are affected, so additional code is required.

I started off just adding this logic to the setter

public ProjectCollection Projects
{
    get { return _projects; }
    set
    {
        if (_projects == value) return;
        _projects = value;
        RaisePropertyChanged("Projects");

        // Extra work needed when collection of projects change
        _settings.SaveProjects(_projects);
        Startable = _projects != null && _projects.Count > 0;
    }
}

But then swapped over to wiring up the PropertyChanged event for INotifyPropertyChanged and removed the additional code out of the property setter

public SettingsViewModel(ISettingsRepository settings)
{
    _settings = settings;
    // ...
    PropertyChanged += onPropertyChanged;
}

void onPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "Projects":
            _settings.SaveProjects(Projects);
            Startable = Projects != null && Projects.Count > 0;
            break;
        // ...
    }
}

public ProjectCollection Projects
{
    get { return _projects; }
    set
    {
        if (_projects == value) return;
        _projects = value;
        RaisePropertyChanged("Projects");
    }
}

Having the logic inside the setter means less code to write, less chance of making a mistake wiring up the wrong property name (unit test should pick this up though) and would be slightly faster, although probably insignificant.

Having the logic wired up to an event seems to be a more maintainable approach, so long as the methods are appropriately named it should be easier to follow the code, and means the setter isn't doing other work besides setting the property. I'm guessing it might also provide more flexibility, using the example above, if the requirements changed so that persisting of changes happened from another event e.g. "Save" button click instead property change, then the code should be easier to change.

I appreciate this is a subjective question, but I'm new to the MVVM pattern (although I guess it may hold true for any setter logic?) so am looking for other reasons before I settle on an approach. Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

独闯女儿国 2024-10-01 03:00:28

在决定将哪些代码放在哪里时,请记住这一点:ViewModel 用于将数据呈现给 View。它可以稍微修改或操纵数据来做到这一点(当然是在合理的范围内 - 将值更改为颜色可以被认为是绝对可以做到的)。 ViewModel 不了解有关 UI 的任何信息,也不了解有关保存数据的任何信息。

属性设置器应该尽可能简单,并且它们应该通知是否有任何东西依赖于它们(大多数情况都是这样 - VM 用于绑定)。这意味着利用 OnPropertyChanged() 事件处理程序的第二个示例是比第一个示例更好的选择。

但是,它仍然知道太多我不喜欢的东西。我会提出模型可以订阅的事件,并让模型完成工作。 ViewModel 应该只是说“嘿,我的数据已经改变,我不在乎你对此做什么,但我已经告诉过你,所以做你喜欢做的事”。然后,模型可以立即保存,或者直到发生更多更改后再保存数据。

When deciding what code to put where, remember this: a ViewModel is for presenting the data to the View. It can massage or manipulate the data a little to do so (within reason of course - changing a value to a color could be considered absolutely fine to do). The ViewModel doesn't know anything about the UI, and it doesn't know anything about saving data.

The property setters should be kept as simple as possible, and they should notify if anything relies on them (which mostly will be the case - the VM is used for binding). This means that your second example utilizing the OnPropertyChanged() event handler is a far better option than the first example.

However, it still knows too much for my liking. I would raise events which the Model can subscribe to, and let the Model do the work. The ViewModel should just say "hey, my data has changed, I don't care what you do about it but i've told you so do whatever you like". The Model can then either save instantly, or what till more changes have taken place before persisting the data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文