C# WPF MVVM-简单登录到应用程序
我将继续学习WPF,目前主要关注MVVM,并使用Karl Shifflett的“盒子中的MVVM”教程。但是,对于在视图/视图模型之间共享数据以及如何更新屏幕上的视图,我有一个疑问。p、 我还没有报道国际奥委会的情况 下面是测试应用程序中我的主窗口的屏幕截图。它分为3个部分(视图)、一个标题、一个带按钮的滑动面板,其余部分作为应用程序的主视图。应用程序的目的很简单,请登录到应用程序。成功登录后,登录视图应消失,由新视图(即概览屏幕视图)替换,应用程序幻灯片上的相关按钮应可见 我认为该应用程序有两个ViewModels。一个用于MainWindowView,一个用于LoginView,因为MainWindow不需要登录命令,所以我将其分开 由于我还没有介绍IOC,我创建了一个LoginModel类,它是一个单例。它只包含一个属性“public bool LoggedIn”,以及一个名为UserLoggedIn的事件 MainWindowViewModel构造函数注册到事件UserLoggedIn。现在在LoginView中,当用户在LoginView上单击Login时,它会在LoginView模型上引发一个命令,如果正确输入用户名和密码,该命令将调用LoginModel并将LoggedIn设置为true。这会触发UserLoggedIn事件,该事件在MainWindowViewModel中处理,以使视图隐藏LoginView,并将其替换为其他视图,即概览屏幕 问题 问题1。显而易见的问题是,这样登录是否正确使用了MVVM。i、 e.控制流程如下。LoginView-->LoginView视图模型-->LoginModel-->主窗口视图模型-->主窗口视图 问题2。假设用户已登录,并且MainWindowViewModel已处理该事件。您将如何创建一个新视图并将其放置在LoginView所在的位置,同样,如果不需要LoginView,您将如何处理它。MainWindowViewModel中是否有类似“UserControl currentControl”的属性,该属性设置为LoginView或OverviewScreenView 第三季度。主窗口是否应该在visual studio designer中设置LoginView。或者它应该是空白的,并且通过编程它意识到没有人登录,所以一旦主窗口被加载,它就会创建一个LoginView并在屏幕上显示它 下面的一些代码示例有助于回答问题 主窗口的XAMLC# WPF MVVM-简单登录到应用程序,c#,wpf,user-interface,mvvm,C#,Wpf,User Interface,Mvvm,我将继续学习WPF,目前主要关注MVVM,并使用Karl Shifflett的“盒子中的MVVM”教程。但是,对于在视图/视图模型之间共享数据以及如何更新屏幕上的视图,我有一个疑问。p、 我还没有报道国际奥委会的情况 下面是测试应用程序中我的主窗口的屏幕截图。它分为3个部分(视图)、一个标题、一个带按钮的滑动面板,其余部分作为应用程序的主视图。应用程序的目的很简单,请登录到应用程序。成功登录后,登录视图应消失,由新视图(即概览屏幕视图)替换,应用程序幻灯片上的相关按钮应可见 我认为该应用程序有
<Window x:Class="WpfApplication1.MainWindow"
xmlns:local="clr-namespace:WpfApplication1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="372" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<local:HeaderView Grid.ColumnSpan="2" />
<local:ButtonsView Grid.Row="1" Margin="6,6,3,6" />
<local:LoginView Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Window>
LoginView视图模型
using System;
using System.Windows.Controls;
using WpfApplication1.Infrastructure;
namespace WpfApplication1
{
public class MainWindowViewModel : ObservableObject
{
LoginModel _loginModel = LoginModel.GetInstance();
private UserControl _currentControl;
public MainWindowViewModel()
{
_loginModel.UserLoggedIn += _loginModel_UserLoggedIn;
_loginModel.UserLoggedOut += _loginModel_UserLoggedOut;
}
void _loginModel_UserLoggedOut(object sender, EventArgs e)
{
throw new NotImplementedException();
}
void _loginModel_UserLoggedIn(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Input;
using WpfApplication1.Infrastructure;
namespace WpfApplication1
{
public class LoginViewViewModel : ObservableObject
{
#region Properties
private string _username;
public string Username
{
get { return _username; }
set
{
_username = value;
RaisePropertyChanged("Username");
}
}
#endregion
#region Commands
public ICommand LoginCommand
{
get { return new RelayCommand<PasswordBox>(LoginExecute, pb => CanLoginExecute()); }
}
#endregion //Commands
#region Command Methods
Boolean CanLoginExecute()
{
return !string.IsNullOrEmpty(_username);
}
void LoginExecute(PasswordBox passwordBox)
{
string value = passwordBox.Password;
if (!CanLoginExecute()) return;
if (_username == "username" && value == "password")
{
LoginModel.GetInstance().LoggedIn = true;
}
}
#endregion
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows.Controls;
使用System.Windows.Input;
使用WpfApplication1.基础设施;
命名空间WpfApplication1
{
公共类loginView视图模型:observeObject
{
#区域属性
私有字符串\u用户名;
公共字符串用户名
{
获取{return\u username;}
设置
{
_用户名=值;
RaisePropertyChanged(“用户名”);
}
}
#端区
#区域命令
公共ICommand登录命令
{
获取{returnnewrelaycommand(LoginExecute,pb=>CanLoginExecute());}
}
#endregion//命令
#区域命令方法
布尔值CanLoginExecute()
{
return!string.IsNullOrEmpty(\u用户名);
}
void LoginExecute(PasswordBox PasswordBox)
{
字符串值=passwordBox.Password;
如果(!CanLoginExecute())返回;
如果(_username==“username”&&value==“password”)
{
LoginModel.GetInstance().LoggedIn=true;
}
}
#端区
}
}
神圣的问题,蝙蝠侠
Q1:
这个过程会起作用,但是我不知道如何使用LoginModel
与MainWindowViewModel
对话
您可以尝试类似于LoginView->LoginViewModel->[SecurityContextSingleton | | LoginManager Singleton]->MainWindowView
我知道有些人认为单身是反模式的,但我发现在这种情况下这是最容易的。通过这种方式,singleton类可以实现INotifyPropertyChanged
接口,并在检测到登出事件时引发事件
在LoginViewModel
或Singleton上实现LoginCommand
(我个人可能会在ViewModel
上实现这一点,以便在ViewModel和“后端”实用程序类之间增加一定程度的分离)。这个login命令将调用singleton上的一个方法来执行登录
Q2:
在这些情况下,我通常有(另一个)单例类充当PageManager
或ViewModelManager
。此类负责创建、处理和保存对顶级页面或当前页面的引用(仅在单个页面的情况下)
我的ViewModelBase
类还有一个属性来保存显示我的类的UserControl的当前实例,这样我就可以钩住加载和卸载的事件。这使我能够使用可以在ViewModel
中定义的虚拟onload()、OnDisplayed()和OnClosed()方法,以便页面可以执行加载和卸载操作
当主窗口视图显示ViewModelManager.CurrentPage
实例时,一旦该实例发生更改,就会触发卸载的事件,调用我的页面的Dispose方法,最后,GC
进入并整理其余部分
Q3:
我不确定我是否理解这一点,但希望你的意思是
public override object Convert(object value, SimpleConverterArguments args)
{
if (value == null)
return null;
ViewModelBase vm = value as ViewModelBase;
if (vm != null && vm.PageTemplate != null)
return vm.PageTemplate;
System.Windows.Controls.UserControl template = GetTemplateFromObject(value);
if (vm != null)
vm.PageTemplate = template;
if (template != null)
template.DataContext = value;
return template;
}
public static System.Windows.Controls.UserControl GetTemplateFromObject(object o)
{
System.Windows.Controls.UserControl template = null;
try
{
ViewModelBase vm = o as ViewModelBase;
if (vm != null && !vm.CanUserLoad())
return new View.Core.SystemPages.SecurityPrompt(o);
Type t = convertViewModelTypeToViewType(o.GetType());
if (t != null)
template = Activator.CreateInstance(t) as System.Windows.Controls.UserControl;
if (template == null)
{
if (o is SearchablePage)
template = new View.Core.Pages.Generated.ViewList();
else if (o is MaintenancePage)
template = new View.Core.Pages.Generated.MaintenancePage(((MaintenancePage)o).EditingObject);
}
if (template == null)
throw new InvalidOperationException(string.Format("Could not generate PageTemplate object for '{0}'", vm != null && !string.IsNullOrEmpty(vm.PageKey) ? vm.PageKey : o.GetType().FullName));
}
catch (Exception ex)
{
BugReporter.ReportBug(ex);
template = new View.Core.SystemPages.ErrorPage(ex);
}
return template;
}