MVVM模式查询

时间:2014-02-07 11:01:46

标签: c# wpf xaml mvvm

我正在学习使用MVVM设计模式的WPF,并试图了解如何在代码之外完成一些事情。 我有一个登录页面,如下图所示。 enter image description here

我从http://www.wpftutorial.net/PasswordBox.html获得了密码控制。

我现在想要简单理解的情况,比如问我的代码是否在正确的类中/正确设置以遵守MVVVM规则并分离关注点。

我目前有一个if语句来检查详细信息是否与名称字符串和密码字符串匹配。 代码在后面的代码中。我只是想知道这对于MVVM是否正确。我想知道你如何在ViewModel中实现它?

 private void OK_Click(object sender, RoutedEventArgs e)
 {
     if (emp.Name == "ep" && emp.Password == "pass")
     {
         MessageBox.Show("namd and Pw accepted");
         //open new page
         var HomeScreen = new HomeScreen();
         HomeScreen.Show();
     }
     else
     {
         //deny access
         MessageBox.Show("Incorrect username and password");
     }
 }

2 个答案:

答案 0 :(得分:2)

不是在后面的代码中实现按钮单击处理程序,而是使用ICommand并将其绑定到XAML中的按钮事件。

这是一个非常好的教程,让我从MVVM入手: WPF Apps With The Model-View-ViewModel Design Pattern

[已编辑添加示例代码]

下面是一个简单的代码示例来完成您的示例所做的事情,但是使用MVVM样式并且没有任何代码隐藏代码

1)创建一个新的WPF解决方案,对于这个小例子我简单地命名为“WpfApplication”。

2)编辑自动创建的MainWindow.xaml

的代码
<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModel="clr-namespace:WpfApplication"
        Title="MainWindow" Height="234" Width="282">

  <!-- Create the ViewModel as the initial DataContext -->
  <Window.DataContext>
    <viewModel:MainWindowViewModel />
  </Window.DataContext>

  <Grid>
    <TextBox Height="23"
             HorizontalAlignment="Left"
             Margin="70,31,0,0"
             Name="textBox1"
             VerticalAlignment="Top"
             Width="120"
             Text="{Binding Path=Name}"/>
    <TextBox Height="23"
             HorizontalAlignment="Left"
             Margin="70,72,0,0"
             Name="textBox2"
             VerticalAlignment="Top"
             Width="120"
             Text="{Binding Path=Password}" />
    <Label Content="Name"
           Height="28"
           HorizontalAlignment="Left"
           Margin="22,29,0,0"
           Name="label1"
           VerticalAlignment="Top" />
    <Label Content="PW"
           Height="28"
           HorizontalAlignment="Left"
           Margin="22,70,0,0"
           Name="label2"
           VerticalAlignment="Top" />
    <Button Content="OK"
            Height="23"
            HorizontalAlignment="Left"
            Margin="70,119,0,0"
            Name="button1"
            VerticalAlignment="Top"
            Width="120" 
            Command="{Binding Path=LoginCommand}"
            CommandParameter="{Binding Path=.}"
            />
  </Grid>
</Window>

(忽略宽度,高度,边距值,这些只是从我的设计师那里复制和粘贴,并且快速和肮脏调整到大致看起来像你的截图;-))

3)创建将处理逻辑登录的Command类。请注意,我没有像Josh Smith的教程那样将它实现为RelayCommand,但是相应地修改代码会很容易:

      namespace WpfApplication
      {
        using System;
        using System.Windows;
        using System.Windows.Input;

        /// <summary>
        /// Checks the user credentials.
        /// </summary>
        public class LoginCommand : ICommand
        {

           /// <summary>
           /// Defines the method to be called when the command is invoked.
           /// </summary>
           /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
           public void Execute(object parameter)
           {
              MainWindowViewModel viewModel = parameter as MainWindowViewModel;

              if (viewModel == null)
              {
                 return;
              }

              if (viewModel.Name == "ep" && viewModel.Password == "pass")
              {
                 MessageBox.Show("namd and Pw accepted");

                 //open new page
                 var HomeScreen = new HomeScreen();
                 HomeScreen.Show();
              }
              else
              {
                 //deny access
                 MessageBox.Show("Incorrect username and password");
              }
           }

           /// <summary>
           /// Defines the method that determines whether the command can execute in its current state.
           /// </summary>
           /// <returns>
           /// true if this command can be executed; otherwise, false.
           /// </returns>
           /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
           public bool CanExecute(object parameter)
           {
              // Update this for your application's needs.
              return true;
           }

           public event EventHandler CanExecuteChanged;
        }
     }

