c# - 更新/使用来自另一个 ViewModel 的变量

标签 c# wpf mvvm

为了实践WPF+MVVM,我决定写一个学校程序。
到目前为止,我有类(class)和学生类(class)。
还有基本的 View 模型、ViewModelBase.cs,它派生自 INPC 和实例类 - “StudentClass”。

所有其他 View 模型都派生自 View 模型库。

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

为了保持井井有条,每个“功能”都有自己的 View 模型(StudentListViewModel.cs、AddStudentViewModel.cs...)。

我试图从 View 模型访问类,这只是导致类在一个窗口中更新而不是在另一个窗口中更新的情况。

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

我已经上传了项目以供引用:http://www.mediafire.com/?n70c7caqex6be1g

希望有人能帮助我。

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

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

更新:

StudentList.xaml 中的 XAML:(这是一个用户控件,因为我使用的是名为 ModernUI 的模板)

<UserControl x:Class="ClassStudent.StudentList"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" DataContext="{StaticResource StudentListViewModel}">
<Grid Style="{StaticResource ContentRoot}">
    <ListView ItemsSource="{Binding StudentClass.StudentList}" >
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="60"/>
                <GridViewColumn  Header="Age" DisplayMemberBinding="{Binding LastName}" Width="60"/>
            </GridView>
        </ListView.View>
    </ListView>
</Grid>

AddStudent.xaml 中的 XAML:

<UserControl x:Class="ClassStudent.AddStudent"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid Style="{StaticResource ContentRoot}"  DataContext="{StaticResource AddStudentViewModel}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Label Content="Name"/>
    <TextBox Text="{Binding Student.Name, Mode=TwoWay}" Grid.Column="1"/>
    <Label Content="Last Name" Grid.Row="1"/>
    <TextBox Text="{Binding Student.LastName, Mode=TwoWay}" Grid.Row="1" Grid.Column="1"/>

    <Button Command="{Binding AddStudent}" Content="Add Student!" Grid.Row="2" />
</Grid>

AddStudentViewModel.cs:

public class AddStudentViewModel : ViewModelBase
{
    private Student _student;
    private ICommand _addStudent;
    private ViewModelBase newIns;

    public ICommand AddStudent
    {
        get
        {
            if (_addStudent == null)
            {
                _addStudent = new RelayCommand(param => this.Add(), null);
            }

            return _addStudent;
        }
    }

    public Student Student
    {
        get
        {
            return _student;
        }
        set
        {
            _student = value;
            NotifyPropertyChanged("Student");
        }
    }

    private void Add()
    {
        StudentClass.StudentList.Add(Student);
        Student = new Student();
    }

    public AddStudentViewModel()
    {
        Student = new Student();
    }
}

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));
        }
    }
}

最佳答案

When I set the viewmodels of the "student list" window, and "add a student" window, the list are sync-ed, obviously. So I guess the thing is the class instance gets duplicated or something like that.

我想你想在两个 View 模型之间进行通知或通信。所以我知道有两种方法可以实现类似的机制,但这里不使用任何框架。

  1. 构建一个 Controller ,它将保留实例 View 模型列表,然后在 View 模型 A 引发事件然后将事件调用给 B 时定义规则。这将花费您很多精力。

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

    关注马丁·福勒:

    An Event Aggregator acts as a single source of events for many objects. It registers for all the events of the many objects allowing clients to register with just the aggregator.

    所以你可以看看EventAggregator来自 Martin Fowler,您可以自己实现一个 EventAggregator,或者您可以使用 Prism框架与 EventAggregator模式已经内置。你可以看看Caliburn micro framework以及。它简单,轻量级,具有 EventAggreagator 模式和 WPF 中的大量最佳实践,是最好的 WPF 框架之一,将帮助您在 WPF 中处理 MVVM 时节省大量精力。

关于c# - 更新/使用来自另一个 ViewModel 的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16498968/

相关文章:

c# - 由于文本框失去焦点,需要单击两次按钮

c# - 自动换行时的 OpenXML、PresentationML 表格高度和行高

c# - 对 System.data.entity.design.dll 的引用不起作用

C# WPF 无法获取 HTTPS 请求的互联网

.net - 自动卡住从模板构建的 wpf 对象

wpf - 如何在 XAML 声明的标签中的两个单词之间强制换行?

c# - mvvm light wpf取消注册

wpf - 使用 ICommand 的按钮不会被禁用?

c# - 静态事件处理程序和非静态事件处理程序有什么区别

c# - 不能使用 NullableContextAttribute stub 类