nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

Visual Studio 2017のプロジェクト テンプレートで、簡単プロジェクトひな形作成

はじめに

MVVMを意識したWPFのプロジェクトを作成するのは結構大変です。もともとVisual Studioのプロジェクトで用意されているWPFプロジェクトは、MVVMを意識したプロジェクトになっていないためです。(´;ω;`)

そこで、自分で、プロジェクトのテンプレートを作成するのがらくちんです。

MVVMを意識したWPFのプロジェクトのひな形作成方法は以下のページが素晴らしいです。
http://yujiro15.net/YKSoftware/MVVM_Tree.html

<MVVMを意識したWPFプロジェクトひな形構成例>
f:id:nprogram:20180220233509p:plain

プロジェクトテンプレート作成方法は、上記のようなプロジェクトのひな形を作成した状態で、 Visual Studio 2017のメニューのプロジェクトから、テンプレートのエクスポートを選択します。 プロジェクトのテンプレートをラジオボタンで選択します。 f:id:nprogram:20180220233644p:plain

テンプレートオプション画面で、テンプレートの説明を入力した後、完了ボタンを押してください。 f:id:nprogram:20180220233700p:plain

自作したプロジェクトテンプレートを、新しいプロジェクト作成時に使用できるようになります。 f:id:nprogram:20180220233838p:plain

なお、NuGetで外部ライブラリ(例えばPrism.WPF)を登録することもできますので、プロジェクトを新規作成するたびに、NuGetで外部ライブラリをインストールする必要がなくなります。(とてもありがたい。)

ReactivePropertyが便利すぎてとても助かる

ReactivePropertyの使い方を学習していきます

画面

f:id:nprogram:20180210194943p:plain

コード

[MainWindowViewModel.cs]

using Reactive.Bindings;
using System;
using System.Linq;
using System.Reactive.Linq;

namespace ReactivePropertySample
{
    class MainWindowViewModel
    {
        public ReactiveProperty<string> Input { get; private set; }
        public ReactiveProperty<string> Output { get; private set; }
        public ReactiveCommand ClearCommand { get; private set; }
        public ReactiveCommand SetCommand { get; private set; }

        public MainWindowViewModel()
        {
            // ViewModelクラスのコンストラクタでReactiveProperty間の関連を定義

            // ReactivePropertyを作成する基本的な方法は、以下の2つ
            // 1. new演算子を使って生成する
            //    コンストラクタの引数にデフォルト値を指定する。指定しない場合は、その型のでデフォルト値が使われる)
            // 2. IObservable<T> に対してToReactiveProperty拡張メソッドを呼ぶ
            this.Input = new ReactiveProperty<string>(""); // デフォルト値を指定してReactivePropertyを作成
            this.Output = this.Input
                .Delay(TimeSpan.FromSeconds(1)) // 1秒間待機して
                .Select(x => x.ToUpper()) // 大文字に変換して
                .ToReactiveProperty(); // ReactiveProperty化する


            // CommandのExecuteが呼ばれたときの処理はSubscribeメソッドで指定します。
            // 先ほど作成したViewModelのInputプロパティが空じゃないときに、Inputプロパティを空にするCommandを追加したコードは以下のようになります。
            this.ClearCommand = this.Input
                .Select(x => !string.IsNullOrWhiteSpace(x)) // Input.Valueが空じゃないとき
                .ToReactiveCommand(); // 実行可能なCommandを作る

            // Commandの動作を定義する
            this.ClearCommand.Subscribe(_ => this.Input.Value = "");


            // 現在の日付を取得する
            DateTime dtToday = DateTime.Today;

            // 実行可能なCommandを生成する
            this.SetCommand = new ReactiveCommand();

            // Commandの動作を定義する
            this.SetCommand.Subscribe(_ => this.Input.Value += dtToday.ToString());
        }
    }
}

[MainWindow.xaml]

<Window x:Class="ReactivePropertySample.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:ReactivePropertySample"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    
    <StackPanel>
        <Label Content="入力" />
        <TextBox Text="{Binding Input.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        <Label Content="出力" />
        <TextBlock Text="{Binding Output.Value}"/>
        <Button Content="SET Today Date" Command="{Binding SetCommand}" />
        <Button Content="CLEAR Text" Command="{Binding ClearCommand}" />
    </StackPanel>
</Window>

他のファイルは変更ありません。

ReactivePropertyの勉強は以下のサイトがおすすめです。

  • MVVMとリアクティブプログラミングを支援するライブラリ「ReactiveProperty v2.0」オーバービュー blog.okazuki.jp

  • MVVMをリアクティブプログラミングで快適にReactivePropertyオーバービュー blog.okazuki.jp

tmori3y2.hatenablog.com

qiita.com

WPF/C#/MVVM/Prismで、簡単なWPFアプリケーションを作ります

WPF/C#/Prismで、簡単なWPFアプリケーションを作ります

以下のサイトにも記載があるように、WPFアプリケーションでMVVMのアプリケーションを作成するのは難しいと思います。

そのため、PrismというMVVM基盤ライブラリを使用します。

qiita.com

本アプリケーションでは、Prismを使用しているため、NuGetからPrism.Wpfというライブラリをプロジェクトにインストールしてください。

画面の見た目

f:id:nprogram:20180207100504p:plain

プロジェクト構成

f:id:nprogram:20180207100908p:plain

コード

[MainWindow.xaml]

<Window x:Class="WpfApp3.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:WpfApp3"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" Text="{Binding LeftValue}" TextAlignment="Center" VerticalContentAlignment="Center"/>
        <Label Grid.Row="1" Content="+" HorizontalAlignment="Center" VerticalContentAlignment="Center"/>
        <TextBox Grid.Row="2" Text="{Binding RightValue}" TextAlignment="Center" VerticalContentAlignment="Center"/>
        <Label Grid.Row="3" Content="=" HorizontalAlignment="Center" VerticalContentAlignment="Center"/>
        <TextBox Grid.Row="4" Text="{Binding AnswerValue}" IsEnabled="False" TextAlignment="Center" VerticalContentAlignment="Center"/>
        <Button Grid.Row="5" Content ="足し算開始" Command ="{Binding CalcCommand , Mode=OneWay}"/>
    </Grid>
</Window>

MainWindowクラスのコンストラクタにおいて、DataContext にViewModelクラスのインスタンスを設定しています。

[MainWindow.xaml.cs]

using System.Windows;

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

            this.DataContext = new ViewModel();
        }
    }
}

[ViewModel.cs]

using Prism.Commands;
using Prism.Mvvm;

namespace WpfApp3
{
    class ViewModel : BindableBase
    {
        public Model model;

        public ViewModel()
        {
            model = new Model();
        }

        private double _leftValue;
        public double LeftValue
        {
            get { return _leftValue; }
            set { this.SetProperty(ref this._leftValue, value); }
        }

        private double _rightValue;
        public double RightValue
        {
            get { return _rightValue; }
            set { this.SetProperty(ref this._rightValue, value); }
        }

        private double _answerValue;
        public double AnswerValue
        {
            get { return _answerValue; }
            set { this.SetProperty(ref this._answerValue, value); }
        }

        private DelegateCommand calcComamnd;
        public DelegateCommand CalcCommand
        {
            get { return calcComamnd = calcComamnd ?? new DelegateCommand(CalcExecute); }
        }

        private void CalcExecute()
        {
            AnswerValue = model.Calc(LeftValue, RightValue);
        }
    }
}

[Model.cs]

namespace WpfApp3
{
    class Model
    {
        public double Calc(double x, double y)
        {
            return x + y;
        }
    }
}

Google Testを使ってみる (Visual Studio 2017 Community) (C++)

環境について

以下の環境で、Google Testを使用してみます。

  • Windows 10
  • Visual Studio 2017 Community
  • Cmake 3.10.2
  • C++

Google Testのライブラリファイル生成手順

まず、Google Testを、GitHubからダウンロードします。 Zipファイルでダウンロードしてください。 ダウンロード後は、アクセス制限がかからないフォルダまで移動してください。 この後、Cドライブ直下など、アクセス制限のあるフォルダで作業すると、Visual Studioでビルドするときに、エラーになってビルドできなくなる可能性があるためです。 github.com

次に、以下のホームページでCMakeをダウンロードします。(例 : cmake-3.10.2-win64-x64.msi)
https://cmake.org/

環境変数の設定は、インストール時の設定で解決できそうです。
f:id:nprogram:20180131041231p:plain

この後、Visual Studioを用いてビルドします。
Cmake 3.10.2でビルドできるVisual Studioのバージョンは、以下のとおり。
本情報は、cmake公式ページのドキュメントのHELP(V3.10)のVisual Studio Generatorsの項目に記載があります。
https://cmake.org/documentation/

  • Visual Studio 6
  • Visual Studio 7
  • Visual Studio 7 .NET 2003
  • Visual Studio 8 2005
  • Visual Studio 9 2008
  • Visual Studio 10 2010
  • Visual Studio 11 2012
  • Visual Studio 12 2013
  • Visual Studio 14 2015
  • Visual Studio 15 2017

(1) コマンドプロンプトを開き、ダウンロードしたGoogle Testまで移動。 <your dir path>googletest-master\googletest
(2) googletest-master\googletestのまでcdコマンドで移動
(3) mkdir buildで、ワーキングディレクトリ作成
(4) cd buildでワーキングディレクトリに移動
(5) cmake .. -DBUILD_GTEST=ON -DBUILD_GMOCK=OFF -G "Visual Studio 15 Win64"でビルドする

<コマンドプロンプト出力結果>

<working dir path>googletest-master\googletest\build>cmake .. -DBUILD_GTEST=ON -DBUILD_GMOCK=OFF -G "Visual Studio 15 Win64"
-- Selecting Windows SDK version 10.0.15063.0 to target Windows 10.0.16299.
-- The CXX compiler identification is MSVC 19.11.25508.2
-- The C compiler identification is MSVC 19.11.25508.2
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.11.25503/bin/HostX86/x64/cl.exe
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.11.25503/bin/HostX86/x64/cl.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.11.25503/bin/HostX86/x64/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.11.25503/bin/HostX86/x64/cl.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Found PythonInterp: C:/Program Files/Python36/python.exe (found version "3.6.2")
-- Looking for pthread.h
-- Looking for pthread.h - not found
-- Found Threads: TRUE
-- Configuring done
-- Generating done
CMake Warning:
  Manually-specified variables were not used by the project:

    BUILD_GMOCK
    BUILD_GTEST


-- Build files have been written to: <working dir path>googletest-master/googletest/build

(6) ワーキングディレクトリにプロジェクトファイルgtest.slnが作成されるので、開きます。

(7) プロジェクトのALL_BUILDをビルドします。ライブラリファイルは、build\Debugbuild\Releaseに作成されます。pdbファイルを含めた中間ファイルは、build\gtest.dirに作成されます。
* gtestd.lib * gtest.pdb * gtest_maind.lib * gtest_main.pdb Releaseフォルダ以下にも以下のように作成されます。 gtest.lib gtest_main.lib

Visual StudioでGoogle Testのライブラリファイルを使用する

本方法は参考ページに非常に詳しく記載されています。

  Sample
  │  Sample.sln
  └─Sample
     │  Sample.cpp
     │  Sample.vcxproj
     │  Sample.vcxproj.filters
     │  ReadMe.txt
     │  stdafx.cpp
     │  stdafx.h
     │  targetver.h
     │
     ├─include     // googletest-master\googletest\include をコピー
     │
     └─lib         // googletest-master\googletest\buildのDebugとReleaseフォルダをコピー(※1)
         ├─Debug
         └─Release

(※1) pdbファイルが必要な場合は、```build\gtest.dir```から取得してください

(1) 構成を[すべての構成] に設定し、INCLUDEディレクトリの追加
ソリューション右クリック -> プロパティ -> 構成プロパティ -> C/C++ -> [追加のインクルードディレクトリ] -> gtestのincludeディレクトリを追加
※$(ProjectDir)を使用して追加した方がよい
例:$(ProjectDir)include

(2) 構成を[すべての構成] に設定し、libファイルのリンク設定
ソリューション右クリック -> プロパティ -> 構成プロパティ -> リンカー -> [追加のライブラリディレクトリ] -> gtestのlibのディレクトリを追加 $(Configuration)を利用して追加した方がよい
例:$(ProjectDir)lib\$(Configuration)
ソリューション右クリック -> プロパティ -> 構成プロパティ -> リンカー -> 入力 -> [追加の依存ファイル] ->

(2-1) 構成を[Release] に設定し、下記を追加 gtest.lib gtest_main.lib

(2-2) 構成を[Debug] に設定し、下記を追加 gtestd.lib gtest_maind.lib

(3) ランタイムライブラリのリンク方法の指定を変更
ソリューション右クリック -> プロパティ -> 構成プロパティ -> C/C++ -> コード生成 -> [ランタイムライブラリ] ->
(3-1) 構成を[Release] に設定し、[マルチスレッド (/MT)] を設定
(3-2) 構成を[Debug] に設定し、[マルチスレッド デバッグ (/MTd)] を設定

(4) 以下のようにコードを書いてSHIFT + F5で実行してください。なお、Google-TestはWin64のものをダウンロードしているので、
プラットフォームは、x64環境でないと正しく動作しません。Google Testが正しく動作することを確認しました。

[コード]

#include "stdafx.h"
#include "gtest/gtest.h"


TEST(Test1, test1_1) {
    int num1 = 1;
    int num2 = 1;

    ASSERT_EQ(num1, num2);  // 成功する

    num2 = 2;

    ASSERT_EQ(num1, num2);  // 失敗する

}

[実行結果] f:id:nprogram:20180131061012p:plain

参考ページ

以下のページを参考にさせていただきました。ありがとうございます。 qiita.com

UIスレッド以外から、UIスレッドのコレクションにアクセスする方法

UIスレッド以外から、UIスレッドのコレクションにアクセスすると、エラーとなり、アクセスできない問題が発生します。

以下のサイトに、問題解決方法が記載してありました。

blog.okazuki.jp

sourcechord.hatenablog.com

WPFで登録と削除が可能なリストを作成します

はじめに

ObservableCollectionを使用して、登録と削除が可能なリストを持つアプリを作成します。

アプリの見た目

アプリには、登録、削除、全削除ボタンがあります。
名前と連絡先に文字列を入れて登録ボタンを押すと、データが登録されます。

リストの項目を選択して削除ボタンを押すと、選択した項目のデータが削除されます。

全削除ボタンを押すと、リストのデータがすべて削除されます。

ただし、列の横幅は、データの長さによって自動調整されません。(´;ω;`) 

