学習用資料3

今回はコード部分も含めて説明していく。
まずはボタンとテキストブロックを配置して、テキストブロックが変化する。ということをやっていく。

表示側コード

```xml:MainWindow.xaml
<Window x:Class="WpfApp2.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="HelloWorld" Name="textBlock" Width="200"></TextBlock>
            <Button Content="Button" Click="Button_Click" Width="200"></Button>
        </StackPanel>
    </Grid>
</Window>
```

C#側のコード

```cs:MainWindow.xaml.cs
using System.Windows;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            textBlock.Text = "Changed It !!!";
        }
    }
}
```

実行結果 ボタンクリック後

![wpf1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514262/22ff7d20-78f7-e7d4-1ad1-dfdaecb778bc.png)


TextBlockにNameというフィールドを作成することによって、そのNameを使うことによってC#側でTextBlockの値を変更することができる。
また、ButtonのClickというフィールドにButton_Clickというイベントを設定し、C#側でも同様のButton_Clickというメソッドを用意してあげることによってクリックした瞬間にButton_Clickのメソッド内部が実行される。

他にもLoadedイベントなどもある。
表示側

```xml:MainWindow.xaml
<Window x:Class="WpfApp2.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="NotLoaded" Name="textBlock" Width="200"></TextBlock>
        </StackPanel>
    </Grid>
</Window>
```

コード側

```cs:MainWindow.xaml.cs
using System.Windows;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            textBlock.Text = "Loaded";
        }
    }
}

```

###新しい画面の作成

まず新しい画面を用意する。
下画像のプロジェクト名。ここでは、WpfApp10を右クリックして追加→新しい項目
![wpf9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514262/d847d0b6-b4a7-fdd2-c2ea-d5fa8188e001.png)

すると、このような画面が出てくるので
![wpf10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514262/2e9b4cb6-76a4-c078-8d70-59e73bdf8c2e.png)

ウインドウを選択する。
ここではWindow1.xamlというものが作られるが、名前を変えたい場合下のWindow1.xamlを好きな名前に変えればよい。

そしてメインウィンドウからボタンを開いてサブウィンドウを開く。
まずはメインウィンドウのxaml側のコードから。

```xml:MainWindow.xaml
<Window x:Class="WpfApp10.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
            <TextBlock Text="Window1"></TextBlock>
            <Button Content="Button" Click="Button_Click"></Button>
        </StackPanel>
        
    </Grid>
</Window>

```

次にMainWindowのC#側のコード

```cs:MainWindow.xaml.cs
using System.Windows;

namespace WpfApp10
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var win = new Window1();
            win.ShowDialog();
        }
    }
}

```

ここのButton_Clickメソッドの中身にある。``` var win = new Window1()```の部分が重要で
まず新しいWindow1型のインスタンスを作成し、
``` win.ShowDialog()```や```win.Show()```などで新しい画面を開くことができる。

![wpf11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514262/01671b26-7627-fb99-e7e1-0da2f9570645.png)

```xml:Window1.xaml
<Window x:Class="WpfApp10.Window1"
        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"
        mc:Ignorable="d"
        Title="Window1" Height="450" Width="800">
    <Grid>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
            <TextBlock Text="Window2"></TextBlock>
            <Button Content="Button" Click="Button_Click"></Button>
        </StackPanel>
    </Grid>
</Window>
```

```cs:Window1.xaml.cs
using System.Windows;

namespace WpfApp10
{
    /// <summary>
    /// Window1.xaml の相互作用ロジック
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }
    }
}
```

Window1の方のButton_ClickにClose()というメソッドがあるが、Close()は画面を閉じる。
もちろん右上のばつボタンでも閉じることができる。
実は```win.ShowDialog()```は返り値を持っていてDefaltではfalseとなっており、
```DialogResult = true```にしてあげるとtrueで受け取ることができる。

```cs:MainWindow.xaml.cs
using System.Windows;

namespace WpfApp10
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var win = new Window1();
            var result = win.ShowDialog();
        }
    }
}

```

```cs:Window1.xaml.cs
using System.Windows;

namespace WpfApp10
{
    /// <summary>
    /// Window1.xaml の相互作用ロジック
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
            Close();
        }
    }
}

```

このようにすると、MainWindow.xaml.csでtrueを受け取ることができる。

###Binding

Bindingとはコード側とビュー側の結果を双方向に反映させるためのものである。
ただし、自動でそうなるかというとそういうわけでもなく
コードとxaml側でのバインディングの仕組みは、コードからこの値を変更しましたよ～反映お願いします～という感じでお願いして初めてコードからxaml側へ値が反映される。

