为了练习WPF + MVVM,我决定写一个学校课程 到目前为止,我有班级和学生班 还有基本的视图模型,ViewModelBase.cs,它派生自INPC,实例类 - “StudentClass”。
所有其他视图模型都派生自viewmodelbase。
问题是,每个“功能”都有一个页面/窗口,(例如,查看所有学生,添加学生,删除学生等等),我希望能够访问该课程从应用程序的任何地方开始,因为所有信息基本上都存储在那里。
为了保持井井有条,每个“功能”都有自己的视图模型(StudentListViewModel.cs,AddStudentViewModel.cs ...)。
我试图从viewmodels访问该类,这只会导致类在一个窗口而不是在另一个窗口中更新的情况。
当我设置“学生列表”窗口的视图模型和“添加学生”窗口时,显然会同步列表。所以我想问题就是类实例得到重复或类似的东西。
我上传了该项目以供参考:http://www.mediafire.com/?n70c7caqex6be1g
希望有人可以帮助我。
我试着在google上寻找答案,但所有的答案都提到了与框架相关的“信使”和“事件”。由于我没有使用这个项目的框架,这些解决方案不适用于我。
另一个解决方案是将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));
}
}
}
答案 0 :(得分:4)
当我设置“学生列表”窗口的视图模型时,“添加一个 学生“窗口,列表是同步的,很明显。所以我想这件事 是类实例得到重复或类似的东西。
我想邀请您在两个视图模型之间通知或通信。所以我知道实现类似机制的两种方法,但不要在这里使用任何框架。
构建一个控制器,它将保留实例视图模型的列表,然后在视图模型A引发事件时定义规则,然后将事件调用到B.这需要您付出很多努力。
您可以查看“观察者模式”来构建发布/订阅事件。当A引发发布事件时,已经注册了订阅事件的视图模型B执行该函数。我建议你应该应用一个EventAggregator模式将获得更多通用,并可以使用无处不在。
关注Martin Fowler:
Event Aggregator充当许多事件的单一事件源 对象。它注册许多对象允许的所有事件 客户只需注册聚合器。
因此,您可以查看Martin Fowler的EventAggregator来实现您自己的EventAggregator,或者您可以使用已经内置Prism模式的EventAggregator框架。您也可以查看Caliburn micro framework。它简单,轻量级,具有EventAggreagator模式,WPF中的吨最佳实践是最好的WPF框架之一,可以帮助您在WPF中处理MVVM时节省大量精力。
答案 1 :(得分:1)
您可能需要建立某种事件机制。 不要打扰,这是标准的.NET技术。
首先: 有一个模型层。这是ViewModel适应视图的基础。 也许它只是某个数据库和视图模型之间的一个薄层。
有了这个,在你的模型中提供一个事件,告诉你的模型 不知何故改变了。
public event EventHandler<ValueChangedEventArgs> ValuesChanged;
public class ValueChangedEventArgs : System.EventArgs
{
public readonly string str;
public ValueChangedEventArgs(string str)
{
this.str = str;
}
}
在模型的某个地方,当值发生变化时,触发该事件:
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;
}
}
然后只需在ViewModel中订阅该事件:
public void ValuesChangedHandler(object sender, EventArgs e)
{
// do something with the new value
}
public StudentListViewModel()
{
yourModel.ValuesChanged += ValuesChangedHandler;
}