【WPF】リファクタリングで学ぶMVVM、Prism ー はじめに


はじめに

WPF、MVVM、Prismのそれぞれの技術要素を、既に作成されたアプリケーションをリファクタリングを行いながら、体系的に学んでいければという記事となります。
リファクタリングを行ううえで最小限の項目しか扱いませんので、WPFやPrismの内容を詳細に学んでいく、とい趣旨ではないことをご了承ください。
※サンプルで用いているコンポーネントはInfragistics社のWPF製品を採用している箇所がありますので、動作をお試しいただく際にはコンポーネントのインストールが必要(Trial版あり)となります。

どんなアプリケーションをリファクタリング?

社員情報を管理するような簡単なアプリケーションを作りました。取り扱う情報としては、名前、年齢という基本的な項目のみ。

仕様

  • 左側のエリアにて、
    • 社員情報一覧を表示
    • レコードの増減は、"行追加","行削除"のボタンより実行
  • 右側のエリアに、
    • 社員情報を修正するエリア(XamPropertyGrid)が表示
    • 編集した内容は'編集内容を確定"にて実行

ソースコード

  • バインディングを一切行わらず
  • すべてイベントのみで処理し、
  • 主要な実装は MainWindow.xaml / MainWindow.xaml.cs の2ファイルのみ です。
MainWindow.xaml
<Window xmlns:igWPF="http://schemas.infragistics.com/xaml/wpf"  xmlns:ig="http://schemas.infragistics.com/xaml"  x:Class="TryRefactoring.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:TryRefactoring"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="900">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <!-- 一覧エリア -->
        <StackPanel  Grid.Column="0" Margin="10">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0" Click="addBtnClick">行追加</Button>
                <Button Grid.Column="1" Click="deleteBtnClick">行削除</Button>
            </Grid>
            <igWPF:XamDataGrid x:Name="xamDataGrid" RecordActivated="XamDataGrid_RecordActivated" Height="300">
                <igWPF:XamDataGrid.FieldSettings>
                    <igWPF:FieldSettings AllowEdit="False" />
                </igWPF:XamDataGrid.FieldSettings>
            </igWPF:XamDataGrid>
        </StackPanel>

        <!-- 編集エリア -->
        <StackPanel Grid.Column="1" Margin="10">
            <Button Click="fixBtnClick">編集内容を確定</Button>
            <ig:XamPropertyGrid  x:Name="xamPropGrid" />
        </StackPanel>

    </Grid>
</Window>

MainWindow.xaml.cs
namespace TryRefactoring
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private string JSON_FILE_PATH = "./Assets/sampledata.json";

        public MainWindow()
        {
            InitializeComponent();

            // Jsonをシリアライズ化してサンプルデータを設定
            this.xamDataGrid.DataSource = LoadJsonFile();
        }

        private List<SampleData> LoadJsonFile()
        {
            // Jsonファイルを読み込み、デシリアライズ化し、SampleDataに設定します。
            string fileContent = System.IO.File.ReadAllText(JSON_FILE_PATH);
            return JsonConvert.DeserializeObject<List<SampleData>>(fileContent);
        }

        private void addBtnClick(object sender, RoutedEventArgs e)
        {
            // 行を追加する
            List<SampleData> records = this.xamDataGrid.DataSource as List<SampleData>;
            records.Add(new SampleData());
            this.xamDataGrid.DataSource = null;
            this.xamDataGrid.DataSource = records;
        }

        private void deleteBtnClick(object sender, RoutedEventArgs e)
        {
            // 選択行を削除する。
            List<SampleData> records = this.xamDataGrid.DataSource as List<SampleData>;
            records.Remove((SampleData)this.xamDataGrid.ActiveDataItem);
            this.xamDataGrid.DataSource = null;
            this.xamDataGrid.DataSource = records;
        }


        private void fixBtnClick(object sender, RoutedEventArgs e)
        {
            SampleData editData = this.xamPropGrid.SelectedObject as SampleData;
            List<SampleData> records = this.xamDataGrid.DataSource as List<SampleData>;
            SampleData targetData = records.First(data => data.Id == editData.Id);

            // 編集内容を反映
            targetData.Age = editData.Age;
            targetData.Name = editData.Name;

            // XamDataGridに反映
            this.xamDataGrid.DataSource = null;
            this.xamDataGrid.DataSource = records;

            // データソース反映時に選択行が解除されるため、再設定
            this.xamDataGrid.SelectedDataItem = targetData;

        }

        private void XamDataGrid_RecordActivated(object sender, Infragistics.Windows.DataPresenter.Events.RecordActivatedEventArgs e)
        {
            // 選択行のオブジェクトをXamPropertyGridに表示
            xamPropGrid.SelectedObject = this.xamDataGrid.ActiveDataItem;
        }

    }
}

ファイル構成

TryRefactoring
│ MainWindow.xaml
│ MainWindow.xaml.cs
├─Assets
│ sampledata.json
├─Data
│ SampleData.cs

GitHubはこちら。
https://github.com/furugen/WPF-Try-Refactoring/tree/edition1

どうやってリファクタリングしていく?

まずは、MVVMの土台を作成し、適切なコントロールの分割化。そのあとにPrismとしての最適化を行っていきます。
各項目については、目次をご参照くださいませ。

目次(予定)

WPF標準機能 + MVVM あれこれ
1. バインディング (View)(ViewModel)(Model)
2. ViewModel,Modelの作成 (View)(ViewModel)
3. ユーザコントロールの分割 (View)(ViewModel)
4. イベントのコマンド化 (ViewModel)

Prism
5. Prism導入
6. Region
7. Module化

まとめ

次の記事から目次のメニューを消化していき、MVVM,Prism向けにリファクタリングしていきます。
まずは、ViewModelの外枠から作っていきますよー。

次の記事

【WPF】リファクタリングで学ぶMVVM、Prism。その① ~ MVVM観点で処理を切り分ける ~