DevExpress控件使用交流,DevExpress中国社区Dev联系电话 联系电话:023-68661681

界面控件DevExpress WinForms MVVM使用教程(五):登录表单(下)

来源:   发布时间:2022-04-25   浏览:1110次

获取工具下载 - DevExpress v21.2

从本文档中,您将了解如何向应用程序添加登录表单。在本节教程中着重讨论了如何实现此任务,这基本上是附加应用程序功能的一部分。

4. 您还需要向主表单的ViewModel中添加一些代码。由于主表单使用自动生成的MyDbContextViewModel 类,因此不建议将自定义代码直接添加到其中 - 如果您需要再次调用Scaffolding Wizard,可以重新生成模型。相反,创建一个位于单独文件中的部分类。 请注意,您必须将类构造函数从其原始文件移动到这个分部类。

C#

//MyDbContextViewModel.partial.cs
public partial class MyDbContextViewModel {
LoginViewModel loginViewModel;

protected MyDbContextViewModel()
: base(UnitOfWorkSource.GetUnitOfWorkFactory()) {
loginViewModel = LoginViewModel.Create();
loginViewModel.SetParentViewModel(this);
}
protected IDialogService DialogService {
get { return this.GetService<IDialogService>(); }
}
protected IMessageBoxService MessageService {
get { return this.GetService<IMessageBoxService>(); }
}

public override void OnLoaded(MyDbContextModuleDescription module) {
base.OnLoaded(module);
Login();
}

public virtual AppState State { get; set; }
// Shows the Login View
public void Login() {
OnLogin(DialogService.ShowDialog(MessageButton.OKCancel, "Please enter you credentials", "LoginView", loginViewModel));
}
//Occurs whenever the end-user clicks a dialog button
void OnLogin(MessageResult result) {
if(result == MessageResult.Cancel)
State = AppState.ExitQueued;
else {
if(loginViewModel.IsCurrentUserCredentialsValid)
State = AppState.Autorized;
else
Login();
}
}
protected void OnStateChanged() {
this.RaiseCanExecuteChanged(x => x.Logout());
if(State == AppState.Autorized)
Messenger.Default.Send<string>(loginViewModel.CurrentUser.Login);
else
Messenger.Default.Send<string>(string.Empty);
}
}

public enum AppState {
NotAutorized,
Autorized,
ExitQueued
}

VB.NET

'MyDbContextViewModel.partial.vb
Partial Public Class MyDbContextViewModel
Private loginViewModel As LoginViewModel

Protected Sub New()
MyBase.New(UnitOfWorkSource.GetUnitOfWorkFactory())
loginViewModel = LoginViewModel.Create()
loginViewModel.SetParentViewModel(Me)
End Sub
Protected ReadOnly Property DialogService() As IDialogService
Get
Return Me.GetService(Of IDialogService)()
End Get
End Property
Protected ReadOnly Property MessageService() As IMessageBoxService
Get
Return Me.GetService(Of IMessageBoxService)()
End Get
End Property

Public Overrides Sub OnLoaded(ByVal [module] As MyDbContextModuleDescription)
MyBase.OnLoaded([module])
Login()
End Sub

Public Overridable Property State() As AppState
' Shows the Login View
Public Sub Login()
OnLogin(DialogService.ShowDialog(MessageButton.OKCancel, "Please enter you credentials", "LoginView", loginViewModel))
End Sub
'Occurs whenever the end-user clicks a dialog button
Private Sub OnLogin(ByVal result As MessageResult)
If result Is MessageResult.Cancel Then
State = AppState.ExitQueued
Else
If loginViewModel.IsCurrentUserCredentialsValid Then
State = AppState.Autorized
Else
Login()
End If
End If
End Sub
Protected Sub OnStateChanged()
Me.RaiseCanExecuteChanged(Sub(x) x.Logout())
If State = AppState.Autorized Then
Messenger.Default.Send(Of String)(loginViewModel.CurrentUser.Login)
Else
Messenger.Default.Send(Of String)(String.Empty)
End If
End Sub
End Class

Public Enum AppState
NotAutorized
Autorized
ExitQueued
End Enum

下面列出了 LoginViewModel 和两个视图(MainView 和 LoginView)的代码。 当您的 ViewModel 准备就绪时,重新构建项目并将 MvvmContext 组件添加到登录表单中,使用其智能标签将 LoginViewModel 分配为此视图的相关视图模型。

C#

//LoginViewModel.cs
public class LoginViewModel {
public IEnumerable<string> LookUpUsers {
get { return CredentialsSource.GetUserNames(); }
}
public virtual User CurrentUser { get; set; }
public bool IsCurrentUserCredentialsValid { get; private set; }

[DevExpress.Mvvm.DataAnnotations.Command(false)]
public void Init() {
this.CurrentUser = new User();
}
public void Update() {
IsCurrentUserCredentialsValid = CredentialsSource.Check(CurrentUser.Login, CurrentUser.Password);
}
public static LoginViewModel Create() {
return ViewModelSource.Create<LoginViewModel>();
}
}

