C# 更新/使用另一个ViewModel中的变量

C# 更新/使用另一个ViewModel中的变量,c#,wpf,mvvm,C#,Wpf,Mvvm,为了练习WPF+MVVM,我决定写一个学校计划。 到目前为止,我有班级和学生班。 还有基本的视图模型ViewModelBase.cs,它源自INPC,还有实例类“StudentClass” 所有其他ViewModel均源自viewmodelbase 问题是我有一个页面/窗口用于每个“功能”(例如,查看所有学生、添加学生、删除学生等),我希望能够从应用程序中的任何位置访问该类,因为所有信息基本上都存储在那里 为了保持有序,每个“功能”都有自己的视图模型(StudentListViewModel.c

为了练习WPF+MVVM,我决定写一个学校计划。
到目前为止,我有班级和学生班。
还有基本的视图模型ViewModelBase.cs,它源自INPC,还有实例类“StudentClass”

所有其他ViewModel均源自viewmodelbase

问题是我有一个页面/窗口用于每个“功能”(例如,查看所有学生、添加学生、删除学生等),我希望能够从应用程序中的任何位置访问该类,因为所有信息基本上都存储在那里

为了保持有序,每个“功能”都有自己的视图模型(StudentListViewModel.cs、AddStudentViewModel.cs…)

我试图从viewmodels访问该类,这只会导致该类在一个窗口中更新,而不是在另一个窗口中更新

当我设置“学生列表”窗口和“添加学生”窗口的viewmodels时,列表显然是同步的。所以我猜问题是类实例被复制了或者类似的东西

我已上传该项目以供参考:

希望有人能帮助我

我试着在谷歌上寻找答案,但所有的答案都提到了与框架相关的“信使”和“事件”。由于我没有为这个项目使用框架,这些解决方案不适用于我

另一个解决方案是将viewmodel的一个实例传递给另一个实例,但我的viewmodels中没有一个调用或实例化另一个viewmodel

更新:

XAML:(这是一个usercontrol,因为我使用的是一个名为ModernUI的模板)

ViewModelBase.cs:

public class ViewModelBase : INotifyPropertyChanged
{
    private Class _studclass;

    public Class StudentClass
    {
        get { return _studclass; }
        set
        {
            _studclass = value;
            NotifyPropertyChanged("StudentClass");
        }
    }

    public ViewModelBase()
    {
        StudentClass = new Class();
        Student asaf = new Student();
        asaf.Name = "Asaf";
        asaf.LastName = "biton";
        StudentClass.StudentList.Add(asaf);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string PropertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
        }
    }
}
当我设置“学生列表”窗口的viewmodels和“添加 “学生”窗口,列表显然是同步的。我猜是这样的 是类实例被复制还是类似的

我建议您在两个视图模型之间进行通知或交流。所以我知道两种实现类似机制的方法,但这里不使用任何框架

  • 构建一个控制器,它将保留实例视图模型的列表,然后在视图模型a引发事件然后调用事件B时定义规则。这将花费您大量的精力

  • 您可以查看“观察者模式”来构建发布/订阅事件。当A引发发布事件时,视图模型B已注册订阅事件以执行该功能。我建议您应用EventAggregator模式,它将变得更加通用,并且可以使用无处不在的

    跟随马丁·福勒:

    事件聚合器充当许多事件的单一事件源 物体。它注册许多对象的所有事件 仅向聚合器注册的客户端

    所以,您可以从Martin Fowler那里了解自己实现EventAggregator的方法,或者使用内置了模式的框架。你也可以看看这个。它简单、轻量级,具有EventAggreagator模式,WPF中的最佳实践是最佳WPF框架之一,它将帮助您在WPF中处理MVVM时节省大量精力


  • 你可能需要建立某种事件机制。 不用麻烦了,这是标准的.NET技术

    首先: 有一个模型层。这是ViewModels适应视图的基础。 也许它只是一些数据库和viewmodels之间的一个薄层

    这样,在模型中提供一个事件,告诉您的模型 不知怎么变了

    public event EventHandler<ValueChangedEventArgs> ValuesChanged;
    
    public class ValueChangedEventArgs : System.EventArgs
    {
        public readonly string str;
    
        public ValueChangedEventArgs(string str)
        {
            this.str = str;
        }
    }
    
    也许在模型中的一个值设置器中

    public string StringValue
    {
        get
        {
            return stringValue;
        }
        set
        {
            OnPriceChanged(new ValueChangedEventArgs(value));
            stringValue = value;
        }
    }
    
    然后只需在ViewModel中订阅该事件:

    protected virtual void OnPriceChanged(ValueChangedEventArgs e)
    {
        if (ValuesChanged != null)
            ValuesChanged(this, e);
    }
    
    public void ValuesChangedHandler(object sender, EventArgs e)
    {
        // do something with the new value
    }
    
    public StudentListViewModel()
    {
           yourModel.ValuesChanged += ValuesChangedHandler;
    }
    

    发布一些相关的XAML和代码。我们不会下载你的项目只是为了回答这个问题。完成。我觉得太长了,所以我上传了整个项目。但如果你这么说的话,那样更好,那就好了。很抱歉没有事先做这件事。我想这是观察家模式事件聚合器是单向的。一旦你开始使用它,你就再也不会使用其他任何东西了;)我喜欢caliburn.micro附带的那款!你说得对。我喜欢Caliburn micro和Caliburn。它们是非常好的框架。顺便说一句,谢谢你的评论。谢谢。我听说过Caliburn,但我希望在使用框架之前,至少自己能够做到这一点。我无法从你发布的链接中了解太多,但我会尝试在google上查找。@xTCx在获得帮助之前,最好先尝试理解这个概念。如果您想了解caliburn.micro的更多信息,请看一看它是否可行。但是我的情况有点不同。在我的“类”模型中,我只有一个可观察的学生集合和一个构造函数。我所做的只是添加到集合中,而不是设置它。那么我该怎么做呢?模型视图模型模式需要一个模型。显示的数据来自该模型,在viewmodel中进行调整,并显示在视图中。通过事件连接模型和视图模型。然后通过绑定连接ViewModel和View。ObservableCollection绝对是ViewModel的一部分。在你的模型中,你有一个数据库连接,一个列表或者类似的东西。班级,学生。班级是学生名单,学生基本上是姓名、姓氏等。。。
    protected virtual void OnPriceChanged(ValueChangedEventArgs e)
    {
        if (ValuesChanged != null)
            ValuesChanged(this, e);
    }
    
    public string StringValue
    {
        get
        {
            return stringValue;
        }
        set
        {
            OnPriceChanged(new ValueChangedEventArgs(value));
            stringValue = value;
        }
    }
    
    public void ValuesChangedHandler(object sender, EventArgs e)
    {
        // do something with the new value
    }
    
    public StudentListViewModel()
    {
           yourModel.ValuesChanged += ValuesChangedHandler;
    }