エンジニアの備忘録

エンジニアの私が備忘録や思ったことをちょいちょい書いてます。

C# WPF入門-簡単アプリ作成-01

WPFで簡単アプリを作ってみましょう。

環境

VisualStudio2019
OS:Windows10
プロセッサ:Core i7-10510U
メモリ:16GB
フレームワーク:4.7.2


完成予定

FirstNameとLastNameを入力するとFullNameが自動的に画面に表示される
FullName = FirstName + LastName

f:id:dasuma20:20191117112148p:plain


WPFアプリケーションの作成

View側の作成

新規プロジェクト作成
WPFアプリ(.NET Framework)選択
→次へ
f:id:dasuma20:20191117014952p:plain


新しいプロジェクトを構成
→作成
f:id:dasuma20:20191117015153p:plain

Model側の作成

追加
→新しいプロジェクト
f:id:dasuma20:20191117015757p:plain


クラスライブラリ(.NET Framework
→次へ
f:id:dasuma20:20191117020208p:plain

わかりやすいようにプロジェクト名を".Model"を付ける
f:id:dasuma20:20191117020409p:plain

Modelを参照する

"InputName"プロジェクトの参照
→参照を追加
f:id:dasuma20:20191117020558p:plain

参照マネージャー
→"InputName.Model"にチェック
→OK
f:id:dasuma20:20191117020703p:plain


Model(Name.cs)の作成

namespace InputName.Model {
    public class Name : INotifyPropertyChanged {
        private string _firstName;
        private string _lastName;
        private string _fullName;

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

        public void SetName() {
            FullName = string.Format("{0} {1}", FirstName, LastName);
        }

        public string FirstName {
            get { return _firstName; }
            set {
                if(_firstName != value) {
                    _firstName = value;
                    SetName();
                    OnPropertyChanged("FirstName");
                }
            }
        }
        public string LastName {
            get { return _lastName; }
            set {
                if(_lastName != value) {
                    _lastName = value;
                    SetName();
                    OnPropertyChanged("LastName");
                }
            }
        }
        public string FullName {
            get { return _fullName; }
            set {
                if(_fullName != value) {
                    _fullName = value;
                    OnPropertyChanged("FullName");
                }
            }
        }
    }
}

ポイント

1.FirstName、LastNameのSetterに"SetName();"を追加
FirstName、LastNameの値を変更した時にFullNameを設定する
裏処理でFullNameを設定する

2.INotifyPropertyChangedを継承
MVVMでは裏処理で値を変更した際に画面に値変更した事を通知しないと値の変更がされません。
そのため"INotifyPropertyChanged"を継承してSetterに

OnPropertyChanged("変数名");

を書くことでModel→ViewModel→Modelへ変更通知がされます。


ViewModel(MainViewModel.cs)の作成

namespace InputName.ViewModel {
    public class MainViewModel : INotifyPropertyChanged {
        private Name _name;

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

        public MainViewModel() {
            _name = new Name();
        }

        public Name Name {
            get { return _name; }
            set {
                if(_name != value) {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
        }
    }
}

ポイント

こちらはポイントは特にないです。
変更通知はModelと同じ


View(MainWindow.xaml.cs)の作成

namespace InputName {
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window {
        private MainViewModel _mainViewModel;

        public MainWindow() {
            InitializeComponent();

            _mainViewModel = new MainViewModel();
            DataContext = _mainViewModel;
        }
    }
}

ポイント

1.DataContext
ViewとViewModelは1対1の関係になっています。
そのViewModelをDataContextさせます。


View(MainWindow.xaml)の作成

<Window x:Class="InputName.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:InputName"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <StackPanel Orientation="Vertical"
                HorizontalAlignment="Center"
                VerticalAlignment="Center">
        <StackPanel Orientation="Horizontal">
            <Label Content="FirstName:" Width="70"/>
            <TextBox Text="{Binding Name.FirstName}" Width="100"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Label Content="LastName:" Width="70"/>
            <TextBox Text="{Binding Name.LastName}" Width="100"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Label Content="FullName:" Width="70"/>
            <TextBox Text="{Binding Name.FullName}" Width="100"/>
        </StackPanel>
    </StackPanel>
</Window>

XAMLは全然わかりにくいですよね。
私も最初は全くわからなかったです。
慣れると案外簡単にXAMLをそのまま変更できます。

XAMLのタグ説明

Label:画面に文字列を表示
   Content:表示する内容
   Width:Labelの幅
TextBox:入力する箱
   Text:Bindingさせる変数
   Width:TextBoxの幅

ポイント

1.TextBoxのBinding
WPFで一番重要になるのがこのBindingです。
このBindingさせるパスがまた重要になります。

<TextBox Text="{Binding Name.FirstName}" Width="100"/>

なぜ"{Binding FirstName}"ではなく、"{Binding Name.FirstName}"なのか、
それはDataContextにMainViewModelを入れたからです。

DataContext = _mainViewModel;

MainViewModelから見た時にFirstNameの場所は
"Name.FirstName"をBindingに書きます。

2.そもそもBindingとは・・・
Model、ViewModelの変更をリアルタイにViewに反映させることです。
※リアルタイムかどうかは設定できます。
WPFで一番難しいのが、XAMLとBindingです。
私は今もこの2つに悩まされています。

完成

これで完成です。

今回は簡単にするためにNameのSetterに"SetName()"を書きました。
でもこの書き方はイマイチです。
次はCommandと言うものを使って"SetName()"を呼び出します。
WPFではこのCommandを使うのが一般的です。