//MainView.cs
public MainView() {
InitializeComponent();
this.Opacity = 0;
. . .
}

void InitializeNavigation() {
. . .
var fluentAPI = mvvmContext1.OfType<MyDbContextViewModel>();
fluentAPI.SetTrigger(x => x.State, (state) =>
{
if(state == AppState.Autorized)
Opacity = 1; /*Show Main Form*/
if(state == AppState.ExitQueued)
Close(); // exit the app;
});
}

//LoginView.cs
public partial class LoginView : DevExpress.XtraEditors.XtraUserControl {
public LoginView() {
InitializeComponent();
}

protected override void OnLoad(System.EventArgs e) {
base.OnLoad(e);
var fluentAPI = mvvmContext1.OfType<LoginViewModel>();
fluentAPI.SetObjectDataSourceBinding(userBindingSource,
x => x.CurrentUser, x => x.Update());

foreach(string item in mvvmContext1.GetViewModel<LoginViewModel>().LookUpUsers)
LoginTextEdit.Properties.Items.Add(item);
fluentAPI.ViewModel.Init();
}
}

VB.NET

'LoginViewModel.vb
Public Class LoginViewModel
Public ReadOnly Property LookUpUsers() As IEnumerable(Of String)
Get
Return CredentialsSource.GetUserNames()
End Get
End Property
Public Overridable Property CurrentUser() As User
Private privateIsCurrentUserCredentialsValid As Boolean
Public Property IsCurrentUserCredentialsValid() As Boolean
Get
Return privateIsCurrentUserCredentialsValid
End Get
Private Set(ByVal value As Boolean)
privateIsCurrentUserCredentialsValid = value
End Set
End Property

<DevExpress.Mvvm.DataAnnotations.Command(False)>
Public Sub Init()
Me.CurrentUser = New User()
End Sub
Public Sub Update()
IsCurrentUserCredentialsValid = CredentialsSource.Check(CurrentUser.Login, CurrentUser.Password)
End Sub
Public Shared Function Create() As LoginViewModel
Return ViewModelSource.Create(Of LoginViewModel)()
End Function
End Class

'MainView.vb
Public Sub New()
InitializeComponent()
Me.Opacity = 0
. . .
End Sub

Private Sub InitializeNavigation()
. . .
Dim fluentAPI = mvvmContext1.OfType(Of MyDbContextViewModel)()
fluentAPI.SetTrigger(Function(x) x.State, Sub(state)
If state = AppState.Autorized Then
Opacity = 1
End If
If state = AppState.ExitQueued Then
Close()
End If
End Sub) ' exit the app; - Show Main Form
End Sub

'LoginView.vb
Partial Public Class LoginView
Inherits DevExpress.XtraEditors.XtraUserControl

Public Sub New()
InitializeComponent()
End Sub

Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
MyBase.OnLoad(e)
Dim fluentAPI = mvvmContext1.OfType(Of LoginViewModel)()
fluentAPI.SetObjectDataSourceBinding(userBindingSource, Function(x) x.CurrentUser, Function(x) x.Update())

For Each item As String In mvvmContext1.GetViewModel(Of LoginViewModel)().LookUpUsers
LoginTextEdit.Properties.Items.Add(item)
Next item
fluentAPI.ViewModel.Init()
End Sub
End Class

此代码使用 OnLoaded 方法重载来显示使用已注册 DialogService 的对话框,为此Login方法调用服务的ShowDialog扩展方法,此方法将子 ViewModel 作为参数 - 将 LoginViewModel 类的新实例传递给它。创建这个实例很重要,不是使用 new 关键字,而是调用 ViewModelSource.Create<ViewModelType> 方法。或者,您可以调用 SetParentViewModel 方法为此实例设置父 ViewModel。

当最终用户单击任何登录对话框的按钮时,此消息结果将传递给 OnLogin 方法,该方法会准确检查单击了哪个按钮。 如果最终用户单击 ‘Cancel’ 或关闭对话框,则应用程序将关闭。如果单击‘OK’按钮,应用程序将检查 IsCurrentUserCredentialsValid 属性,该属性会在调用 Update 方法时自动刷新其值。如果输入的凭据有效,将显示主表单,否则将重新显示登录表单,这是通过为 State 属性分配不同的值来完成的。 MainView 有一个触发器,用于监视 State 属性值的变化,并在它发生时做出相应的反应。

5. 前面的步骤足以实现具有最少功能的登录表单。 但是,如果您的主视图分配了关闭确认操作,可能会遇到某些问题。 例如,如果您关闭登录表单,主表单(由于未输入有效凭据而变得透明)也将尝试自行关闭。 这将显示确认消息,如果您单击‘Cancel’按钮,表格将保留,但您将看不到它。 要克服此类问题,请删除表单关闭操作(如果有)并添加以下代码。

C#

//MainView.cs
fluentAPI.WithEvent<FormClosingEventArgs>(this, "FormClosing")
.EventToCommand(x => x.OnClosing(null), new Func<CancelEventArgs, object>((args) => args));

