ファイル名:Helpers\RelayCommand.cs
using System.Windows.Input;
namespace Maywork.WPF.Helpers;
public sealed 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 ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object? parameter)
=> _canExecute?.Invoke(parameter) ?? true;
public void Execute(object? parameter)
=> _execute(parameter);
public event EventHandler? CanExecuteChanged;
public void RaiseCanExecuteChanged()
=> CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
/*
// 使い方
// ICommand の簡易実装クラス。
// execute : 実行時に呼ばれる処理
// canExecute : 実行可否を判定する処理(省略時は常に true)
// RaiseCanExecuteChanged() を呼ぶことでボタン状態を更新可能。
// 使用例
public RelayCommand SubmitCommand { get; }
public MainViewModel()
{
SubmitCommand = new RelayCommand(
execute: _ => MessageBox.Show($"Title: {Title}"),
canExecute: _ => !IsEmpty
);
}
*/
Download
利用例(クリックで展開)
ファイル名:App.xaml
<Application x:Class="ViewModelBaseDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ViewModelBaseDemo"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
ファイル名:App.xaml.cs
using System.Configuration;
using System.Data;
using System.Windows;
namespace ViewModelBaseDemo;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
ファイル名:Helpers\ViewModelBase.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Maywork.WPF.Helpers;
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? name = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
protected bool SetProperty<T>(
ref T field,
T value,
Action<T>? onChanged = null,
[CallerMemberName] string? propertyName = null)
{
if (Equals(field, value))
return false;
field = value;
onChanged?.Invoke(value);
OnPropertyChanged(propertyName);
return true;
}
}
/*
// 使い方
// INotifyPropertyChanged の実装を簡略化する基底クラス。
// SetProperty() は値変更時のみ通知を行い、
// onChanged デリゲートで追加処理を記述できます。
// 使用例
using Maywork.WPF.Helpers;
namespace ViewModelBaseDemo;
internal class MainViewModel : ViewModelBase
{
private string _title = "";
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
}
*/
ファイル名:MainViewModel.cs
using Maywork.WPF.Helpers;
using System.Windows;
namespace ViewModelBaseDemo;
public class MainViewModel : ViewModelBase
{
private string _title = "";
public string Title
{
get => _title;
set => SetProperty(ref _title, value, _ =>
{
OnPropertyChanged(nameof(IsEmpty));
SubmitCommand.RaiseCanExecuteChanged();
});
}
public bool IsEmpty => string.IsNullOrWhiteSpace(_title);
public RelayCommand SubmitCommand { get; }
public MainViewModel()
{
SubmitCommand = new RelayCommand(
execute: _ => MessageBox.Show($"Title: {Title}"),
canExecute: _ => !IsEmpty
);
}
}
ファイル名:MainWindow.xaml
<Window x:Class="ViewModelBaseDemo.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:ViewModelBaseDemo"
mc:Ignorable="d"
Title="{Binding Title}" Height="450" Width="800">
<Grid>
<StackPanel Margin="20">
<TextBox Text="{Binding Title, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="Submit"
Command="{Binding SubmitCommand}"
Margin="0,10,0,0"/>
</StackPanel>
</Grid>
</Window>
ファイル名:MainWindow.xaml.cs
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ViewModelBaseDemo;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new MainViewModel();
this.DataContext = vm;
this.Loaded += (_, __) =>
{
vm.Title = "タイトルが変更された";
};
}
}
ファイル名:ViewModelBaseDemo.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
</Project>

コメント