グリッドの行の背景色を変更したい[Mac][C#][Xamarin][Uno Platform]

特定の条件を満たす行は、黄緑にしたい。
かつ、選択したら青くしたい。
だから、特定の条件を満たし、かつ、選択したら混ぜた色にしたい。
面倒くさいなぁ。

背景色を変えるだけなら単純。

NSTableViewオブジェクト.GetRowView(変更したい行, true).BackgroundColor = NSColor.FromRGB(R値, G値, B値);

さらに、選択行を変更したら、

  • 選択を解除した行の色を元に戻す
  • 選択した行の色に青味を足す

をしなきゃいけない。

これに加えて、選択した行が見えなくなるまでグリッドをスクロールし、戻ってくると、選択色が解除される問題にも取り掛かる。
どうやらスクロールして戻ってくると、NSTableViewオブジェクト.DelegateのGetViewForItem関数が実行され、そのときに背景色を変に初期化しちゃうと元に戻っちゃう……ぽい?

そんなわけで、NSTableViewオブジェクト.Delegateに割り当てるDelegateクラスを実装する。

public class MyDelegate : NSTableViewDelegate
{
    // 使う色を定義しておく
    private static readonly NSColor BaseColor = NSColor.FromRgb(背景色のRGB値);
    private static readonly NSColor HitColor = NSColor.FromRgb(144, 238, 144);         // 黄緑
    private static readonly NSColor SelectColor = NSColor.FromRgb(98, 167, 222);       // 青
    private static readonly NSColor HitAndSelectColor = NSColor.FromRgb(58, 167, 185); // 混ぜた色

    // 選択した行を覚えておく
    private int SelectedRow { get; set; } = -1;

    // テーブルの列定義辞書
    public new Dictionary<string, funcDelegate> TableColumnsDict = new Dictionary<string, funcDelegate>()
    {
        //{"DisplayName", "" },
    };

    /// <summary>
    /// テーブル列の値設定用デリゲート
    /// </summary>
    /// <param name="rowView">設定先の行コントロール</param>
    /// <param name="obj">設定先セルのテキストコントロール</param>
    /// <param name="row">何行目か</param>
    /// <param name="isSelectRow">選択された行か</param>
    public delegate void funcDelegate(NSTableRowView rowView, NSObject obj, nint row, bool isSelectRow);

    /// <summary>
    /// 行選択イベント
    /// </summary>
    /// <param name="tableView">選択変更前のテーブル</param>
    /// <param name="row">選択行</param>
    /// <returns>行変更を許可するならtrue</returns>
    public override bool ShouldSelectRow(NSTableView tableView, nint row)
    {
        // 行の色変更
        // ここで変更しないとクリック時に色が変わらない
        SetBackColor(tableView, (int)tableView.SelectedRow, this.SelectedRow);

        return true;
    }

    /// <summary>
    /// テーブルの背景色の設定
    /// </summary>
    /// <param name="table">テーブル</param>
    /// <param name="preRow">選択が外れる行</param>
    /// <param name="selectRow">選択行</param>
    protected virtual void SetBackColor(NSTableView table, int preRow, int selectRow)
    {
        // 選択が外れる行の背景色を設定
        if (0 <= preRow)
        {
            table.GetRowView(preRow, true).BackgroundColor = 特定の条件 ? HitColor : BaseColor;
        }

        // 選択した行の背景色を選択
        if (0 <= selectRow)
        {
            table.GetRowView(selectRow, true).BackgroundColor = 特定の条件 ? HitAndSelectColor : SelectColor;
        }
    }

    /// <summary>
    /// テーブルの各列の値設定用デリゲートを実行する
    /// </summary>
    /// <param name="tableView">テーブル</param>
    /// <param name="tableColumn">カラム</param>
    /// <param name="row">何行目か</param>
    /// <returns></returns>
    public override NSView GetViewForItem(NSTableView tableView, NSTableColumn tableColumn, nint row)
    {
        NSTextField view = (NSTextField)tableView.MakeView("Cell", this);
        if (view == null)
        {
            view = new NSTextField();
            view.Identifier = "Cell";
            // ひとまず透過で初期化
            view.BackgroundColor = NSColor.Clear;
        }

        if (TableColumnsDict.ContainsKey(tableColumn.Identifier))
        {
            TableColumnsDict[tableColumn.Identifier](tableView.GetRowView(row, true), view, row, row == this.SelectedRow);
        }

        return view;
    }

    /// <summary>
    /// テーブル列の値設定用デリゲート
    /// </summary>
    /// <param name="rowView">設定先の行コントロール</param>
    /// <param name="obj">設定先セルのテキストコントロール</param>
    /// <param name="row">何行目か</param>
    /// <param name="isSelectRow">選択された行か</param>
    public static void FuncSetColumn(NSTableRowView rowView, NSObject obj, nint row, bool isSelectRow)
    {
        // 値を設定したり、文字色変えたり

        // 行全体の色を設定
        // ここで色を設定しないとスクロールしたときに戻ってしまう
        rowView.BackgroundColor = isSelectRow ? SelectColor : BaseColor;
        if(特定の条件)
        {
            rowView.BackgroundColor = isSelectRow ? HitAndSelectColor : HitColor;
        }
    }
}

んで、テーブルを作るときに上のDelegateを登録しておきましょう。
面倒なので、ここでは「名前」の1列しかないテーブルと仮定します。

NSTableViewオブジェクト.AddColumn(new NSTableColumn("名前"));
var delg = new MyDelegate();
delg.TableColumnsDict.Add("名前", MyDelegate.FuncSetColumn);
NSTableViewオブジェクト.Delegate = delg;

ただ、Columnを設定する度に1行まるっと色を染めているのは、列が増えると効率が悪い気がするなぁ。
もっとうまい方法はありそう。
CoreGetRowViewとかでやった方がいいのかなぁー


他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。

返信を残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)