2012/2/29

(WPF) 在 WPF 視窗中找到所有控制項

在 WPF 視窗裡, 控制項模型和 Windows Form 或 Web Form 之間都有或大或小的差異。就以巡覽控制項這件事來說吧, 你可能會和我一樣, 對於容器(包括視窗本身)都沒有提供 Controls 或 Items 屬性可用而深感不方便。它甚至也不提供像 XML 和 LINQ to XML 之下的各種巡覽功能, 像是 Descendants 屬性。

我最近打算在我的 WPF 程式中把某個 StackPanel 裡面的所有 TextBox 一次 Disable 或 Enable。在我最熟悉的 ASP.NET 中, 這是很簡單的一件事。如果是客戶端程式的話, 我甚至可以使用 jQuery 來輕鬆的辦到。很可惜, 在 WPF 程式中., 似乎並沒有提供現成的類似功能。

山不轉人轉。首先, 我發現像 StackPanel 或 WrapPanel 這類容器都有 Children 屬性, 可以將底下的所有子控制項條列為 UIElement 類別的物件。UIElement 是 WPF 中獨有的基底類別 (Control 和 Panel 均繼承自 FrameworkElement, 而 FrameworkElement 繼承自 UIElement)。其用法如下:

foreach (UIElement child in WrapPanel1.Children)
{
   ...
}

很可惜, 雖然我們可以使用這個方法條列出容器之下的各控制項, 我們只能得到第一層(如同 XML 中的 Nodes)。如果這個容器之內還有容器, 我們就得想想其它辦法。

幸好, 我發現 WPF 中各種容器, 包括 WrapPanel, StackPanel 等等, 都繼承自 Panel 這個基底類別。所以只要簡的轉型, 就可以使用遞迴的做法巡覽及條列各種不同容器裡面的所有控制項, 而不會只限於第一層了。

以下, 假設我要把某個 WrapPanel 裡的所有 TextBox 控制項一次全部 Disable 或 Enable, 方法可以這樣寫:

void disableAllTextBoxes(object control)
{
    if (control is TextBox)
        ((TextBox)control).IsEnabled = false;
    else
        if (control is Panel)
            foreach (UIElement child in ((Panel)control).Children)
                disableAllTextBoxes(child);
}

void enableAllTextBoxes(object control)
{
    if (control is TextBox)
        ((TextBox)control).IsEnabled = true;
    else
        if (control is Panel)
            foreach (UIElement child in ((Panel)control).Children)
                enableAllTextBoxes(child);
}

如果你的 WrapPanel 的 Name 是 wpEdit  的話, 以下這道指令即可把其它所有 TextBox 全部變成 disabled:

disableAllTextBoxes(wpEdit);

你也可以把 WPF 最外層的那個 Grid 當作參數(當然, 你得先給它取個名字), 然後你就可以針對整個視窗裡的物件動作了。

 

沒有留言:

張貼留言