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

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

ただいまの
回答率

90.35%

MVVMでModelを使いたい。

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 671

youth

score 6

前提・実現したいこと

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

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

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

該当のソースコード

<Window x:Class="BindingTenkey.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:BindingTenkey"
        mc:Ignorable="d"
        Title="MainWindow" Height="500" Width="800">
    <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="100*"/>
                <RowDefinition Height="100*"/>
                <RowDefinition Height="100*"/>
                <RowDefinition Height="100*"/>
                <RowDefinition Height="100*"/>
                <RowDefinition Height="100*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="80*"/>
                <ColumnDefinition Width="80*"/>
                <ColumnDefinition Width="80*"/>
            </Grid.ColumnDefinitions>
            <Button Grid.Row="0" Grid.Column="0" Click="OnNumberCilck">7</Button>
            <Button Grid.Row="0" Grid.Column="1" Click="OnNumberCilck">8</Button>
            <Button Grid.Row="0" Grid.Column="2" Click="OnNumberCilck">9</Button>
            <Button Grid.Row="1" Grid.Column="0" Click="OnNumberCilck">4</Button>
            <Button Grid.Row="1" Grid.Column="1" Click="OnNumberCilck">5</Button>
            <Button Grid.Row="1" Grid.Column="2" Click="OnNumberCilck">6</Button>
            <Button Grid.Row="2" Grid.Column="0" Click="OnNumberCilck">1</Button>
            <Button Grid.Row="2" Grid.Column="1" Click="OnNumberCilck">2</Button>
            <Button Grid.Row="2" Grid.Column="2" Click="OnNumberCilck">3</Button>
            <Button Grid.Row="3" Grid.Column="0" Click="OnNumberCilck">0</Button>
        <Button Grid.Row="3" Grid.Column="1" Click="OnClearClick">Clear</Button>
        <Button Grid.Row="3" Grid.Column="2" Click="OnEnterClick">Enter</Button>
        <Label Grid.Row="4" Grid.Column="0" Content="ID" />
        <TextBox Text="{Binding Path=MemberId, Mode=OneWay}" Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" />
        <Label Grid.Row="5" Grid.Column="0" Content="Name" />
        <TextBox Text="{Binding Path=MemberName, Mode=OneWay}" Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" />
    </Grid>
</Window>
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace BindingTenkey
{
    public partial class MainWindow : Window
    {
        MemberViewModel MemberViewModel;
        public List<MemberModel> Members = new List<MemberModel>();

        public MainWindow()
        {
            InitializeComponent();

            MemberViewModel = new MemberViewModel(this);

            DataContext = this.MemberViewModel;

            var member = new MemberModel()
            {
                MemberId = "2000",
                MemberName ="クウガ"
            };
            Members.Add(member);
            var member5 = new MemberModel()
            {
                MemberId = "555",
                MemberName = "555"
            };
            Members.Add(member5);
        }

        private void OnNumberCilck(object sender, System.Windows.RoutedEventArgs e)
        {
            var button = (Button)sender;
            this.MemberViewModel.NumberCommand(button.Content);
        }

        private void OnEnterClick(object sender, System.Windows.RoutedEventArgs e)
        {
            this.MemberViewModel.EnterCommand();
        }

        private void OnClearClick(object sender, System.Windows.RoutedEventArgs e)
        {
            this.MemberViewModel.ClearCommand();
        }
    }
}
namespace BindingTenkey
{
    public class MemberModel
    {
        public string MemberId { get; set; }

        public string MemberName { get; set; }
    }
}
using System.ComponentModel;
using System.Linq;

namespace BindingTenkey
{
    public class MemberViewModel : INotifyPropertyChanged
    {
        private MainWindow MainWindow;

        public MemberViewModel(MainWindow mainWindow)
        {
            this.MainWindow = mainWindow;
        }

        public string MemberId { get; set; }
        public string MemberName { get; set; }

        internal void NumberCommand(object content)
        {
            MemberId += (string)content;
            OnPropertyChanged(nameof(MemberId));
        }

        internal void EnterCommand()
        {
            var result = MainWindow.Members
                .Where(m => m.MemberId == MemberId).FirstOrDefault();
            if (result == null)
            {
                ClearCommand();
                return;
            }
            MemberName = result.MemberName;
            OnPropertyChanged(nameof(MemberName));
        }