f:id:nprogram:20180118044159p:plain

プロジェクト構成

プロジェクト構成は以下のとおりです。

f:id:nprogram:20180118044353p:plain

コード

コードは以下のとおりです。
* MainWindow.xaml

<Window x:Class="ListView.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:ListView"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <!-- 行を3つ定義 -->
        <Grid.RowDefinitions>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <!-- 列を3つ定義 -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <ListView Name="lstEntry" ItemsSource="{Binding Path=Items}" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1" Grid.ColumnSpan="5" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" Width="200"/>
                    <GridViewColumn Header="Contact" DisplayMemberBinding="{Binding Path=Contact}" Width="200"/>
                </GridView>
            </ListView.View>
        </ListView>

        <Button Content="登録" Grid.Row="1" Grid.Column="0" Click="Add_Click" />
        <Button Content="削除" Grid.Row="2" Grid.Column="0" Click="Remove_Click" />
        <Button Content="全削除" Grid.Row="3" Grid.Column="0" Click="RemoveAll_Click" />
        <Label Content="名前"  Grid.Row="1" Grid.Column="1" HorizontalAlignment ="Center" VerticalAlignment ="Center"/>
        <Label Content="連絡先" Grid.Row="1" Grid.Column="3" HorizontalAlignment ="Center" VerticalAlignment ="Center"/>
        <Label Content="(リスト選択項目削除)" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan ="2" HorizontalAlignment ="Center" VerticalAlignment ="Center"/>
        <Label Content="(リスト項目全削除)" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan ="2" HorizontalAlignment ="Center" VerticalAlignment ="Center"/>
        <TextBox Name="txtName" Grid.Row="1" Grid.Column="2" TextAlignment="Center" VerticalContentAlignment="Center"/>
        <TextBox Name="txtContact" Grid.Row="1" Grid.Column="4" Grid.ColumnSpan="2" TextAlignment="Center" VerticalContentAlignment="Center"/>
    </Grid>
