用C#在mvvm设计模式下,用IHostedService设计登录程序,实现登录后窗口跳转,请给出一个完整实例及其完整代码
时间: 2024-05-13 13:18:13 浏览: 123
以下是一个基于MVVM设计模式和IHostedService的登录程序示例,其中使用了WPF作为UI框架,密码加密采用了SHA256算法:
MainWindow.xaml:
```xml
<Window x:Class="LoginApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LoginApp"
Title="Login" Height="250" Width="400">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Username:" />
<TextBox Grid.Row="0" Grid.Column="1" Margin="5" Text="{Binding Username}" />
<Label Grid.Row="1" Grid.Column="0" Content="Password:" />
<PasswordBox Grid.Row="1" Grid.Column="1" Margin="5" Password="{Binding Password}" />
<TextBlock Grid.Row="2" Grid.Column="1" Margin="5" Foreground="Red" Text="{Binding Error}" />
<Button Grid.Row="3" Grid.Column="1" Margin="5" Content="Login" Command="{Binding LoginCommand}" />
</Grid>
</Window>
```
MainWindowViewModel.cs:
```csharp
using System;
using System.ComponentModel;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace LoginApp
{
public class MainWindowViewModel : INotifyPropertyChanged
{
private string _username;
private string _password;
private string _error;
public string Username
{
get => _username;
set
{
_username = value;
OnPropertyChanged(nameof(Username));
}
}
public string Password
{
get => _password;
set
{
_password = value;
OnPropertyChanged(nameof(Password));
}
}
public string Error
{
get => _error;
set
{
_error = value;
OnPropertyChanged(nameof(Error));
}
}
public ICommand LoginCommand { get; }
public event PropertyChangedEventHandler PropertyChanged;
public MainWindowViewModel()
{
LoginCommand = new RelayCommand(async () => await LoginAsync());
}
private async Task LoginAsync()
{
Error = null;
// Validate input
if (string.IsNullOrWhiteSpace(Username) || string.IsNullOrWhiteSpace(Password))
{
Error = "Username and password are required.";
return;
}
// Hash password
var passwordHash = HashPassword(Password);
// Simulate login request
var token = await Task.Run(() =>
{
Thread.Sleep(2000); // Simulate network delay
if (Username == "admin" && passwordHash == "AC3C1E5F9A4C91E4DE7D6F5A3B85F0B2F1854D7B9D9AAB2B6DFAF6F9E2C3E8E4")
{
return Guid.NewGuid().ToString();
}
else
{
return null;
}
});
if (token != null)
{
// Login successful, navigate to main window
var mainWindow = new MainWindow();
mainWindow.DataContext = new MainViewModel(token);
mainWindow.Show();
Application.Current.MainWindow.Close();
}
else
{
// Login failed
Error = "Invalid username or password.";
}
}
private static string HashPassword(string password)
{
using var sha256 = SHA256.Create();
var bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
var sb = new StringBuilder();
foreach (var b in bytes)
{
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
```
MainViewModel.cs:
```csharp
using System.ComponentModel;
using System.Windows.Input;
namespace LoginApp
{
public class MainViewModel : INotifyPropertyChanged
{
private string _token;
public string Token
{
get => _token;
set
{
_token = value;
OnPropertyChanged(nameof(Token));
}
}
public ICommand LogoutCommand { get; }
public event PropertyChangedEventHandler PropertyChanged;
public MainViewModel(string token)
{
Token = token;
LogoutCommand = new RelayCommand(Logout);
}
private void Logout()
{
// Navigate back to login window
var loginWindow = new MainWindow();
loginWindow.Show();
Application.Current.MainWindow.Close();
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
```
RelayCommand.cs:
```csharp
using System;
using System.Windows.Input;
namespace LoginApp
{
public class RelayCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool> _canExecute;
public RelayCommand(Action execute, Func<bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute();
public void Execute(object parameter) => _execute();
public void RaiseCanExecuteChanged() => CommandManager.InvalidateRequerySuggested();
}
}
```
LoginHostedService.cs:
```csharp
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace LoginApp
{
public class LoginHostedService : IHostedService
{
private readonly Window _loginWindow;
public LoginHostedService(Window loginWindow)
{
_loginWindow = loginWindow;
}
public Task StartAsync(CancellationToken cancellationToken)
{
// Show login window
_loginWindow.Show();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
// Close login window
_loginWindow.Close();
return Task.CompletedTask;
}
}
}
```
App.xaml.cs:
```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Windows;
namespace LoginApp
{
public partial class App : Application
{
private IHost _host;
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
_host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.AddSingleton<Window>(new MainWindow());
services.AddSingleton<LoginHostedService>();
})
.Build();
await _host.StartAsync();
}
protected override async void OnExit(ExitEventArgs e)
{
base.OnExit(e);
await _host.StopAsync();
_host.Dispose();
}
}
}
```
在以上代码中,MainWindowViewModel类包含了登录窗口的数据和行为,其中LoginCommand命令用于处理登录操作。当用户点击登录按钮时,LoginAsync方法被执行,该方法首先验证输入是否合法,然后对密码进行哈希处理,并模拟发送登录请求。如果请求成功,程序会跳转到主窗口,否则会提示错误信息。
MainViewModel类则包含了主窗口的数据和行为,其中LogoutCommand命令用于处理注销操作。当用户点击注销按钮时,Logout方法被执行,该方法会关闭主窗口,并跳转回登录窗口。
RelayCommand类是一个通用的命令实现,用于将委托转换为ICommand接口。
LoginHostedService类继承自IHostedService接口,用于在应用程序启动时显示登录窗口,并在应用程序关闭时关闭登录窗口。
App类则用于配置和启动应用程序,其中使用了Microsoft.Extensions.Hosting和Microsoft.Extensions.DependencyInjection库来实现依赖注入和应用程序生命周期管理。
阅读全文