少し分けながら説明する。
今回目的としてPersonクラスを作成し、Personクラスのインスタンスに変更を加えた場合xaml側にも反映させるようにさせる。

Personクラス

```cs:MainWindow.xaml.cs
using System.ComponentModel;

public class Person:INotifyPropertyChanged
    {
        private int _Id = 1;
        public int Id
        {
            get => _Id;
            set
            {
                _Id = value;
                SetProperty(nameof(Id));
            }
        }

        private string _Name = "taro";
        public string Name
        {
            get => _Name;
            set
            {
                _Name = value;
                SetProperty(nameof(Name));
            }
        }

        private string _Mail = "taro@co.jp";
        public string Mail
        {
            get => _Mail;
            set
            {
                _Mail = value;
                SetProperty(nameof(Mail));
            }
        }

        private void SetProperty(string PropertyName)
        {
            var e = new PropertyChangedEventArgs(PropertyName);
            PropertyChanged?.Invoke(this, e);
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

```

まずバインディングさせたいクラスにINotifyPropertyChangedというインターフェースを実装させる。
INotifyPropertyChangedというのはPropertyChangedという変数を持ち、それを実行させることによって
変更通知を出すことができる。
各メソッドにPropertyChangedを書いていくのは面倒なのでSetPropertyでメソッド化する。
PropertyChangedEventArgsというのに、PropertyNameを入れてどの変数名で変更があったのかを通知する。
各変数について、settterの方に各それぞれSetPropertyメソッドを入れていく。
引数はnameof(変数名)で行うことによって、変数名の書き間違えを防ぐ。
setterに実装を入れてしまうため、明示的に値を入れる処理を書いてあげないといけないが、public変数のまま``` Id = value```のようにするとこの瞬間また代入されるのでsetterの処理が再度走って、stackpverflowを起こしてしまう。
なので、privateの_Id,とpublicのId二つを作ってあげてsetするときは_Idにgetするときは_Idからするようにする。
これで、Personの方は完成。

MainWindowクラス側

```cs:MainWindow.xaml.cs
public partial class MainWindow : Window
    {
        private Person person = new Person();
        public MainWindow()
        {
            InitializeComponent();
            person.Id = 1;
            person.Name = "taro";
            person.Mail = "taro@co.jp";
            this.DataContext = person;
            
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            person.Id = 2;
            person.Name = "ziro";
            person.Mail = "ziro@co.jp";
        }
    }
```

ここでは、Personクラスのpersonというグローバル変数を作り、
```this.DataContext = person```によってバインディングが開始される。
Button_ClickメソッドはButton_Clickを実行したときに、personを変更させてバインディングされてるかを見るためだ。

コード全体

```cs:MainWindow.xaml.cs
using System.ComponentModel;
using System.Windows;

namespace WpfApp11
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private Person person = new Person();
        public MainWindow()
        {
            InitializeComponent();
            person.Id = 1;
            person.Name = "taro";
            person.Mail = "taro@co.jp";
            DataContext = person;
            
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            person.Id = 2;
            person.Name = "ziro";
            person.Mail = "ziro@co.jp";
        }
    }

    public class Person:INotifyPropertyChanged
    {
        private int _Id = 1;
        public int Id
        {
            get => _Id;
            set
            {
                _Id = value;
                SetProperty(nameof(Id));
            }
        }

        private string _Name = "taro";
        public string Name
        {
            get => _Name;
            set
            {
                _Name = value;
                SetProperty(nameof(Name));
            }
        }

        private string _Mail = "taro@co.jp";
        public string Mail
        {
            get => _Mail;
            set
            {
                _Mail = value;
                SetProperty(nameof(Mail));
            }
        }

        private void SetProperty(string PropertyName)
        {
            var e = new PropertyChangedEventArgs(PropertyName);
            PropertyChanged?.Invoke(this, e);
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

```

xaml側

```xml:MainWindow.xaml
<Window x:Class="WpfApp11.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="{Binding Name}"></TextBlock>
            <Button Content="ボタン" Click="Button_Click"></Button>
        </StackPanel>
    </Grid>
</Window>
```

xaml側にはTextBlockのところに、{Binding Name}というものが存在する。
ここと、personクラスのNameをBindingさせている。
これで、ボタンがクリックされたとき、ziroになっていればバインディングされていることになる。


実行結果
![wpf12.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514262/b93984a0-27f7-5a5b-1a8f-17010e2d14b4.png)

バインディングがされている。