sh1’s diary

プログラミング、読んだ本、資格試験、ゲームとか私を記録するところ

WPF DataGrid の列の位置・横幅を記憶する方法

こんな感じのことがやりかったので、テストで作成してみました。

f:id:shikaku_sh:20200318143905g:plain
データグリッドの列の見た目(列番号・幅)を保存します

今回の例では、ウィンドウ(MainWindow クラス)を閉じるタイミング(Closing イベント)でデータグリッドの情報を .json ファイルに保存して、ウィンドウを起動するタイミング(SourceInitialized イベント)でデータグリッドの情報を復元しています。

  • Closing イベント
  • SourceInitialized イベント

JSON データの Read/Write は、DynamicJson を利用しました。が、ライセンスがよくわからなくなっているのと、バグがあるみたいなので Microsoft 標準の「System.Text.Json」に変更しました。

f:id:shikaku_sh:20200318160119p:plain
バージョンは安定版にしました


保存する情報

保存するデータグリッドの情報は次のような形式としました。

  • Header 列を認識するための一意の名前
  • DisplayIndex 左から順番に列番号
  • Width 列の横幅
public class DataGridParameter
{
    public string Header { get; set; }
    public int DisplayIndex { get; set; }
    public double Width { get; set; }
}

f:id:shikaku_sh:20200318160235p:plain:w400
こんな感じで記録します(別になんでもいい)


取得

var columns = DataGrid.Columns.Select
(
    p => new DataGridParameter { Header = p.Header.ToString(), DisplayIndex = p.DisplayIndex, Width = p.ActualWidth }
);

Header で列の一意性を決めているけど、GitHub に公開しているほうは、添付プロパティで一意性を確保しています。GitHub のやりかたのほうが、確実だと思います。


復元

foreach (DataGridParameter param in params)
{
    var column = DataGrid.Columns.SingleOrDefault(p => p.Header.ToString() == param.Header);

    if (column != null)
    {
        column.DisplayIndex = param.DisplayIndex;
        column.Width = param.Width;
    }
}

復元は小さい DisplayIndex から順番に設定していくこと。


サンプル

GitHub の「Samples」リポジトリーにまとめて公開しています。今回のサンプルは「DataGridColumnPositionSaveSample」です。

ざっくりは以下。(Header で列の一意性を決めているけど、GitHub に公開しているほうは、添付プロパティで一意性を確保しています。GitHub のやりかたのほうが、確実だと思います。)

public static void Load(string filePath, IEnumerable<DataGridColumn> columns)
{
    var text = "";

    if (!File.Exists(filePath)) throw new IOException("指定されたファイルパスにファイルが存在しません。");

    using (var reader = new StreamReader(filePath, Encoding.UTF8))
    {
        text = reader.ReadToEnd();
    }

    if (string.IsNullOrEmpty(text)) throw new IOException("指定されたファイルのデータが空白です。");

    var jsonParams = JsonSerializer.Deserialize<IEnumerable<DataGridParameter>>(text);

    if ((jsonParams?.Count() ?? 0) <= 0) return;

    // 左端(小さい番号)から順番に設定していく
    foreach (DataGridParameter param in jsonParams.OrderBy(p => p.DisplayIndex))
    {
        var column = columns.SingleOrDefault(p => p.Header.ToString() == param.Header);

        if (column != null)
        {
            column.DisplayIndex = param.DisplayIndex;
            column.Width = param.Width;
        }
    }
}

public static void Save(string filePath, IEnumerable<DataGridColumn> columns)
{
    if (string.IsNullOrEmpty(filePath)) throw new IOException("指定されたファイルパスに異常があります。");
    if (columns == null) throw new ArgumentNullException("設定するカラムが null です。");

    var columnParams = columns.Select(p => new DataGridParameter { Header = p.Header.ToString(), DisplayIndex = p.DisplayIndex, Width = p.ActualWidth });
    var text = JsonSerializer.Serialize(columnParams);

    using (var writer = new StreamWriter(filePath, false, Encoding.UTF8))
    {
        writer.Write(text);
    }
}


参考

Effective C# 6.0/7.0

Effective C# 6.0/7.0

Effective C# 4.0

Effective C# 4.0

Effective C#

Effective C#