</Window>
  • MainWindow.xaml.cs
using System.Windows;

namespace ListView
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private ViewModel viewModel = new ViewModel();

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this.viewModel;
        }

        private void Add_Click(object sender, RoutedEventArgs e)
        {
            viewModel.AddPair(txtName.Text, txtContact.Text);
        }

        private void Remove_Click(object sender, RoutedEventArgs e)
        {
            viewModel.RemovePair(lstEntry.SelectedIndex);
        }

        private void RemoveAll_Click(object sender, RoutedEventArgs e)
        {
            viewModel.RemoveAllPair();
        }
    }
}
  • ViewModel.cs
using System.Collections.ObjectModel;

namespace ListView
{
    public class ViewModel
    {
        public ObservableCollection<Entry> Items { get { return _Items; } }
        private ObservableCollection<Entry> _Items = new ObservableCollection<Entry>();

        public void AddPair(string k, string v)
        {
            _Items.Add(new Entry(k, v));

        }

        public void RemovePair(int n)
        {
            if ( (n >= 0) && (n < Items.Count) )
            {
                _Items.RemoveAt(n);
            }
        }

        public void RemoveAllPair()
        {
            _Items.Clear();
        }
    }
}
  • Entry.cs
namespace ListView
{
    public class Entry
    {
        /// <summary>
        /// 名前
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 連絡先
        /// </summary>
        public string Contact { get; set; }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="someName"></param>
        /// <param name="someContact"></param>
        public Entry(string someName, string someContact)
        {
            this.Name = someName;
            this.Contact = someContact;
        }
    }
}

