UltraTree にはノードの選択履歴を残す機能がありません。今回はノードの選択履歴を残し、Ctrl + Z で選択履歴をさかのぼる機能を実装したいと思います。

概要

UltraTree コントロールを使用し、ツリー構造上でのノード選択履歴を管理・操作する機能をご紹介します。
主な機能としては、ユーザーがツリー内のノードを選択するたびにその履歴をスタックに保存し、Ctrl+Z キー操作により直前の選択状態に「戻る」ことが可能になっています。

実装機能について

ツリー構造の構築

  • ノードの階層構造
    • ルートノード「Top」を作成し、その下に「Fruits」や「Meat」などのカテゴリノードを追加。
    • 各カテゴリ内で、さらに子ノード(例:「A」「B」「C」などのグループ、及びそれらの中に「Apple」「Orange」などのアイテム)が設定されています。
  • 全ノードの展開
    • ExpandAll() メソッドにより、ツリー全体が展開された状態で表示されます。

選択履歴の管理

  • 履歴用スタック
    • Stack<UltraTreeNode> 型の selectionHistory を用いて、ユーザーのノード選択履歴を保持。
    • 初期状態では「Top」ノードを履歴に追加。
  • ノード選択時のイベント処理
    • AfterSelect イベントハンドラ内で、通常の選択操作が行われた場合に新たな選択ノードを履歴に追加。
    • 履歴操作(Undo)中には、履歴の更新を防ぐために isUndoing フラグを活用。

「Undo」機能(Ctrl+Z 操作)

  • キー操作の検出
    • KeyDownイベントハンドラで、Ctrl + Z キーが押されたかをチェック。
  • 履歴を用いた選択状態の復元
    • 履歴スタックに複数のノードが存在する場合、現在の選択ノードを一旦スタックから取り除き、直前のノードを再選択。
    • 再選択の際、 AfterSelect イベントで再び履歴に追加されないよう、isUndoing フラグを一時的に true に設定。
  • ListBox への反映
    • UpdateHistoryListBox メソッドで、スタックの内容を逆順(古い順)に ListBox に表示。これにより、ユーザーは履歴の流れを視覚的に確認できるようになります。

サンプルコード

public partial class Form1 : Form
{
    // 選択履歴を保持するスタック
    private Stack<UltraTreeNode> selectionHistory = new Stack<UltraTreeNode>();
    // 履歴操作中かどうかを示すフラグ(イベントループ防止用)
    private bool isUndoing = false;

    public Form1()
    {
        InitializeComponent();
        InitializeUltraTree();
    }

    private void Form1_Load(object sender, EventArgs e)
    {}

    private void InitializeUltraTree()
    {
        // ツリーデータの作成
        // ルートノード: Top
        UltraTreeNode topNode = ultraTree1.Nodes.Add("Top", "Top");

        // フルーツ
        UltraTreeNode fruitsNode = topNode.Nodes.Add("Fruits", "フルーツ");
        // A
        UltraTreeNode aNode = fruitsNode.Nodes.Add("A", "A");
        aNode.Nodes.Add("Apple", "りんご");
        aNode.Nodes.Add("Orange", "みかん");
        // B
        UltraTreeNode bNode = fruitsNode.Nodes.Add("B", "B");
        bNode.Nodes.Add("Pear", "なし");
        bNode.Nodes.Add("Grape", "ぶどう");
        bNode.Nodes.Add("Banana", "ばなな");
        // C
        UltraTreeNode cNode = fruitsNode.Nodes.Add("C", "C");
        cNode.Nodes.Add("Peach", "もも");

        // 肉
        UltraTreeNode meatNode = topNode.Nodes.Add("Meat", "肉");
        // D
        UltraTreeNode dNode = meatNode.Nodes.Add("D", "D");
        dNode.Nodes.Add("Pork", "豚");
        dNode.Nodes.Add("Beef", "牛");

        // 全ノードを展開して表示
        ultraTree1.ExpandAll();

        // 初期選択(Top ノード)を履歴に追加
        topNode.Selected = true;
        UpdateHistoryListBox();

    }

    // Ctrl+Z キー操作により直前のノードに戻るイベントハンドラ
    private void ultraTree1_KeyDown(object sender, KeyEventArgs e)
    {
        // Ctrl + Z が押された場合の処理
        if (e.Control && e.KeyCode == Keys.Z)
        {
            // 履歴に複数のノードがある場合のみ戻る
            if (selectionHistory.Count > 1)
            {
                // 履歴戻し操作中であることを示すフラグを true に設定
                isUndoing = true;

                // 現在選択されているノードを履歴から取り除く(現在の状態を一旦破棄)
                selectionHistory.Pop();

                // 履歴のトップにある直前のノードを取得する
                UltraTreeNode previousNode = selectionHistory.Peek();

                // 直前のノードを再び選択状態にする
                // ※この際、AfterSelect イベントで履歴に再度追加されないように isUndoing フラグが true になっている
                previousNode.Selected = true;

                // 選択履歴の内容を ListBox に反映させるため、ListBox を更新する
                UpdateHistoryListBox();

                // 履歴戻し操作が完了したので、フラグを false に戻す
                isUndoing = false;
                
            }
        }
    }

    /// UltraTree のノード選択後に呼び出されるイベントハンドラです。

    /// このメソッドは、選択操作が履歴戻し操作中ではない場合に、
    /// 現在選択されているノード(SelectedNodes[0])を選択履歴のスタックに追加し、
    /// ListBox に履歴内容を反映させるための更新処理を行います。
    /// 選択されているノードが1つだけの場合に処理を実施します。
    private void ultraTree1_AfterSelect(object sender, SelectEventArgs e)
    {
        // isUndoing が false(つまり、履歴戻し操作中ではない)かつ
        // 選択されているノードが1つだけの場合に処理を実行する
        if (!isUndoing && ultraTree1.SelectedNodes.Count == 1)
        {
            // 現在選択されているノード(SelectedNodes[0])を選択履歴のスタックに追加する
            selectionHistory.Push(ultraTree1.SelectedNodes[0]);
            // 選択履歴の内容を ListBox に反映させるため、ListBox を更新する
            UpdateHistoryListBox();
        }
    }

    /// selectionHistory の内容を ListBox に表示する
    private void UpdateHistoryListBox()
    {
        listBox1.Items.Clear();
        foreach (var node in selectionHistory.Reverse())
        {
            listBox1.Items.Add(node.Text);
        }
    }
}

実行イメージ

サンプルコード

Tagged:

製品について

Ultimate UI for Windows Forms