C#(WPF)勉強メモ-ICommandを使用したログインフォームの作成
1. はじめに
C#勉強メモでは、筆者が学んだことをまとめたものである。今回は、ICommandインタフェースを使用してログインフォームを作成する。
2. 作成するログインフォーム
今回は、下記のログインフォームを目標とする(図1)。
仕様:
(1) ウィンドウにIDとパスワードの入力フォームを作成する。
(2) IDとパスワードを入力し、ログインボタンを押すと、ログイン成功と表示する。
(3) ただし、未入力がある場合は、入力エラーと表示する。
3. 画面を作成する
XAMLで画面を作成する。
<Window x:Class="WpfApp3.MainWindow"
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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="420">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="ID:" Grid.Row="0" VerticalAlignment="Center"/>
<TextBox x:Name="IdTextBox" Grid.Row="0" Margin="50,0,0,5" Width="200" Text="{Binding UserId, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="パスワード:" Grid.Row="1" VerticalAlignment="Center"/>
<TextBox x:Name="PasswordTextBox" Grid.Row="1" Margin="50,0,0,5" Width="200"
Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="ログイン" Grid.Row="2" Margin="130,26,130,-16" Width="100" Height="50"
Command="{Binding LoginCommand}"/>
</Grid>
</Window>
上記を実行すると、下記の画面を表示する。
今回、特に注目したいのが、Commandである。
<Button Content="ログイン" Grid.Row="2" Margin="130,26,130,-16" Width="100" Height="50"
Command="{Binding LoginCommand}"/>
Commandキーワードでバインディングしておくことで、XAMLと実装コードを分離することができる。また、ICommandインタフェースを使用して、コマンドの実行条件を動的に制御することができる。
もう一点が、UpdateSourceTrigger=PropertyChangedである。
Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
UpdateSourceTriggerとは、バインドしたプロパティを更新するタイミングを指定する。今回は、テキストボックスを更新するタイミングでPasswordプロパティに反映する。
4. ICommandインタフェース
3項で、Command={Binding…}と記述している。これは、Commandインタフェースを使用してコントロールを制御することを意味している。ICommandインタフェースの中身を確認する。
public interface ICommand
{
event EventHandler? CanExecuteChanged;
bool CanExecute(object? parameter);
void Execute(object? parameter);
}
ICommandの中身はインタフェースで、CanExecuteChangedというイベントハンドラとCanExecute、Executeというメソッドがある。
4.1 CanExecute
CanExecuteでは、コマンドが実行可能な状態であるか判断するメソッドである。
メソッドのシグネチャは、以下のようになっている。
bool CanExecute(object? parameter);
//記述例
public bool CanExecute(object parameter)
{
//実行可能
return true;
}
public bool CanExecute(object parameter)
{
//実行不可
return false;
}
trueだと実行可能で、falseだと実行不可を表す。例えば、IDとパスワードが入力されていない場合は、ログインボタンを押せないとする。この場合は、入力フォームをチェックし、どちらかが空の場合はfalseすることで、ボタンを無効状態にする。
4.2 CanExecuteChangedイベント
CanExecuteChangedは、GUIの変更があった場合に、CanExecuteを呼び出すイベントである。これによって、イベントに従って監視をして置き、ボタンの有効・無効などを設定できる。
4.3 Execute
Executeは、コマンドを実行したときに呼び出すメソッドである。
void Execute(object? parameter);
例えば、ボタンクリックした場合は、ここが呼びされる。
4.4 例題
まず、ユーザIDとパスワードを管理するクラスを定義する。
//UserInfo.cs
namespace WpfApp3
{
public class UserInfo
{
public string UserId; //ユーザID
public string Password; //パスワード
}
}
次に、MainWindow.csを定義する。
//MainWindow.cs
using System.Windows;
using System.Windows.Input;
namespace WpfApp3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new LoginViewModel();
}
}
}
最後に、LoginViewModel.csを定義する。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApp3
{
public class LoginViewModel : INotifyPropertyChanged
{
UserInfo _userInfo = new UserInfo();
private RelayCommand _loginCommand; //ログインコマンド
public string UserId
{
get { return _userInfo.UserId; }
set
{
if (_userInfo.UserId != value)
{
_userInfo.UserId = value;
OnPropertyChanged(nameof(UserId));
_loginCommand.RaiseCanExecuteChanged();
}
}
}
public string Password
{
get { return _userInfo.Password; }
set
{
if (_userInfo.Password != value)
{
_userInfo.Password = value;
OnPropertyChanged(nameof(Password));
_loginCommand.RaiseCanExecuteChanged();
}
}
}
public ICommand LoginCommand => _loginCommand;
public LoginViewModel()
{
_loginCommand = new RelayCommand(ExecuteLogin, CanExecuteLogin);
}
private void ExecuteLogin(object parameter)
{
MessageBox.Show("ログインOK");
}
private bool CanExecuteLogin(object parameter)
{
//テキストボックスがnullであるか判定する
return !string.IsNullOrWhiteSpace(UserId) && !string.IsNullOrWhiteSpace(Password);
}
//プロパティの変更通知
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
}
結果、簡単なログインフォームが作成できた。