获取工具下载 - DevExpress v21.2
从本文档中,您将了解如何向应用程序添加登录表单。在本节教程中着重讨论了如何实现此任务,这基本上是附加应用程序功能的一部分。
4. 您还需要向主表单的ViewModel中添加一些代码。由于主表单使用自动生成的MyDbContextViewModel 类,因此不建议将自定义代码直接添加到其中 - 如果您需要再次调用Scaffolding Wizard,可以重新生成模型。相反,创建一个位于单独文件中的部分类。 请注意,您必须将类构造函数从其原始文件移动到这个分部类。
C#
?
class="prettyprint lang-cs">//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 枚举器的值的原因。 可能存在三种应用状态:
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线上公开课、中文教程资讯请上中文网获取