更新/使用可变从另一个视图模型 [英] Updating/using a variable from another ViewModel

查看:108
本文介绍了更新/使用可变从另一个视图模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了练习WPF + MVVM,我决定写一个学校课程。

到目前为止,我有类和学生类。

还有基本的视图模型,ViewModelBase.cs,来源于INPC和实例类 - StudentClass。



所有其他视图模型派生自viewmodelbase。



事情是我有一个页面/窗口为每个功能,(例如,查看所有的学生,添加学生,删除学生等...),我想要能



为了保持组织,每个feature都有自己的viewmodel(StudentListViewModel .cs,AddStudentViewModel.cs ...)。



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



当我设置学生列表窗口和添加学生窗口的视图模型时,显然列表是同步的。所以我想事情是类实例得到重复或类似的东西。



我上传的项目作为参考: http://www.mediafire.com/?n70c7caqex6be1g



希望有人能帮助我。



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



另一个解决方案是将viewmodel的实例传递给另一个,



更新:



XAML在StudentList.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 =300d:DesignWidth =300DataContext ={StaticResource StudentListViewModel}>
< Grid Style ={StaticResource ContentRoot}>
< ListView ItemsSource ={Binding StudentClass.StudentList}>
< ListView.View>
< GridView>
< GridViewColumn Header =NameDisplayMemberBinding ={Binding Name}Width =60/>
< GridViewColumn Header =AgeDisplayMemberBinding ={Binding LastName}Width =60/>
< / GridView>
< /ListView.View>
< / ListView>
< / Grid>



XAML在AddStudent.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 =300d: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 NameGrid.Row =1/>
< TextBox Text ={Binding Student.LastName,Mode = TwoWay}Grid.Row =1Grid.Column =1/>

< Button Command ={Binding AddStudent}Content =添加学生! 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学生学生
{
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));
}
}
}


解决方案>


当我设置学生列表窗口的视图模型和添加
学生窗口时,显然列表是同步的。所以我猜这个事情
是类实例被重复或类似的东西。


在两个视图模型之间通信。所以我知道两种方法来实现类似的机制,但不使用任何框架在这里。


  1. 构建一个控制器保存实例视图模型列表,然后在视图模型A引发事件,然后将事件调用B时定义规则。这将花费你的努力。


  2. 看看观察者模式来构建发布/订阅事件。当A引发发布事件时,视图模型B已经注册了订阅事件以执行该函数。我建议你应用一个EventAggregator模式将获得更多的通用和可以使用无处不在。



    关注Martin Fowler:


    An Event Aggregator许多
    对象的事件。它注册许多对象的所有事件,允许
    客户端仅向聚合器注册。


    请查看Martin Fowler的 EventAggregator ,以便您自己实现EventAggregator,也可以使用 Prism 框架 EventAggregator 模式已内置。您还可以查看 Caliburn微框架。它是简单,轻量级的EventAggreagator模式和一个吨最佳实践在WPF是最好的WPF框架之一将帮助你在处理MVVM在WPF中节省了很多努力。



In order to practice WPF+MVVM, I've decided to write a school program.
So far I have the class and student classes.
There is also the basic view model, ViewModelBase.cs, which derives from INPC, and instances class - "StudentClass".

All other viewmodels derive from viewmodelbase.

The thing is I have a page/window for each "feature", (for example; viewing all of the students, adding a student, deleting a student etc...) and I want to be able to access that class from anywhere in the application since all of the info is stored there basically.

In order to stay organized, each "feature" has its own viewmodel (StudentListViewModel.cs, AddStudentViewModel.cs...).

I tried to access the class from the viewmodels, which just caused a case where the class updates in one window and not in the other.

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.

I've uploaded the project for reference: http://www.mediafire.com/?n70c7caqex6be1g

Hopefully someone can help me.

I tried looking on google for answers, but all of the answers mentions "Messengers" and "events" which are related to frameworks. And since I didn't use a framework for this project, those solutions doesn't apply for me.

Another solution was to pass an instance of the viewmodel to another, but none of my viewmodels call or instantiate another viewmodel.

Update:

XAML in StudentList.xaml: (This is a usercontrol because I'm using a template called 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>

XAML in AddStudent.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.

I guest you want to inform or communicate between two view models. So I know two ways to implement a similar mechanism but don't use any framework at here.

  1. Build a controller which will keep list of instance view models and then define rule when view model A raise event then call event to B. It will take your efforts a lot.

  2. You can look at "observer pattern" to build a publish/ subscribe event. When A raise a publish event the view model B which already register subscribe event to execute the function. I suggest you should apply an EventAggregator pattern will get more generic and can use ubiquitous.

    Follow Martin Fowler:

    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.

    So you can take look at EventAggregator from Martin Fowler to implement an EventAggregator by your self or you can use Prism framework with EventAggregator pattern already built-in. You can look at The Caliburn micro framework as well. It is simple, lightweight which have EventAggreagator pattern and a tons best practices in WPF is one of a best of WPF framework will help you save a lot of efforts when deal with MVVM in WPF.

这篇关于更新/使用可变从另一个视图模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