質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

3回答

1447閲覧

MVVMでModelを使いたい。

youth

総合スコア12

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

2クリップ

投稿2018/12/20 08:54

編集2018/12/20 08:56

前提・実現したいこと

こんにちは!
Windows10でVisual Studio2017Communityで、WPFのシステムを作っています。
MVVMにしてみようと思い、次のように処理しました。

発生している問題・エラーメッセージ

Modelを使っていない…。
ModelのMemberIdとMemberNameを使うには、どうすればいいでしょう?

該当のソースコード

XAML

1<Window x:Class="BindingTenkey.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:BindingTenkey" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="500" Width="800"> 9 <Grid> 10 <Grid.RowDefinitions> 11 <RowDefinition Height="100*"/> 12 <RowDefinition Height="100*"/> 13 <RowDefinition Height="100*"/> 14 <RowDefinition Height="100*"/> 15 <RowDefinition Height="100*"/> 16 <RowDefinition Height="100*"/> 17 </Grid.RowDefinitions> 18 <Grid.ColumnDefinitions> 19 <ColumnDefinition Width="80*"/> 20 <ColumnDefinition Width="80*"/> 21 <ColumnDefinition Width="80*"/> 22 </Grid.ColumnDefinitions> 23 <Button Grid.Row="0" Grid.Column="0" Click="OnNumberCilck">7</Button> 24 <Button Grid.Row="0" Grid.Column="1" Click="OnNumberCilck">8</Button> 25 <Button Grid.Row="0" Grid.Column="2" Click="OnNumberCilck">9</Button> 26 <Button Grid.Row="1" Grid.Column="0" Click="OnNumberCilck">4</Button> 27 <Button Grid.Row="1" Grid.Column="1" Click="OnNumberCilck">5</Button> 28 <Button Grid.Row="1" Grid.Column="2" Click="OnNumberCilck">6</Button> 29 <Button Grid.Row="2" Grid.Column="0" Click="OnNumberCilck">1</Button> 30 <Button Grid.Row="2" Grid.Column="1" Click="OnNumberCilck">2</Button> 31 <Button Grid.Row="2" Grid.Column="2" Click="OnNumberCilck">3</Button> 32 <Button Grid.Row="3" Grid.Column="0" Click="OnNumberCilck">0</Button> 33 <Button Grid.Row="3" Grid.Column="1" Click="OnClearClick">Clear</Button> 34 <Button Grid.Row="3" Grid.Column="2" Click="OnEnterClick">Enter</Button> 35 <Label Grid.Row="4" Grid.Column="0" Content="ID" /> 36 <TextBox Text="{Binding Path=MemberId, Mode=OneWay}" Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" /> 37 <Label Grid.Row="5" Grid.Column="0" Content="Name" /> 38 <TextBox Text="{Binding Path=MemberName, Mode=OneWay}" Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" /> 39 </Grid> 40</Window>

C#

1using System.Collections.Generic; 2using System.Windows; 3using System.Windows.Controls; 4 5namespace BindingTenkey 6{ 7 public partial class MainWindow : Window 8 { 9 MemberViewModel MemberViewModel; 10 public List<MemberModel> Members = new List<MemberModel>(); 11 12 public MainWindow() 13 { 14 InitializeComponent(); 15 16 MemberViewModel = new MemberViewModel(this); 17 18 DataContext = this.MemberViewModel; 19 20 var member = new MemberModel() 21 { 22 MemberId = "2000", 23 MemberName ="クウガ" 24 }; 25 Members.Add(member); 26 var member5 = new MemberModel() 27 { 28 MemberId = "555", 29 MemberName = "555" 30 }; 31 Members.Add(member5); 32 } 33 34 private void OnNumberCilck(object sender, System.Windows.RoutedEventArgs e) 35 { 36 var button = (Button)sender; 37 this.MemberViewModel.NumberCommand(button.Content); 38 } 39 40 private void OnEnterClick(object sender, System.Windows.RoutedEventArgs e) 41 { 42 this.MemberViewModel.EnterCommand(); 43 } 44 45 private void OnClearClick(object sender, System.Windows.RoutedEventArgs e) 46 { 47 this.MemberViewModel.ClearCommand(); 48 } 49 } 50}