4)现在添加将与View通信的ViewModel,并为其提供命令界面和值:

    namespace WpfApplication
    {
       using System;
       using System.Collections.Generic;
       using System.ComponentModel;
       using System.Linq;
       using System.Text;
       using System.Windows.Input;

       /// <summary>
       /// TODO: Update summary.
       /// </summary>
       public class MainWindowViewModel : INotifyPropertyChanged
       {    
          #region Implementation of INotifyPropertyChanged

          /// <summary>
          /// Occurs when a property value changes.
          /// </summary>
          public event PropertyChangedEventHandler PropertyChanged;

          /// <summary>
          /// Signal that the property value with the specified name has changed.
          /// </summary>
          /// <param name="propertyName">The name of the changed property.</param>
          protected virtual void OnPropertyChanged(string propertyName)
          {
             if (this.PropertyChanged != null)
             {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
             }
          }

          #endregion Implementation of INotifyPropertyChanged

          #region Backing Fields

          /// <summary>
          /// Gets or sets the value of Name.
          /// </summary>
          private string name;

          /// <summary>
          /// Gets or sets the value of Password.
          /// </summary>
          private string password;

          /// <summary>
          /// Gets or sets the value of LoginCommand.
          /// </summary>
          private LoginCommand loginCommand;

          #endregion Backing Fields

          #region Constructor

          /// <summary>
          /// Initializes a new instance of the <see cref="MainWindowViewModel"/> class.
          /// </summary>
          public MainWindowViewModel()
          {
             this.loginCommand = new LoginCommand();
          }

          #endregion Constructor

          #region Properties

          /// <summary>
          /// Gets or sets the name of the user.
          /// </summary>
          public string Name
          {
             get
             {
                return this.name;
             }

             set
             {
                if (this.name == value)
                {
                   return;
                }

                this.name = value;
                this.OnPropertyChanged("Name");
             }
          }

          /// <summary>
          /// Gets or sets the user password.
          /// </summary>
          public string Password
          {
             get
             {
                return this.password;
             }

             set
             {
                if (this.password == value)
                {
                   return;
                }

                this.password = value;
                this.OnPropertyChanged("Password");
             }
          }

          /// <summary>
          /// Gets or sets the command object that handles the login.
          /// </summary>
          public ICommand LoginCommand
          {
             get
             {
                return this.loginCommand;
             }

             set
             {
                if (this.loginCommand == value)
                {
                   return;
                }

                this.loginCommand = (LoginCommand)value;
                this.OnPropertyChanged("LoginCommand");
             }
          }

          #endregion Properties
       }
    }

5)最后,不要忘记添加一个将由LoginCommand打开到解决方案的其他窗口HomeScreen。 : - )

答案 1 :(得分:2)

要实现这一点,你应该像这样绑定按钮的命令 -

<Button Content ="OK" Command = {Binding OKCommand} />

在ViewModel中,为此绑定创建一个ICommand属性,如下所示 -

public class MyViewModel() : INotifyPropertyChanged
{

ICommand _OKCommand;
public ICommand OKCommad
{
  get { return _OKCommand; }
  set { _OKCommand = value; PropertyChanged(OKCommad); }
}

public MyViewModel()
{
  this.OKCommand += new DelegateCommand(OKCommand_Execute);
}

public void OKCommand_Execute()
{
 // Code for button click here
}

}

另请注意,要使用此委托命令,您需要添加对 Microsoft.Practices.Prism.dll

的引用