        internal void ClearCommand()
        {
            MemberId = string.Empty;
            OnPropertyChanged(nameof(MemberId));
            MemberName = string.Empty;
            OnPropertyChanged(nameof(MemberName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

試したこと

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

疑問点

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

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

Windows10 Home
Visual Studio 2017 Community

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+2

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/21 10:16

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

    キャンセル

  • 2018/12/21 11:42

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

    キャンセル

  • 2018/12/25 13:03

    精神論は不要です。

    キャンセル

+2

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を使って実装しています。よろしければ参考にしてください。

<Window x:Class="BindingTenkey.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:BindingTenkey.Views"
        xmlns:vm="clr-namespace:BindingTenkey.ViewModels"
        Title="MainWindow" Height="500" Width="800">
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <Style x:Key="NumberButton" TargetType="{x:Type Button}">
            <Setter Property="Command" Value="{Binding NumberCommand}"/>
            <Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self},Path=Content}"/>
        </Style>
    </Window.Resources>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Closed">
            <l:DataContextDisposeAction/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="100*"/>
            <RowDefinition Height="100*"/>
            <RowDefinition Height="100*"/>
            <RowDefinition Height="100*"/>
            <RowDefinition Height="100*"/>
            <RowDefinition Height="100*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="80*"/>
            <ColumnDefinition Width="80*"/>
            <ColumnDefinition Width="80*"/>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0" Grid.Column="0" Style="{StaticResource NumberButton}" Content="7"/>
        <Button Grid.Row="0" Grid.Column="1" Style="{StaticResource NumberButton}" Content="8"/>
        <Button Grid.Row="0" Grid.Column="2" Style="{StaticResource NumberButton}" Content="9"/>
        <Button Grid.Row="1" Grid.Column="0" Style="{StaticResource NumberButton}" Content="4"/>
        <Button Grid.Row="1" Grid.Column="1" Style="{StaticResource NumberButton}" Content="5"/>
        <Button Grid.Row="1" Grid.Column="2" Style="{StaticResource NumberButton}" Content="6"/>
        <Button Grid.Row="2" Grid.Column="0" Style="{StaticResource NumberButton}" Content="1"/>
        <Button Grid.Row="2" Grid.Column="1" Style="{StaticResource NumberButton}" Content="2"/>
        <Button Grid.Row="2" Grid.Column="2" Style="{StaticResource NumberButton}" Content="3"/>
        <Button Grid.Row="3" Grid.Column="0" Style="{StaticResource NumberButton}" Content="0"/>
        <Button Grid.Row="3" Grid.Column="1" Content="Clear" Command="{Binding ClearCommand}"/>
        <Button Grid.Row="3" Grid.Column="2" Content="Enter" Command="{Binding EnterCommand}"/>
        <Label Grid.Row="4" Grid.Column="0" Content="ID" />
        <TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding MemberId, Mode=OneWay}"  />
        <Label Grid.Row="5" Grid.Column="0"  Content="Name" />
        <TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding MemberName, Mode=OneWay}" />
    </Grid>
</Window>
using BindingTenkey.Models;
using Livet;
using Livet.Commands;
using Livet.EventListeners;

namespace BindingTenkey.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {
        public MainWindowViewModel()
        {
            _model = new Model();
            CompositeDisposable.Add(new PropertyChangedEventListener(_model)
            {
                { nameof(_model.Member), (sender,e) => MemberChanged() }
            });
        }

        #region MemberId変更通知プロパティ
        private string _MemberId;