C#

1namespace BindingTenkey 2{ 3 public class MemberModel 4 { 5 public string MemberId { get; set; } 6 7 public string MemberName { get; set; } 8 } 9}

C#

1using System.ComponentModel; 2using System.Linq; 3 4namespace BindingTenkey 5{ 6 public class MemberViewModel : INotifyPropertyChanged 7 { 8 private MainWindow MainWindow; 9 10 public MemberViewModel(MainWindow mainWindow) 11 { 12 this.MainWindow = mainWindow; 13 } 14 15 public string MemberId { get; set; } 16 public string MemberName { get; set; } 17 18 internal void NumberCommand(object content) 19 { 20 MemberId += (string)content; 21 OnPropertyChanged(nameof(MemberId)); 22 } 23 24 internal void EnterCommand() 25 { 26 var result = MainWindow.Members 27 .Where(m => m.MemberId == MemberId).FirstOrDefault(); 28 if (result == null) 29 { 30 ClearCommand(); 31 return; 32 } 33 MemberName = result.MemberName; 34 OnPropertyChanged(nameof(MemberName)); 35 } 36 37 internal void ClearCommand() 38 { 39 MemberId = string.Empty; 40 OnPropertyChanged(nameof(MemberId)); 41 MemberName = string.Empty; 42 OnPropertyChanged(nameof(MemberName)); 43 } 44 45 public event PropertyChangedEventHandler PropertyChanged; 46 protected void OnPropertyChanged(string name) 47 { 48 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 49 } 50 } 51}

試したこと

MVVMほとんど初めて。なんとかコードを書いてみた。
動作はしました。

疑問点

1.ModelのMemberIdとMemberNameを使うには、どうすればいいでしょう?
2.Mainで作ったリストを渡すのに、コンストラクタで
MemberViewModel = new MemberViewModel(this);
としているのは、もっとよい方法はありますか?
よろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

Windows10 Home
Visual Studio 2017 Community

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

Model以前にMVVMの考え方から逸脱している部分が多いように見受けられましたので、気になった点をいくつか指摘させていただきます。

◆ビュー・ビューモデル・モデル間の依存関係が適切ではありません。
MVVMパターンの常識 ― 「M」「V」「VM」の役割とは? MVVMパターンの概要

ViewはViewModelに依存し、ViewModelはModelに依存します。逆方向の依存はありません

現在のコードではビューでモデルを生成している他、ビューモデルにコンストラクタでビューのインスタンスを渡している点がこれに反しています。疑問点2の回答ですが、このリストはMainでは作りません。ビューとビューモデルはモデルの情報を表示しますので、表示されるリストはモデルで生成するべきです。

◆ビジネスロジックに相当するモデルが存在していません。
MVVMパターンの常識 ― 「M」「V」「VM」の役割とは? Model

Modelは、C#などの汎用プログラミング言語で記述され、ドメイン・ロジックとデータ、つまりはビジネス・ロジックとビジネス・ドメインのステートを持ちます。

MVVMではコアロジックがすべてModelに記述されます。その理由はビュー周辺からロジックを分離し、単体テストができるようにするためです。このアプリケーションのコアロジックは今MemberViewModelの中で行っている、入力された値と一致するMemberIdを持つMemberNameを取得することだと思いますので、それを行うモデルを新しく作りましょう。MemberModelのリストも、このモデルの中で生成すれば良いです。

◆ビューからビューモデルの操作を呼び出す際はコマンドを使用します。
MVVMパターンの常識 ― 「M」「V」「VM」の役割とは? コマンドを使用する理由

