Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF MVVM-简单登录到应用程序_C#_Wpf_User Interface_Mvvm - Fatal编程技术网

C# WPF MVVM-简单登录到应用程序

C# WPF MVVM-简单登录到应用程序,c#,wpf,user-interface,mvvm,C#,Wpf,User Interface,Mvvm,我将继续学习WPF,目前主要关注MVVM,并使用Karl Shifflett的“盒子中的MVVM”教程。但是,对于在视图/视图模型之间共享数据以及如何更新屏幕上的视图,我有一个疑问。p、 我还没有报道国际奥委会的情况 下面是测试应用程序中我的主窗口的屏幕截图。它分为3个部分(视图)、一个标题、一个带按钮的滑动面板,其余部分作为应用程序的主视图。应用程序的目的很简单,请登录到应用程序。成功登录后,登录视图应消失,由新视图(即概览屏幕视图)替换,应用程序幻灯片上的相关按钮应可见 我认为该应用程序有

我将继续学习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并在屏幕上显示它

下面的一些代码示例有助于回答问题

主窗口的XAML

<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;
}