MVVM共享属性

本文关键字:属性 共享 MVVM | 更新日期: 2023-09-27 17:59:04

SO上也有一些类似的问题,但它们并不完全一样,所以我改为发布这篇文章。我是MVVM的新手,所以我想知道如何创建一个类,该类可以包含可以在视图之间共享的属性。因此,如果我在一个视图中设置了一个属性,那么如果它发生了更改,所有其他视图都会收到通知,并相应地调整它们的属性。

我现在拥有的东西相当粗糙,绝对不是我想用的东西。这是我的公共类,它将包含所有属性:

public static class Common
{
    private static string _title;
    public static string Title
    {
        get { return _title; }
        set
        {
            if (_title == value)
            {
                return;
            }
            _title = value;
            OnPropertyChanged("Title");
        }
    }
    public static void Load()
    {
        // set properties here
    }
    public static event PropertyChangedEventHandler PropertyChanged;
    private static void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(typeof(SettingsWorker), new PropertyChangedEventArgs(name));
        }
    }
}

我必须从每个ViewModel订阅它:

Common.PropertyChanged += Common_PropertyChanged;
private void Common_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    Title = Common.Title;
}

但这就是崩溃发生的地方。我可以从PropertyChangedEventArgs中获取属性名称,但我不知道如何获取值。因此,我不得不更新所有的属性,这可能会让维护变得很麻烦。代码变得一团糟。

我基本上是在尝试获得ViewModels可以共享的属性。我怎样才能做到这一点?

MVVM共享属性

看起来您只需要在多个位置显示一些全局数据。要做到这一点,最简单的方法是让它像普通的ViewModel类,然后让它对其他每个ViewModel都可用,并从它们中公开它以直接绑定到(而不是将属性复制到每个ViewModel中)。你可以使用IOC来实现这一点,或者使其静态可用,更类似于你现在的方式。

如果您采用静态方向,则需要进行的关键更改是使用singleton而不是静态类,以便允许属性更改通知工作。绑定可在实例上使用INPC,但不能在静态类上使用。Common类看起来更像这样:

public class Common : INotifyPropertyChanged
{
    private static Common _instance = null;
    protected Common()
    {
    }
    public static Common GetInstance()
    {
        if (_instance == null)
            _instance = new Common();
        return _instance;
    }
    private string _title;
    public string Title
    {
        get { return _title; }
        set
        {
            if (_title == value)
                return;
            _title = value;
            OnPropertyChanged("Title");
        }
    }
    public void Load()
    {
    }
    public virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventArgs ea = new PropertyChangedEventArgs(propertyName);
        if (PropertyChanged != null)
            PropertyChanged(this, ea);
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

有很多不同的方法可以使用它。这里有一个更直接的:

public class SomeViewModel : ViewModelBase
{
    public Common CommonData { get; private set; }
    public SomeViewModel()
    {
        CommonData = Common.GetInstance();
    }
}

然后在XAML中,您可以绑定到公共类的属性并获得更改通知,即使是在不同的VM使用中也是如此。

<TextBox Text="{Binding Path=CommonData.Title}"/>

还有一种选择是将singleton作为属性进行访问,并使用x:Static从XAML直接绑定到它,但这与您所要求的方向有点不同。

因此,如果您有其他视图希望在属性更改时得到通知,我假设您为每个视图都有一个单独的视图模型。在这种情况下,你会问"视图模型如何与其他视图模型对话?"为了获得良好的学习体验,我建议研究观察者模式。如果你不喜欢这种风格,那么我建议你考虑使用MVVM框架,比如"SimpleMVVM、Catel或许多其他"(只需要查找一些)。然后,一旦你的项目中有了这个框架,我就会创建一个基本的视图模型类,所有的视图模型都将继承这个类。一旦完成,您就可以利用框架信使系统。基本上它看起来像:

    public YourViewModel()
    {           
        RegisterToReceiveMessages(MessageTokens.SomeToken, OnChangeCallYourMethodToAddress); //The MessageTokens is something you generally create ur self.
    }
    #region Notifications
    void OnChangeCallYourMethodToAddress(object sender, NotificationEventArgs<SlideShowLocale> e)
    {
        SomeProperty = e.Data;
    }

然后从另一个ViewModel向"YourViewModel"发送消息:

    public AnotherViewModel
    {
        SendMessage(MessageTokens.SomeToken, new NotificationEventArgs(WhateverYouWantToSend));
    }

因此,基本上,通过声明您想要的令牌,它会找到用该令牌注册的视图模型,并侦听任何传入的消息