我是 MVVM 的新手(WPF 的一些经验),我对我认为的基础知识感到非常困惑。我正在尝试制作一个简单的注册表单。用户输入他们的姓名、用户名和密码。为了学习 MVVM 而不是让事情过于复杂,我对密码所做的唯一检查是它是否包含大写字母。暂时没有散列、加密等。
所以我有一个模型,它是User
从实体框架生成的。这是我的第一个困惑。它看起来像这样:
public partial class User : INotifyPropertyChanged
{
public short Id { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
if (_firstName == value)
{
return;
}
_firstName = value;
OnPropertyChanged("FirstName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
正如你所看到的,它有点不匹配。第一部分是由 Entity 生成的,我在 FirstName 方面对其进行了修改,使其看起来更像我认为的 MVVM。模型是我创建 get/set 的位置,它们是否也需要在 ViewModel 中?
转到我的 ViewModel,我很困惑我是否需要再次重新创建User
(FirstName, LastName ....)的属性,或者它们是否可以通过模型访问。我可以User
在 ViewModel 中创建一个公开 a 的所有属性的User
吗?这是我ViewModel
到目前为止的代码:
internal class NewUserViewModel : BaseViewModel
{
private User _newUser;
public User NewUser
{
get => _newUser;
set
{
if (_newUser == value)
{
return;
}
_newUser = value;
OnPropertyChanged("NewUser");
}
}
private string _password;
public string Password
{
get => _password;
set
{
if (_password == value)
return;
_password = value;
OnPasswordChanged();
OnPropertyChanged("Password");
}
}
#region RegisterCommand
private DelegateCommand _registerCommand;
public ICommand RegisterCommand
{
get
{
_registerCommand = new DelegateCommand(param => Register(), param => CanRegister());
return _registerCommand;
}
}
private bool CanRegister()
{
return _isPasswordValid;
}
private bool _isPasswordValid;
public void OnPasswordChanged()
{
_isPasswordValid = Password.Any(char.IsUpper);
}
private void Register()
{
using (var context = new WorkstreamContext())
{
var users = context.Set<User>();
users.Add(_newUser);
context.SaveChanges();
}
}
#endregion
}
到目前为止,我已经重新创建了该Password
属性,以便我可以访问它,但是这对我来说很不安,我觉得我要么公开所有属性,要么使用NewUser
,但是我不确定如何执行此操作。目前代码一半有效。该Save
按钮呈灰色,但是当密码包含我所期望的大写字母时,它不会启用。实际报名表:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Source="pack://application:,,,/Resources/NewUserForm/NewUser.jpg" HorizontalAlignment="Center" VerticalAlignment="Center" Height="100"/>
<TextBlock Grid.Row="1" Text="Please Enter Your Details" HorizontalAlignment="Center" Foreground="DarkSlateGray" FontSize="16"/>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Height="{Binding ActualHeight, ElementName=FirstNameTextBox}" Source="pack://application:,,,/Resources/NewUserForm/FirstName.jpg" Margin="5,5,0,5"/>
<xctk:WatermarkTextBox Grid.Column="1" x:Name="FirstNameTextBox" Watermark="first name" Text="{Binding NewUser.FirstName, Mode=TwoWay}" />
</Grid>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Height="{Binding ActualHeight, ElementName=LastNameTextBox}" Source="pack://application:,,,/Resources/NewUserForm/LastName.jpg" Margin="5,5,0,5"/>
<xctk:WatermarkTextBox Grid.Column="1" x:Name="LastNameTextBox" Watermark="last name" Text="{Binding NewUser.LastName, Mode=TwoWay}" />
</Grid>
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Height="{Binding ActualHeight, ElementName=UsernameTextBox}" Source="pack://application:,,,/Resources/NewUserForm/User.jpg" Margin="5,5,0,5"/>
<xctk:WatermarkTextBox Grid.Column="1" x:Name="UsernameTextBox" Watermark="username" Text="{Binding NewUser.Username, Mode=TwoWay}" />
</Grid>
<Grid Grid.Row="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Height="{Binding ActualHeight, ElementName=PasswordTextBox}" Source="pack://application:,,,/Resources/NewUserForm/Password.jpg" Margin="5,5,0,5"/>
<xctk:WatermarkTextBox Grid.Column="1" x:Name="PasswordTextBox" Watermark="password" Text="{Binding NewUser.Password, Mode=TwoWay}"/>
</Grid>
<DockPanel Grid.Row="6">
<Button Content="Save" Command="{Binding RegisterCommand, Mode=OneWay, Source={StaticResource NewUserViewModel}}" HorizontalAlignment="Right"/>
<Button HorizontalAlignment="Right"/>
</DockPanel>
</Grid>
我将 TextBoxes 绑定到 ViewModel 上公开的 NewUser 的方式是在 MVVM 中操作的正确方法吗?我很欣赏有很多关于 MVVM 的教程,我已经阅读/查看了很多。但是,我已经到了越来越感到困惑的阶段,如果有人能给我详细说明我的代码并指出我哪里出错了,为什么代码不起作用以及我可以在哪里,我将不胜感激提升。
你的问题很广泛。但是如果这个User
类实现了INotifyPropertyChanged
接口,它实际上是一种视图模型,你可以像你正在做的那样直接绑定到这个模型的属性:
{Binding NewUser.FirstName}
如果NewUser
是某种 DTO 对象,您可以将它包装在您的视图模型中并绑定到视图模型属性:
public string Password
{
get { return _user.Password; }
set { return _user.Password = value; OnNotifyPropertyChanged(); }
}
真正的“模型”更像是一种服务或某种业务逻辑对象。
Save 按钮呈灰色,但是当密码包含我所期望的大写字母时,它不会启用。
您的Password
财产的二传手甚至会受到打击吗?绑定到视图模型的Password
属性:
Text="{Binding Password}"
...并调用该RaiseCanExecuteChanged()
命令以刷新其状态:
private string _password;
public string Password
{
get => _password;
set
{
if (_password == value)
return;
_password = value;
OnPasswordChanged();
OnPropertyChanged("Password");
_registerCommand.RaiseCanExecuteChanged(); //<--
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句