        public string MemberId
        {
            get
            { return _MemberId; }
            private set
            {
                if (_MemberId == value)
                    return;
                _MemberId = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        #region MemberName変更通知プロパティ
        private string _MemberName;

        public string MemberName
        {
            get
            { return _MemberName; }
            private set
            {
                if (_MemberName == value)
                    return;
                _MemberName = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        #region NumberCommand
        private ListenerCommand<string> _NumberCommand;

        public ListenerCommand<string> NumberCommand
        {
            get
            {
                if (_NumberCommand == null)
                {
                    _NumberCommand = new ListenerCommand<string>(Number);
                }
                return _NumberCommand;
            }
        }

        public void Number(string parameter)
        {
            MemberId = MemberId + parameter;
        }
        #endregion

        #region EnterCommand

        private ViewModelCommand _EnterCommand;

        public ViewModelCommand EnterCommand
        {
            get
            {
                if (_EnterCommand == null)
                {
                    _EnterCommand = new ViewModelCommand(Enter);
                }
                return _EnterCommand;
            }
        }

        public void Enter()
        {
            _model.SelectMember(MemberId);
        }

        #endregion

        #region ClearCommand
        private ViewModelCommand _ClearCommand;

        public ViewModelCommand ClearCommand
        {
            get
            {
                if (_ClearCommand == null)
                {
                    _ClearCommand = new ViewModelCommand(Clear);
                }
                return _ClearCommand;
            }
        }

        public void Clear()
        {
            MemberId = string.Empty;
        }
        #endregion

        private void MemberChanged()
        {
            if (_model.Member == null)
            {
                Clear();
            }
            MemberName = _model.Member?.MemberName;
        }

        private Model _model;
    }
}
using Livet;
using System.Collections.Generic;
using System.Linq;

namespace BindingTenkey.Models
{
    public class Model : NotificationObject
    {
        public Model()
        {
            _members = new List<MemberModel>()
            {
                new MemberModel()
                {
                    MemberId = "2000",
                    MemberName = "クウガ"
                },
                new MemberModel()
                {
                    MemberId = "555",
                    MemberName = "555"
                }
            };
        }

        #region Member変更通知プロパティ
        private MemberModel _Member;

        public MemberModel Member
        {
            get
            { return _Member; }
            private set
            {
                if (_Member == value)
                    return;
                _Member = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        public void SelectMember(string memberId)
        {
            _Member = _members.FirstOrDefault(m => m.MemberId.Equals(memberId));
            RaisePropertyChanged(nameof(Member));
        }

        private List<MemberModel> _members;
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/21 22:22 編集

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

    キャンセル

  • 2018/12/25 11: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なのか??? などと考えているところです。

    キャンセル

  • 2018/12/27 00:30

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

    キャンセル

+1

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

using System.ComponentModel;

namespace WpfApp2.Common
{
    public class NotificationObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
using System;
using System.Windows.Input;

namespace WpfApp2.Common
{
    /// <summary>
    /// コマンド(CommandParameterなし)
    /// </summary>
    public class DelegateCommand : ICommand
    {
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="action"></param>
        public DelegateCommand(Action action)
        {
            _action = action;
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="action"></param>
        public DelegateCommand(Action action, Func<bool> canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        /// <summary>
        /// コマンドの実行可否判定
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }

        /// <summary>
        /// コマンド実行
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            _action?.Invoke();
        }

        /// <summary>
        /// コマンドの実行可否変化イベントを駆動
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, new EventArgs());
        }

        public event EventHandler CanExecuteChanged;        // 実行可否イベント
        private Action _action = null;                      // 実行するコマンド
        private Func<bool> _canExecute = null;              // コマンドの実行可否判定
    }

    /// <summary>
    /// コマンド(CommandParameterあり)
    /// </summary>
    public class DelegateCommand<T> : ICommand
    {
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="action"></param>
        public DelegateCommand(Action<T> action)
        {
            _action = action;
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="action"></param>
        public DelegateCommand(Action<T> action, Func<bool> canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        /// <summary>
        /// コマンドの実行可否判定
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute();
        }

        /// <summary>
        /// コマンド実行
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            if (_action != null && parameter is T)
            {
                _action((T)parameter);
            }
        }

        /// <summary>
        /// コマンドの実行可否変化イベントを駆動
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, new EventArgs());
        }

        public event EventHandler CanExecuteChanged;        // 実行可否イベント
        private Action<T> _action = null;                      // 実行するコマンド
        private Func<bool> _canExecute = null;              // コマンドの実行可否判定
    }
}
using System.ComponentModel;
using System.Windows;
using WpfApp2.Common;
using WpfApp2.Models;

namespace WpfApp2.ViewModel
{
    public class MainWindowViewModel : NotificationObject
    {
        public MainWindowViewModel()
        {
            _model = new Model();
            WeakEventManager<INotifyPropertyChanged, PropertyChangedEventArgs>.AddHandler(_model, nameof(_model.PropertyChanged), (s, e) =>
            {
                if (e.PropertyName.Equals(nameof(_model.Member)))
                {
                    MemberChanged();
                }
            });
        }

        #region MemberId変更通知プロパティ
        private string _MemberId;

        public string MemberId
        {
            get
            { return _MemberId; }
            private set
            {
                if (_MemberId == value)
                    return;
                _MemberId = value;
                RaisePropertyChanged(nameof(MemberId));
            }
        }
        #endregion

        #region MemberName変更通知プロパティ
        private string _MemberName;

        public string MemberName
        {
            get
            { return _MemberName; }
            private set
            {
                if (_MemberName == value)
                    return;
                _MemberName = value;
                RaisePropertyChanged(nameof(MemberName));
            }
        }
        #endregion

        #region NumberCommand
        private DelegateCommand<string> _NumberCommand;

        public DelegateCommand<string> NumberCommand
        {
            get
            {
                if (_NumberCommand == null)
                {
                    _NumberCommand = new DelegateCommand<string>(Number);
                }
                return _NumberCommand;
            }
        }

        public void Number(string parameter)
        {
            MemberId = MemberId + parameter;
        }
        #endregion

        #region EnterCommand

        private DelegateCommand _EnterCommand;

        public DelegateCommand EnterCommand
        {
            get
            {
                if (_EnterCommand == null)
                {
                    _EnterCommand = new DelegateCommand(Enter);
                }
                return _EnterCommand;
            }
        }

        public void Enter()
        {
            _model.SelectMember(MemberId);
        }

        #endregion

        #region ClearCommand
        private DelegateCommand _ClearCommand;

        public DelegateCommand ClearCommand
        {
            get
            {
                if (_ClearCommand == null)
                {
                    _ClearCommand = new DelegateCommand(Clear);
                }
                return _ClearCommand;
            }
        }

        public void Clear()
        {
            MemberId = string.Empty;
        }
        #endregion

        private void MemberChanged()
        {
            if (_model.Member == null)
            {
                Clear();
            }
            MemberName = _model.Member?.MemberName;
        }

        private Model _model = null;
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る