首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WPF TreeView.BringIntoView 替代方案:SelectItem 擴充方法

     編輯:關於.NET

WPF 的 TreeView.BringIntoView() 方法經常失效,無法正確捲動至指定項目。本文提供一個可靠的替代方案:透過擴充方法 SelectItem() 遞迴展開並選取目標項目。

完整程式碼

public static class TreeViewHelper {
    /// 展開 TreeView 所有子節點
    public static void ExpandAll(this TreeView treeView) {
        ExpandSubContainers(treeView);
    }

    private static void ExpandSubContainers(ItemsControl parent) {
        foreach (object item in parent.Items) {
            TreeViewItem container = parent.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (container != null && container.Items.Count > 0) {
                container.IsExpanded = true;
                if (container.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) {
                    EventHandler handler = null;
                    handler = (s, e) => {
                        if (container.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) {
                            ExpandSubContainers(container);
                            container.ItemContainerGenerator.StatusChanged -= handler;
                        }
                    };
                    container.ItemContainerGenerator.StatusChanged += handler;
                } else {
                    ExpandSubContainers(container);
                }
            }
        }
    }

    /// 搜尋並選取指定項目,自動展開父節點
    public static void SelectItem(this TreeView treeView, object item) {
        ExpandAndSelectItem(treeView, item);
    }

    private static bool ExpandAndSelectItem(ItemsControl parent, object target) {
        // 1. 檢查目前層級
        foreach (object item in parent.Items) {
            TreeViewItem container = parent.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (item == target && container != null) {
                container.IsSelected = true;
                container.BringIntoView();
                container.Focus();
                return true;
            }
        }
        // 2. 遞迴搜尋子層級
        foreach (object item in parent.Items) {
            TreeViewItem container = parent.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (container != null && container.Items.Count > 0) {
                bool wasExpanded = container.IsExpanded;
                container.IsExpanded = true;
                if (container.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) {
                    EventHandler handler = null;
                    handler = (s, e) => {
                        if (container.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) {
                            if (!ExpandAndSelectItem(container, target))
                                container.IsExpanded = wasExpanded;
                            container.ItemContainerGenerator.StatusChanged -= handler;
                        }
                    };
                    container.ItemContainerGenerator.StatusChanged += handler;
                } else {
                    if (!ExpandAndSelectItem(container, target))
                        container.IsExpanded = wasExpanded;
                    else
                        return true;
                }
            }
        }
        return false;
    }
}

使用方式

// 展開所有節點
myTreeView.ExpandAll();

// 選取特定資料項目(自動展開路徑)
myTreeView.SelectItem(targetDataItem);

核心邏輯說明

  • 虛擬化支援:透過監聽 ItemContainerGenerator.StatusChanged 事件,等待容器產生後再遞迴展開,解決 UI 虛擬化導致容器尚未建立的問題。
  • 狀態還原:若目標不在該分支,會將 IsExpanded 還原為原本狀態,避免不必要的展開。
  • 雙重搜尋:先檢查目前層級,再遞迴子層級,確保找到深層嵌套的項目。

此方案比內建 BringIntoView 更可靠,適用於資料繫結與虛擬化的 TreeView 場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved