我正在使用MVVM模式开发一个WPF应用程序。但是,我遇到了一些问题,因为这是我第一次尝试使用MVVM模式。我有一个主登录视图,当我按下按钮时,没有任何React,我不知道为什么:
LoginView.xaml
<Window x:Class="Library.View.LoginView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Library.View"
xmlns:ViewModel="clr-namespace:Library.ViewModel" xmlns:customcontrol="clr-namespace:Library.CustomControl"
mc:Ignorable="d"
Title="LoginView" Height="550" Width="800"
WindowStyle="None"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="Transparent"
AllowsTransparency="True"
MouseDown="Window_MouseDown">
<Window.DataContext>
<ViewModel:LoginViewModel/>
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility"/>
</Window.Resources>
<Window.Visibility>
<Binding Path="IsViewVisible" Mode="TwoWay" Converter="{StaticResource BooleanToVisibility}"/>
</Window.Visibility>
<Border CornerRadius="12">
<Border.Background>
<ImageBrush ImageSource="/Image/back_image.jpg" />
</Border.Background>
<Border CornerRadius="12"
BorderThickness="2"
Opacity="0.86">
<Border.BorderBrush>
<LinearGradientBrush StartPoint="0, 0" EndPoint="1,1">
<GradientStop Color="#462AD8" Offset="0"/>
<GradientStop Color="#DA34AE" Offset="0.75"/>
<GradientStop Color="#8A16C1" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
<GradientStop Color="#060531" Offset="0"/>
<GradientStop Color="#1B1448" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="5"/>
</Grid.ColumnDefinitions>
<TextBlock Text="ZALOGUJ SIĘ"
Foreground="DarkGray"
FontSize="10"
FontFamily="Montserrat"
Grid.Column="0"
VerticalAlignment="Center"
Margin="10,0,0,0"/>
<Button x:Name="btnMinimalize"
BorderThickness="0"
Content="-"
Foreground="White"
FontSize="16"
FontFamily="Montserrat"
Cursor="Hand"
Grid.Column="1"
Click="btnMinimalize_Click">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="#28AEED"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#278BEF"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Width="18" Height="18"
CornerRadius="9"
Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<Button x:Name="btnClosed"
BorderThickness="0"
Content="X"
Foreground="White"
FontSize="12"
FontFamily="Montserrat"
Cursor="Hand"
Grid.Column="2"
Click="btnClosed_Click">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="#DA34AE"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#C62DAE"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Width="18" Height="18"
CornerRadius="9"
Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
<StackPanel Width="250"
Grid.Row="2"
Orientation="Vertical"
Margin="0,35,0,0">
<Image Source="/Image/Logo_image.jpg" Width="100" Height="100"/>
<TextBlock Text="Biblioteka Narodowa"
Foreground="White"
FontSize="25"
FontWeight="Medium"
FontFamily="Montserrat"
HorizontalAlignment="Center"/>
<TextBlock Text="Nazwa użytkownika"
Foreground="DarkGray"
FontSize="12"
FontWeight="Medium"
FontFamily="Montserrat"
Margin="0,35,0,0"/>
<TextBox x:Name="txtUser"
Text="{Binding Username,UpdateSourceTrigger=PropertyChanged}"
FontSize="13"
FontWeight="Medium"
FontFamily="Montserrat"
Foreground="White"
CaretBrush="LightGray"
BorderBrush="DarkGray"
BorderThickness="0,0,0,1"
Height="28"
VerticalContentAlignment="Center"
Margin="0,5,0,0"
Padding="25,0,0,0">
<TextBox.Background>
<ImageBrush ImageSource="/Image/user-solid.png" Stretch="Uniform" AlignmentX="Left">
</ImageBrush>
</TextBox.Background>
</TextBox>
<TextBlock Text="Hasło"
Foreground="DarkGray"
FontSize="12"
FontWeight="Medium"
FontFamily="Montserrat"
Margin="0,15,0,0"/>
<customcontrol:BindablePassword Password="{Binding Password,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
Height="28"
Margin="0,5,0,0">
</customcontrol:BindablePassword>
<TextBlock Text="{Binding ErrorMessage}"
Foreground="#D7596D"
FontSize="12"
FontWeight="Medium"
FontFamily="Montserrat"
Margin="0,15,0,0"
TextWrapping="Wrap"/>
<Button x:Name="btnLogin"
Command="{Binding LoginComand}"
BorderThickness="0"
Content="Zaloguj"
Foreground="White"
FontSize="12"
FontFamily="Montserrat"
Cursor="Hand"
Margin="0,30,0,0" >
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="#462AD8"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#28AEED"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Width="150" Height="40"
CornerRadius="9"
Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Margin="0,15,0,0">
<TextBlock Text="Zapomniałeś Hasła?"
Foreground="DarkGray"
FontSize="12"
FontWeight="Medium"
FontFamily="Montserrat"/>
<TextBlock Text="Reset"
Foreground="DarkGray"
FontSize="12"
FontWeight="Medium"
FontFamily="Montserrat"
Cursor="Hand"
Margin="8,0,0,0"/>
</StackPanel>
</StackPanel>
</Grid>
</Border>
</Border>
</Window>
loginViewModel.cs
using Library.Model;
using Library.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Library.ViewModel
{
public class LoginViewModel : ViewModelBase
{
//Feilds
private string _username;
private SecureString _password;
private string _errorMessage;
private bool _isViewVisible=true;
private IUserRepository userRepository;
public string Username
{
get
{
return _username;
}
set
{
_username = value;
OnPropertyChanged(nameof(Username));
}
}
public SecureString Password
{
get
{
return _password;
}
set
{
_password = value;
OnPropertyChanged(nameof(Password));
}
}
public string ErrorMessage {
get
{
return _errorMessage;
}
set
{
_errorMessage = value;
OnPropertyChanged(nameof(ErrorMessage));
}
}
public bool IsViewVisible
{
get
{
return _isViewVisible;
}
set
{
_isViewVisible = value;
OnPropertyChanged(nameof(IsViewVisible));
}
}
//->Commands
public ICommand LoginComand { get; }
public ICommand RecoverPasswordCommand { get; }
public ICommand ShowPasswordCommand { get; }
public ICommand RememberPasswordCommand { get; }
//Constructor
public LoginViewModel()
{
userRepository= new UserRepository();
LoginComand = new ViewModelCommand(ExecuteLoginCommand, CanExecuteLoginCommand);
RecoverPasswordCommand = new ViewModelCommand(p=>ExecuteRecoverPassCommand("",""));
}
private bool CanExecuteLoginCommand(object obj)
{
bool vaildDate;
if (string.IsNullOrWhiteSpace(Username) || Username.Length < 3 || Password == null ||
Password.Length < 3)
vaildDate = false;
else
vaildDate = true;
return vaildDate;
}
private void ExecuteLoginCommand(object obj)
{
var isValidUser = userRepository.AuthenticateUser(new NetworkCredential(Username, Password));
if (isValidUser)
{
Thread.CurrentPrincipal = new GenericPrincipal(
new GenericIdentity(Username), null);
isValidUser= false;
}
else
{
ErrorMessage = "* Błąd w nazwie użtkownika lub błędne hasło";
}
}
private void ExecuteRecoverPassCommand(string username,string email)
{
throw new NotImplementedException();
}
}
}
ViewModelbase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace Library.ViewModel
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ViewModelCommand.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Library.ViewModel
{
public class ViewModelCommand : ICommand
{
//Feilds
private readonly Action<object> _executeAction;
private readonly Predicate<object>? _canExecuteAction;
//Constructos
public ViewModelCommand(Action<object> executeAction)
{
_executeAction = executeAction;
_canExecuteAction = null;
}
public ViewModelCommand(Action<object> executeAction, Predicate<object> canExecuteAction)
{
_executeAction = executeAction;
_canExecuteAction = canExecuteAction;
}
//Events
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value;}
}
//Methods
public bool CanExecute(object parameter) => _canExecuteAction == null ? true : _canExecuteAction(parameter);
public void Execute(object parameter) => _executeAction(parameter);
}
}
我检查了代码,看看是否有什么遗漏,我已经调整了DataContext,因为当我检查它,一切都通过了,没有错误显示,即使连接到数据库一切正常。我在App.xaml中更改了我的第一个窗口的调用,它在子条件下工作。
App.xaml
<Application x:Class="Library.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Library"
Startup="ApplicationStart">
<Application.Resources>
</Application.Resources>
</Application>
App.xaml.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Library.View;
namespace Library
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected void ApplicationStart(object sender, StartupEventArgs e)
{
var loginView= new LoginView();
loginView.Show();
loginView.IsVisibleChanged += (s, ev) =>
{
if (loginView.IsVisible == false && loginView.IsLoaded)
{
var mainView = new MainWindow();
mainView.Show();
loginView.Close();
}
};
}
}
}
1条答案
按热度按时间imzjd6km1#
这里是一个最小的例子,演示了使用社区工具包mvvm修改命令和canexecutechanged。
我的主窗口:
视图模型
运行时,按钮最初禁用并变灰。
当我键入第四个字母时,按钮被启用:
属性基本上是不言自明的。但是...
有一个由代码生成器生成的分部类。
为私有变量创建公共属性。
notifycanexecutechanged属性将在键入每个字符时引发canexecutechanged,并将其传输到视图模型用户名。
relaycommand属性的canexecute部分设置了IsLoginExecutable布尔值,当然在键入每个字符时都会调用它。
https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/
https://blogs.msmvps.com/bsonnino/2022/08/06/the-mvvm-pattern-revisited-with-the-mvvm-community-toolkit-8-0/