コマンドとは、Viewに公開する操作のことです。ICommandインターフェイスの実装であるコマンドは、ViewModelのプロパティとして公開されます。データ・バインディング経由でViewから操作されます。

これに関しては上の2つほど逸脱しているわけではないと思うのですが、大抵はコマンドを使います。コマンドであればButtonのCommandプロパティにバインドできるので、コードビハインドにある各ボタンのイベントハンドラは必要なくなります。結果的にコードビハインドからはInitializeComponentの呼び出し以外の記述がなくなります。

またこれは指摘ではありませんが、INotifyPropertyChangedの実装はよく使うので、これを実装しただけのクラスを作っておくと各ビューモデルやモデルでこれを継承することで変更通知が実装できるので便利です。実装自体はこれでいいと思います。


これらを踏まえて私なりにMVVMっぽく書いてみたコードを載せますので、ご自身のコードと見比べてみてください。ちなみにMVVMは1から作ると結構大変なので、ライブラリを利用する事が多いです。このサンプルコードではLivetを使って実装しています。よろしければ参考にしてください。

XAML

1<Window x:Class="BindingTenkey.Views.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 5 xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 6 xmlns:l="http://schemas.livet-mvvm.net/2011/wpf" 7 xmlns:v="clr-namespace:BindingTenkey.Views" 8 xmlns:vm="clr-namespace:BindingTenkey.ViewModels" 9 Title="MainWindow" Height="500" Width="800"> 10 <Window.DataContext> 11 <vm:MainWindowViewModel/> 12 </Window.DataContext> 13 <Window.Resources> 14 <Style x:Key="NumberButton" TargetType="{x:Type Button}"> 15 <Setter Property="Command" Value="{Binding NumberCommand}"/> 16 <Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self},Path=Content}"/> 17 </Style> 18 </Window.Resources> 19 <i:Interaction.Triggers> 20 <i:EventTrigger EventName="Closed"> 21 <l:DataContextDisposeAction/> 22 </i:EventTrigger> 23 </i:Interaction.Triggers> 24 <Grid> 25 <Grid.RowDefinitions> 26 <RowDefinition Height="100*"/> 27 <RowDefinition Height="100*"/> 28 <RowDefinition Height="100*"/> 29 <RowDefinition Height="100*"/> 30 <RowDefinition Height="100*"/> 31 <RowDefinition Height="100*"/> 32 </Grid.RowDefinitions> 33 <Grid.ColumnDefinitions> 34 <ColumnDefinition Width="80*"/> 35 <ColumnDefinition Width="80*"/> 36 <ColumnDefinition Width="80*"/> 37 </Grid.ColumnDefinitions> 38 <Button Grid.Row="0" Grid.Column="0" Style="{StaticResource NumberButton}" Content="7"/> 39 <Button Grid.Row="0" Grid.Column="1" Style="{StaticResource NumberButton}" Content="8"/> 40 <Button Grid.Row="0" Grid.Column="2" Style="{StaticResource NumberButton}" Content="9"/> 41 <Button Grid.Row="1" Grid.Column="0" Style="{StaticResource NumberButton}" Content="4"/> 42 <Button Grid.Row="1" Grid.Column="1" Style="{StaticResource NumberButton}" Content="5"/> 43 <Button Grid.Row="1" Grid.Column="2" Style="{StaticResource NumberButton}" Content="6"/> 44 <Button Grid.Row="2" Grid.Column="0" Style="{StaticResource NumberButton}" Content="1"/> 45 <Button Grid.Row="2" Grid.Column="1" Style="{StaticResource NumberButton}" Content="2"/> 46 <Button Grid.Row="2" Grid.Column="2" Style="{StaticResource NumberButton}" Content="3"/> 47 <Button Grid.Row="3" Grid.Column="0" Style="{StaticResource NumberButton}" Content="0"/> 48 <Button Grid.Row="3" Grid.Column="1" Content="Clear" Command="{Binding ClearCommand}"/> 49 <Button Grid.Row="3" Grid.Column="2" Content="Enter" Command="{Binding EnterCommand}"/> 50 <Label Grid.Row="4" Grid.Column="0" Content="ID" /> 51 <TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding MemberId, Mode=OneWay}" /> 52 <Label Grid.Row="5" Grid.Column="0" Content="Name" /> 53 <TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding MemberName, Mode=OneWay}" /> 54 </Grid> 55</Window> 56

