努力学习 MVVM 基础知识

微风

我是 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 的教程,我已经阅读/查看了很多。但是,我已经到了越来越感到困惑的阶段,如果有人能给我详细说明我的代码并指出我哪里出错了,为什么代码不起作用以及我可以在哪里,我将不胜感激提升。

毫米8

你的问题很广泛。但是如果这个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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章