我最近开始在学校尝试MVVM模式,并且想知道最好的方法(如果有)是从ViewModel通知View,让视图知道在不破坏MVVM的情况下运行方法吗?基本上是让视图知道是否成功,例如尝试登录或尝试连接数据库?
例如登录页面,主窗口仅在成功登录后才将内容更改为新页面,否则,将显示一个消息框
编辑:
我正在使用.NET
到目前为止,我已经尝试过:
查看:
<Page
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"
xmlns:local="clr-namespace:View.Pages" xmlns:ViewModels="clr-namespace:ViewModel.ViewModels;assembly=ViewModel" x:Class="View.Pages.Start_Page"
mc:Ignorable="d"
d:DesignHeight="720" d:DesignWidth="1280"
Title="Start_Page">
<Page.DataContext>
<ViewModels:Start_Page_ViewModel/>
</Page.DataContext>
其背后的代码:
public Start_Page()
{
InitializeComponent();
Start_Page_ViewModel currentDataContext = DataContext as Start_Page_ViewModel;
currentDataContext.CurrentUserIDGotten += GoToMenu;
}
private void GoToMenu(int result)
{
if (result == -1)
{
MessageBox.Show("User credentials incorrect");
}
else if (result == -2)
{
MessageBox.Show("Connection failed");
}
else
{
Application.Current.MainWindow.Content = new Menu_Page();
}
}
ViewModel:
public class Start_Page_ViewModel
{
private string userName;
private string userPassword;
public string UserName { get => userName; set => userName = value; }
public string UserPassword { get => userPassword; set => userPassword = value; }
private RelayCommand logIn;
public RelayCommand LogIn => logIn;
public delegate void CurrentUserIDGottenEventHandler(int result);
public event CurrentUserIDGottenEventHandler CurrentUserIDGotten;
public Start_Page_ViewModel()
{
logIn = new RelayCommand(LogInToProgram, CanLogIn);
}
public void LogInToProgram(object o)
{
PasswordBox passwordBox = o as PasswordBox;
ViewModelController.Instance.CurrentUserID = Database_Controller.Instance.SignIn(userName, passwordBox.Password);
OnUserIDGotten(ViewModelController.Instance.CurrentUserID);
}
public bool CanLogIn(object o)
{
if (userName != null)
{
return true;
}
return false;
}
protected virtual void OnUserIDGotten(int result)
{
if (CurrentUserIDGotten != null)
{
CurrentUserIDGotten(result);
}
}
}
答案 0 :(得分:0)
通常,ViewModel通过数据绑定与View通信。 ViewModel可能会公开View绑定到的属性,例如LoginSuccessful
。然后,当属性更新时,视图将收到PropertyChanged通知并更改其外观的某些方面。这样做的方式各不相同;例如,XAML中的text属性可以直接绑定到基础ViewModel属性:
<TextBox Text="{Binding Source={StaticResource UserViewModel}, Path=Username}"/>
ViewModel可能类似于:
public class UserViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
public string Username {
get { return _username; }
set {
_username = value;
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Username"));
}
}
private string _username;
public UserViewModel() { }
}
只要在UserViewModel类上更改了Username属性,该文本框就会更新以显示新值。
但是,这种方法并不适用于所有情况。在使用布尔值时,实现数据触发器通常很有用:
<TextBox Text="{Binding Source={StaticResource UserViewModel}, Path=Username}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Source={StaticResource UserViewModel}, Path=IsTaken}" Value="True">
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBox>
如果在ViewModel上将IsTaken属性设置为true,则此代码扩展了前面的示例,以使文本框的背景变为红色。关于数据触发器的一件好事是它们会自行重置。例如,如果将该值设置为false,则背景将恢复为原始颜色。
如果要采用其他方法,并向ViewModel通知用户输入或类似重要的事件,则可以使用命令。命令可以绑定到XAML中的属性,并由ViewModel实现。当用户执行某些操作(例如单击按钮)时,将调用它们。可以通过实现ICommand接口来创建命令。
答案 1 :(得分:0)
以纯粹的方式,没有指定的框架。
喜欢这个
using System;
public class MainClass {
public static void Main (string[] args) {
ViewModel m = new ViewModel();
View v = new View();
v.Model = m;
m.MakeSomeChange();
}
}
public class View {
private IViewModel _model;
public IViewModel Model {
get {
return _model;
}
set {
if(_model != null) {
_model.OnChanged -= OnChanged;
}
if(value != null) {
value.OnChanged += OnChanged;
}
_model = value;
}
}
private void OnChanged(){
//update view
Console.WriteLine ("View Updated");
}
}
public delegate void ViewChangeDelegate();
public interface IViewModel {
event ViewChangeDelegate OnChanged;
}
public class ViewModel: IViewModel {
public event ViewChangeDelegate OnChanged;
public void MakeSomeChange() {
//make some change in the view Model
OnChanged.Invoke();
}
}