C#

1using BindingTenkey.Models; 2using Livet; 3using Livet.Commands; 4using Livet.EventListeners; 5 6namespace BindingTenkey.ViewModels 7{ 8 public class MainWindowViewModel : ViewModel 9 { 10 public MainWindowViewModel() 11 { 12 _model = new Model(); 13 CompositeDisposable.Add(new PropertyChangedEventListener(_model) 14 { 15 { nameof(_model.Member), (sender,e) => MemberChanged() } 16 }); 17 } 18 19 #region MemberId変更通知プロパティ 20 private string _MemberId; 21 22 public string MemberId 23 { 24 get 25 { return _MemberId; } 26 private set 27 { 28 if (_MemberId == value) 29 return; 30 _MemberId = value; 31 RaisePropertyChanged(); 32 } 33 } 34 #endregion 35 36 #region MemberName変更通知プロパティ 37 private string _MemberName; 38 39 public string MemberName 40 { 41 get 42 { return _MemberName; } 43 private set 44 { 45 if (_MemberName == value) 46 return; 47 _MemberName = value; 48 RaisePropertyChanged(); 49 } 50 } 51 #endregion 52 53 #region NumberCommand 54 private ListenerCommand<string> _NumberCommand; 55 56 public ListenerCommand<string> NumberCommand 57 { 58 get 59 { 60 if (_NumberCommand == null) 61 { 62 _NumberCommand = new ListenerCommand<string>(Number); 63 } 64 return _NumberCommand; 65 } 66 } 67 68 public void Number(string parameter) 69 { 70 MemberId = MemberId + parameter; 71 } 72 #endregion 73 74 #region EnterCommand 75 76 private ViewModelCommand _EnterCommand; 77 78 public ViewModelCommand EnterCommand 79 { 80 get 81 { 82 if (_EnterCommand == null) 83 { 84 _EnterCommand = new ViewModelCommand(Enter); 85 } 86 return _EnterCommand; 87 } 88 } 89 90 public void Enter() 91 { 92 _model.SelectMember(MemberId); 93 } 94 95 #endregion 96 97 #region ClearCommand 98 private ViewModelCommand _ClearCommand; 99 100 public ViewModelCommand ClearCommand 101 { 102 get 103 { 104 if (_ClearCommand == null) 105 { 106 _ClearCommand = new ViewModelCommand(Clear); 107 } 108 return _ClearCommand; 109 } 110 } 111 112 public void Clear() 113 { 114 MemberId = string.Empty; 115 } 116 #endregion 117 118 private void MemberChanged() 119 { 120 if (_model.Member == null) 121 { 122 Clear(); 123 } 124 MemberName = _model.Member?.MemberName; 125 } 126 127 private Model _model; 128 } 129} 130

C#

1using Livet; 2using System.Collections.Generic; 3using System.Linq; 4 5namespace BindingTenkey.Models 6{ 7 public class Model : NotificationObject 8 { 9 public Model() 10 { 11 _members = new List<MemberModel>() 12 { 13 new MemberModel() 14 { 15 MemberId = "2000", 16 MemberName = "クウガ" 17 }, 18 new MemberModel() 19 { 20 MemberId = "555", 21 MemberName = "555" 22 } 23 }; 24 } 25 26 #region Member変更通知プロパティ 27 private MemberModel _Member; 28 29 public MemberModel Member 30 { 31 get 32 { return _Member; } 33 private set 34 { 35 if (_Member == value) 36 return; 37 _Member = value; 38 RaisePropertyChanged(); 39 } 40 } 41 #endregion 42 43 public void SelectMember(string memberId) 44 { 45 _Member = _members.FirstOrDefault(m => m.MemberId.Equals(memberId)); 46 RaisePropertyChanged(nameof(Member)); 47 } 48 49 private List<MemberModel> _members; 50 } 51} 52

投稿2018/12/20 16:33

Gurz1019_MP

総合スコア196

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

youth

2018/12/21 01:14

ありがとうございます。MVVMの関連ページはだいぶ読んだのですが、VMの意味を理解できなくて、それで現状のようになっています。ご指摘大感謝。見比べるのはちょっと時間をかけますのでしばしお待ちください。 勉強中なので、できればLivetを使わないコードがあるとなお助かりました。 MVVMのVMの理解とLivetの理解と、ふたつはむずかしいので…。ひょっとするとLivetを理解できず、すごく時間がかかるかもしれません。
youth

2018/12/21 01:28

NuGetでLivetしてみました。LivetExtensionsとLivetCaskをインストールしてもエラー消えず動作しませんでした。・・・。
Gurz1019_MP

2018/12/21 13:18

Livetを使用した理由の一つは、INotifyPropertyChangedとICommandを実装するのが面倒だったからです。Livetではこれらを実装したクラスが提供されています。NotificationObject(Modelが継承しています)とViewModelCommandおよびListenerCommand<T>(両方VMで使っています)がそれです。これらを自力で実装するのであれば、ライブラリを使う必要性はありません。ですが大抵の場合自力で実装するメリットが(勉強目的以外)特にないので、ライブラリを使います。まずは便利なライブラリを使用してMVVMを理解し、なんとなくわかってきたらライブラリがやってくれていることを理解するという流れでもいいと思います。
Gurz1019_MP

2018/12/21 13:18

VMに関しては「Vを抽象化したもの」という表現を見たことがあります。UIとロジックの間に一つ挟むことで、ビジネスロジックの独立性を保ったままUIを変更することができます。例えばデスクトップとタブレットで同じ機能を利用できるアプリケーションなどでは、モデルは機能が同じなので全く同じものを利用し、ビューはそれぞれのハードで扱いやすいUIを提供して、ビューモデルはビューの違いで生まれるロジックの呼び出し方法の差などを吸収する、といった感じだと思います。あるいは複数のビューモデルで同じビューを使用すると、同じUIで異なる機能を提供したりすることもできます。
Gurz1019_MP

2018/12/21 13:25 編集

すみません、VS2017へのLivetの導入は少し面倒かもしれません。どうしても使いたい場合は、こちらなどを参考にしてみてください。https://days-of-programming.blogspot.com/2017/04/wpf-mvvmlivetvs2017.html INotifyPropertyChangedは正しく実装できているので、ICommandが実装できればLivetの必要性は殆ど無いです。 Livetはちょっとドキュメントが少ないように思うので、わからなければ聞いていただければお答えします。
youth

2018/12/25 02:45

いろいろ補足ありがとうございます。 (1)Livetは当面諦めました。現在Livetなしで動作していることと、Livetの学習コストが高すぎるためです。おっしゃるとおり、習得順としては最初に便利なライブラリで楽するのがベストと思いますが、Livetは導入が大変で便利なライブラリの範疇にないです。 (2)VMについては理解できていません。理解できないから書けないわけです。自分のコードと比較すると(Livetが多くてぼんやりですが)わたしがModelだと思っているものはViewModelであり、ViewModelだと思っているものはModelであるように感じました。ちょうど真逆なのかなと。 とはいえ、ではViewModelでDbにつなぐのか? ModelだけでDbにつなげないとModelだけでうごかないじゃん? などと疑問噴出。MVCのModelとMVVMのModelは違うのか、MVCのModelはMVVMのVMなのか??? などと考えているところです。
Gurz1019_MP

2018/12/26 15:30

ちょど真逆、ではありません。ViewとViewModelが、本来Modelで行うべき処理をやっています。 Livetを使わないサンプルコードを書きました。コードが見づらくなるので回答を分けます。
guest

0

まずは、MVVM入門 その1「シンプル四則演算アプリケーションの作成」
この辺りから順に進めてください。
今のコードの動いている部分はMVVMと関係ありません。

投稿2018/12/20 10:35

hihijiji

総合スコア4150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

youth

2018/12/21 01:16

この回答も質問の意図とぜんぜん関係ないです。 ページはだいぶ読んでわからないので、具体的なご指摘をいただきたく質問しました。
hihijiji

2018/12/21 02:42

定石は真似るのが鉄則です。 理解できないから我流に走るのではなく、既にある動くものをちょっとづつ変えてその結果を体感しながら学ぶのが近道です。
youth

2018/12/25 04:03

精神論は不要です。
guest

0

Livetを使わないサンプルです。LivetなしのMVVMを作ったことがない(ICommandの実装が初めて)ので間違いがあるかもしれませんが、一通り動いているのでこんな感じだと思います。ViewとModelは前回のサンプルとほぼ変わらないので省略します。

C#

1using System.ComponentModel; 2 3namespace WpfApp2.Common 4{ 5 public class NotificationObject : INotifyPropertyChanged 6 { 7 public event PropertyChangedEventHandler PropertyChanged; 8 9 public void RaisePropertyChanged(string propertyName) 10 { 11 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 12 } 13 } 14} 15

C#

1using System; 2using System.Windows.Input; 3 4namespace WpfApp2.Common 5{ 6 /// <summary> 7 /// コマンド(CommandParameterなし) 8 /// </summary> 9 public class DelegateCommand : ICommand 10 { 11 /// <summary> 12 /// コンストラクタ 13 /// </summary> 14 /// <param name="action"></param> 15 public DelegateCommand(Action action) 16 { 17 _action = action; 18 } 19 20 /// <summary> 21 /// コンストラクタ 22 /// </summary> 23 /// <param name="action"></param> 24 public DelegateCommand(Action action, Func<bool> canExecute) 25 { 26 _action = action; 27 _canExecute = canExecute; 28 } 29 30 /// <summary> 31 /// コマンドの実行可否判定 32 /// </summary> 33 /// <param name="parameter"></param> 34 /// <returns></returns> 35 public bool CanExecute(object parameter) 36 { 37 return _canExecute == null ? true : _canExecute(); 38 } 39 40 /// <summary> 41 /// コマンド実行 42 /// </summary> 43 /// <param name="parameter"></param> 44 public void Execute(object parameter) 45 { 46 _action?.Invoke(); 47 } 48 49 /// <summary> 50 /// コマンドの実行可否変化イベントを駆動 51 /// </summary> 52 public void RaiseCanExecuteChanged() 53 { 54 CanExecuteChanged?.Invoke(this, new EventArgs()); 55 } 56 57 public event EventHandler CanExecuteChanged; // 実行可否イベント 58 private Action _action = null; // 実行するコマンド 59 private Func<bool> _canExecute = null; // コマンドの実行可否判定 60 } 61 62 /// <summary> 63 /// コマンド(CommandParameterあり) 64 /// </summary> 65 public class DelegateCommand<T> : ICommand 66 { 67 /// <summary> 68 /// コンストラクタ 69 /// </summary> 70 /// <param name="action"></param> 71 public DelegateCommand(Action<T> action) 72 { 73 _action = action; 74 } 75 76 /// <summary> 77 /// コンストラクタ 78 /// </summary> 79 /// <param name="action"></param> 80 public DelegateCommand(Action<T> action, Func<bool> canExecute) 81 { 82 _action = action; 83 _canExecute = canExecute; 84 } 85 86 /// <summary> 87 /// コマンドの実行可否判定 88 /// </summary> 89 /// <param name="parameter"></param> 90 /// <returns></returns> 91 public bool CanExecute(object parameter) 92 { 93 return _canExecute == null ? true : _canExecute(); 94 } 95 96 /// <summary> 97 /// コマンド実行 98 /// </summary> 99 /// <param name="parameter"></param> 100 public void Execute(object parameter) 101 { 102 if (_action != null && parameter is T) 103 { 104 _action((T)parameter); 105 } 106 } 107 108 /// <summary> 109 /// コマンドの実行可否変化イベントを駆動 110 /// </summary> 111 public void RaiseCanExecuteChanged() 112 { 113 CanExecuteChanged?.Invoke(this, new EventArgs()); 114 } 115 116 public event EventHandler CanExecuteChanged; // 実行可否イベント 117 private Action<T> _action = null; // 実行するコマンド 118 private Func<bool> _canExecute = null; // コマンドの実行可否判定 119 } 120} 121

C#

1using System.ComponentModel; 2using System.Windows; 3using WpfApp2.Common; 4using WpfApp2.Models; 5 6namespace WpfApp2.ViewModel 7{ 8 public class MainWindowViewModel : NotificationObject 9 { 10 public MainWindowViewModel() 11 { 12 _model = new Model(); 13 WeakEventManager<INotifyPropertyChanged, PropertyChangedEventArgs>.AddHandler(_model, nameof(_model.PropertyChanged), (s, e) => 14 { 15 if (e.PropertyName.Equals(nameof(_model.Member))) 16 { 17 MemberChanged(); 18 } 19 }); 20 } 21 22 #region MemberId変更通知プロパティ 23 private string _MemberId; 24 25 public string MemberId 26 { 27 get 28 { return _MemberId; } 29 private set 30 { 31 if (_MemberId == value) 32 return; 33 _MemberId = value; 34 RaisePropertyChanged(nameof(MemberId)); 35 } 36 } 37 #endregion 38 39 #region MemberName変更通知プロパティ 40 private string _MemberName; 41 42 public string MemberName 43 { 44 get 45 { return _MemberName; } 46 private set 47 { 48 if (_MemberName == value) 49 return; 50 _MemberName = value; 51 RaisePropertyChanged(nameof(MemberName)); 52 } 53 } 54 #endregion 55 56 #region NumberCommand 57 private DelegateCommand<string> _NumberCommand; 58 59 public DelegateCommand<string> NumberCommand 60 { 61 get 62 { 63 if (_NumberCommand == null) 64 { 65 _NumberCommand = new DelegateCommand<string>(Number); 66 } 67 return _NumberCommand; 68 } 69 } 70 71 public void Number(string parameter) 72 { 73 MemberId = MemberId + parameter; 74 } 75 #endregion 76 77 #region EnterCommand 78 79 private DelegateCommand _EnterCommand; 80 81 public DelegateCommand EnterCommand 82 { 83 get 84 { 85 if (_EnterCommand == null) 86 { 87 _EnterCommand = new DelegateCommand(Enter); 88 } 89 return _EnterCommand; 90 } 91 } 92 93 public void Enter() 94 { 95 _model.SelectMember(MemberId); 96 } 97 98 #endregion 99 100 #region ClearCommand 101 private DelegateCommand _ClearCommand; 102 103 public DelegateCommand ClearCommand 104 { 105 get 106 { 107 if (_ClearCommand == null) 108 { 109 _ClearCommand = new DelegateCommand(Clear); 110 } 111 return _ClearCommand; 112 } 113 } 114 115 public void Clear() 116 { 117 MemberId = string.Empty; 118 } 119 #endregion 120 121 private void MemberChanged() 122 { 123 if (_model.Member == null) 124 { 125 Clear(); 126 } 127 MemberName = _model.Member?.MemberName; 128 } 129 130 private Model _model = null; 131 } 132} 133

投稿2018/12/26 15:38

Gurz1019_MP

総合スコア196

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問