//MyDbContextViewModel.partial.cs
public override void OnClosing(CancelEventArgs cancelEventArgs) {
base.OnClosing(cancelEventArgs);
if(!cancelEventArgs.Cancel) {
if(State == AppState.Autorized && MessageService.ShowMessage("Do you really want to close the application?", "Confirm", MessageButton.YesNo) == MessageResult.No)
cancelEventArgs.Cancel = true;
}
}

VB.NET

'MainView.vb
fluentAPI.WithEvent(Of FormClosingEventArgs)(Me, "FormClosing").EventToCommand(Function(x) x.OnClosing(Nothing), New Func(Of CancelEventArgs, Object)(Function(args) args))

'MyDbContextViewModel.partial.vb
public override void OnClosing(CancelEventArgs cancelEventArgs)
MyBase.OnClosing(cancelEventArgs)
If Not cancelEventArgs.Cancel Then
If State = AppState.Autorized AndAlso MessageService.ShowMessage("Do you really want to close the application?", "Confirm", MessageButton.YesNo) = MessageResult.No Then
cancelEventArgs.Cancel = True
End If
End If

此代码检查当前的 State 属性值,仅在授权通过时显示确认消息。 如果最终用户尚未登录并决定关闭应用程序,则不会显示任何确认信息。 这就是为什么 State 属性不是布尔值,而是接受自定义 AppState 枚举器的值的原因。 可能存在三种应用状态:

  • Authorized(已授权) - 用户凭据有效。 主表单是可见的,尝试关闭它应该会显示确认消息,最终用户可以单击 ‘No’ 来保持应用程序运行。
  • NotAuthorized - 输入了用户凭据,但未通过验证。 主应用程序表单保持透明,登录表单重新显示。
  • ExitQueued - 未输入用户凭据,登录表单已关闭,应用程序应在没有任何确认对话框的情况下终止。

6. 您的登录表单现已准备就绪。可以通过为密码编辑器设置特定的 RepositoryItemTextEdit.PasswordChar 来装饰它,在主表单上反映登录用户的名称,并将按钮添加到主视图的网格控件中,以便您重新登录等,下面的代码说明了 怎么做。

C#

//LoginView.cs
PasswordTextEdit.Properties.PasswordChar = '*';

//MyDbContextViewModel.partial.cs
protected void OnStateChanged() {
this.RaiseCanExecuteChanged(x => x.Logout());
if(State == AppState.Authorized)
Messenger.Default.Send<string>(loginViewModel.CurrentUser.Login);
else
Messenger.Default.Send<string>(string.Empty);
}

public void Logout() {
State = AppState.ExitQueued;
System.Diagnostics.Process.Start(System.Windows.Forms.Application.ExecutablePath);
}

public bool CanLogout() {
return State == AppState.Authorized;
}
//MainView.cs
Messenger.Default.Register<string>(this, OnUserNameMessage);
fluentAPI.BindCommand(biLogout, x => x.Logout());

void OnUserNameMessage(string userName) {
if(string.IsNullOrEmpty(userName))
this.Text = "Expenses Application";
else
this.Text = "Expenses Application - (" + userName + ")";
}

VB.NET

'LoginView.vb
PasswordTextEdit.Properties.PasswordChar = "*"c

'MyDbContextViewModel.partial.vb
protected void OnStateChanged()
Me.RaiseCanExecuteChanged(Sub(x) x.Logout())
If State = AppState.Authorized Then
Messenger.Default.Send(Of String)(loginViewModel.CurrentUser.Login)
Else
Messenger.Default.Send(Of String)(String.Empty)
End If

public void Logout()
State = AppState.ExitQueued
System.Diagnostics.Process.Start(System.Windows.Forms.Application.ExecutablePath)

public Boolean CanLogout()
Return State = AppState.Authorized
'MainView.vb
Messenger.Default.Register(Of String)(Me, AddressOf OnUserNameMessage)
fluentAPI.BindCommand(biLogout, Function(x) x.Logout())

void OnUserNameMessage(String userName)
If String.IsNullOrEmpty(userName) Then
Me.Text = "Expenses Application"
Else
Me.Text = "Expenses Application - (" & userName & ")"
End If

DevExpress WinForm | 下载试用

DevExpress WinForm拥有180+组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任!

更多产品正版授权详情及优惠,欢迎咨询在线客服>>


DevExpress技术交流群6:600715373      欢迎一起进群讨论

更多DevExpress线上公开课、中文教程资讯请上中文网获取

DevExpress企业定制服务
本站文章除注明转载外,均为本站原创或翻译
欢迎任何形式的转载,但请务必注明出处,尊重他人劳动成果
转载请注明:文章转载自:DevExpress控件中文网 [https://www.devexpresscn.com/]
本文地址:https://www.devexpresscn.com/post/3024.html

相关产品: DevExpress Universal Subscription,

在线
客服
微信
QQ 电话
023-68661681
返回
顶部