Вместо реализации щелчка кнопки обработчик в коде позади, использовать ICommand
и привязать его к событию кнопки в XAML.
Вот действительно отличный учебник, который получил меня начиная с MVVM: WPF Apps With The Model-View-ViewModel Design Pattern
[Отредактировано добавить пример кода]
Heres простой пример кода, чтобы сделать только то, что ваш пример делает, но в стиле 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, который будет обрабатывать логический логин. Обратите внимание, что я не выполнил его как 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) Теперь добавьте 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) Наконец, не забудьте добавить дополнительное окно HomeScreen
, который будет открыт в LoginCommand к решению.:-)
Большое спасибо, что заставляет вещи выделять cl earer. Означает ли это, что любой класс, в который я помещал обработчик событий, является моделью View? И любые методы, которые я хочу использовать с представлением, могут перейти в один класс, и это автоматически будет viewModel? Спасибо –
@EPOColla: В вашем примере я бы сказал «да». Но EventHandlers и методы не «автоматически» составляют ViewModel. В идеале вы структурируете свои классы, чтобы ViewModel был единственным классом ** напрямую ** обмениваться данными с View (некоторые исключения этого правила в стороне, например, Converters, Behaviors, ...). –
Это дает вам возможность реализовать такую обработку несколькими способами. Например, ViewModel может предоставить свойство, содержащее 'Command'. Как вы реализуете 'Command' ist до вас. Вы можете сделать это с помощью «RelayCommands», как в учебнике, или использовать класс, который только реализует интерфейс «ICommand» и ссылается на него с ViewModel. Красота MVVM заключается в том, что View никогда не должен знать о том, как вы обрабатываете событие Click, если вы придерживаетесь интерфейса. –