参考にしたサイト

codezine.jp

WPFでGridコントロール

Gridコントロール

Gridコントロールを使えば、コントロールの配置を簡単に決めることできます。 3行、3列のGridを作成する場合は以下のように指定します。

f:id:nprogram:20180116042646p:plain

<Window x:Class="GridBox.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:GridBox"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid ShowGridLines="True">
        <!-- 行を3つ定義 -->
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <!-- 列を3つ定義 -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
    </Grid>

以下のように、Grid.RowGrid.Columnを指定することで、Gridの意図した箇所にコントロールをセット可能です。

f:id:nprogram:20180116041054p:plain

<Window x:Class="GridBox.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:GridBox"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid ShowGridLines="True">
        <!-- 行を3つ定義 -->
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <!-- 列を3つ定義 -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Button Content="Button 0-0" Grid.Row="0" Grid.Column="0" />
        <Button Content="Button 1-0" Grid.Row="1" Grid.Column="0" />
        <Button Content="Button 2-0" Grid.Row="2" Grid.Column="0" />
        <Button Content="Button 0-1" Grid.Row="0" Grid.Column="1" />
        <Button Content="Button 1-1" Grid.Row="1" Grid.Column="1" />
        <Button Content="Button 2-1" Grid.Row="2" Grid.Column="1" />
        <Button Content="Button 0-2" Grid.Row="0" Grid.Column="2" />
        <Button Content="Button 1-2" Grid.Row="1" Grid.Column="2" />
        <Button Content="Button 2-2" Grid.Row="2" Grid.Column="2" />
    </Grid>
</Window>

以下のように、Grid.RowSpanを設定することで、何行にわたって要素を置くか設定可能です。
また、Grid.ColumnSpanを設定することで、何列にわたって要素を置くか設定可能です。

f:id:nprogram:20180116043043p:plain

<Window x:Class="GridBox.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:GridBox"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid ShowGridLines="True">
        <!-- 行を3つ定義 -->
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <!-- 列を3つ定義 -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>

        <Button Content="Button1" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2"/>
        <Button Content="Button2" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"/>
    </Grid>
</Window>