この例が必要だったので、さまざまな手法を使用して書きました。
いくつかの設計目標を念頭に置いていました
1 - シンプルに保つ
2 - ビューにコード ビハインドがまったくない (ウィンドウ クラス)
3 - ViewModel クラス ライブラリの System 参照のみの依存関係を示します。
4 - ビジネス ロジックを ViewModel に保持し、一連の「スタブ」メソッドを記述することなく、適切なメソッドに直接ルーティングします。
これがコードです...
App.xaml (注目に値するのは StartupUri だけではありません)
<Application
x:Class="WpfApplicationCleanSeparation.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>
App.xaml.cs (メイン ビューを読み込む)
using System.Windows;
using WpfApplicationCleanSeparation.ViewModels;
namespace WpfApplicationCleanSeparation
{
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
var view = new MainView();
var viewModel = new MainViewModel();
view.InitializeComponent();
view.DataContext = viewModel;
CommandRouter.WireMainView(view, viewModel);
view.Show();
}
}
}
CommandRouter.cs (魔法)
using System.Windows.Input;
using WpfApplicationCleanSeparation.ViewModels;
namespace WpfApplicationCleanSeparation
{
public static class CommandRouter
{
static CommandRouter()
{
IncrementCounter = new RoutedCommand();
DecrementCounter = new RoutedCommand();
}
public static RoutedCommand IncrementCounter { get; private set; }
public static RoutedCommand DecrementCounter { get; private set; }
public static void WireMainView(MainView view, MainViewModel viewModel)
{
if (view == null || viewModel == null) return;
view.CommandBindings.Add(
new CommandBinding(
IncrementCounter,
(λ1, λ2) => viewModel.IncrementCounter(),
(λ1, λ2) =>
{
λ2.CanExecute = true;
λ2.Handled = true;
}));
view.CommandBindings.Add(
new CommandBinding(
DecrementCounter,
(λ1, λ2) => viewModel.DecrementCounter(),
(λ1, λ2) =>
{
λ2.CanExecute = true;
λ2.Handled = true;
}));
}
}
}
MainView.xaml (コード ビハインドはなく、文字通り削除されています!)
<Window
x:Class="WpfApplicationCleanSeparation.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplicationCleanSeparation="clr-namespace:WpfApplicationCleanSeparation"
Title="MainWindow"
Height="100"
Width="100">
<StackPanel>
<TextBlock Text="{Binding Counter}"></TextBlock>
<Button Content="Decrement" Command="WpfApplicationCleanSeparation:CommandRouter.DecrementCounter"></Button>
<Button Content="Increment" Command="WpfApplicationCleanSeparation:CommandRouter.IncrementCounter"></Button>
</StackPanel>
</Window>
MainViewModel.cs (この例は非常に単純化されているため、実際のモデルも含まれています。MVVM パターンの脱線はご容赦ください。
using System.ComponentModel;
namespace WpfApplicationCleanSeparation.ViewModels
{
public class CounterModel
{
public int Data { get; private set; }
public void IncrementCounter()
{
Data++;
}
public void DecrementCounter()
{
Data--;
}
}
public class MainViewModel : INotifyPropertyChanged
{
private CounterModel Model { get; set; }
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public MainViewModel()
{
Model = new CounterModel();
}
public int Counter
{
get { return Model.Data; }
}
public void IncrementCounter()
{
Model.IncrementCounter();
PropertyChanged(this, new PropertyChangedEventArgs("Counter"));
}
public void DecrementCounter()
{
Model.DecrementCounter();
PropertyChanged(this, new PropertyChangedEventArgs("Counter"));
}
}
}

素早く汚いだけで、誰かに役立つことを願っています。さまざまな Google を通じていくつかの異なるアプローチを見てきましたが、必要最小限のコードで簡単に実装できるものはありませんでした。さらに簡単にする方法があれば教えてください、ありがとう。
ハッピーコーディング:)
EDIT:私自身のコードを簡素化するために、これは Adds をワンライナーにするのに役立つかもしれません。
private static void Wire(this UIElement element, RoutedCommand command, Action action)
{
element.CommandBindings.Add(new CommandBinding(command, (sender, e) => action(), (sender, e) => { e.CanExecute = true; }));
}