Làm cách nào tôi có thể tìm thấy các điều khiển WPF theo tên hoặc loại?


264

Tôi cần tìm kiếm một hệ thống phân cấp điều khiển WPF cho các điều khiển khớp với tên hoặc loại đã cho. Tôi có thể làm cái này như thế nào?

Câu trả lời:


311

Tôi đã kết hợp định dạng mẫu được sử dụng bởi thuật toán của John Myczek và Tri Q ở trên để tạo ra Thuật toán findChild có thể được sử dụng cho bất kỳ phụ huynh nào. Hãy nhớ rằng việc tìm kiếm đệ quy một cây ở phía dưới có thể là một quá trình dài. Tôi chỉ kiểm tra tại chỗ trên ứng dụng WPF, vui lòng nhận xét về bất kỳ lỗi nào bạn có thể tìm thấy và tôi sẽ sửa mã của mình.

WPF Snoop là một công cụ hữu ích trong việc xem xét cây trực quan - tôi thực sự khuyên bạn nên sử dụng nó trong khi thử nghiệm hoặc sử dụng thuật toán này để kiểm tra công việc của bạn.

Có một lỗi nhỏ trong Thuật toán Tri Q. Sau khi tìm thấy đứa trẻ, nếu childrenCount> 1 và chúng ta lặp lại một lần nữa, chúng ta có thể ghi đè lên đứa trẻ được tìm thấy đúng. Vì vậy, tôi đã thêm một if (foundChild != null) break;mã vào mã của tôi để đối phó với điều kiện này.

/// <summary>
/// Finds a Child of a given item in the visual tree. 
/// </summary>
/// <param name="parent">A direct parent of the queried item.</param>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="childName">x:Name or Name of child. </param>
/// <returns>The first parent item that matches the submitted type parameter. 
/// If not matching item can be found, 
/// a null parent is being returned.</returns>
public static T FindChild<T>(DependencyObject parent, string childName)
   where T : DependencyObject
{    
  // Confirm parent and childName are valid. 
  if (parent == null) return null;

  T foundChild = null;

  int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
  for (int i = 0; i < childrenCount; i++)
  {
    var child = VisualTreeHelper.GetChild(parent, i);
    // If the child is not of the request child type child
    T childType = child as T;
    if (childType == null)
    {
      // recursively drill down the tree
      foundChild = FindChild<T>(child, childName);

      // If the child is found, break so we do not overwrite the found child. 
      if (foundChild != null) break;
    }
    else if (!string.IsNullOrEmpty(childName))
    {
      var frameworkElement = child as FrameworkElement;
      // If the child's name is set for search
      if (frameworkElement != null && frameworkElement.Name == childName)
      {
        // if the child's name is of the request name
        foundChild = (T)child;
        break;
      }
    }
    else
    {
      // child element found.
      foundChild = (T)child;
      break;
    }
  }

  return foundChild;
}

Gọi nó như thế này:

TextBox foundTextBox = 
   UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "myTextBoxName");

Lưu ý Application.Current.MainWindowcó thể là bất kỳ cửa sổ cha mẹ.


@CrimsonX: Có lẽ tôi đang làm sai điều này ... Tôi có một nhu cầu tương tự khi tôi cần đến một điều khiển (ListBox) bên trong ContentControl (Expander). Mã trên không hoạt động với tôi như vậy .. Tôi đã phải cập nhật mã ở trên để xem nút nút (GetChildrenCount => 0) có phải là ContentControl không. Nếu có, hãy kiểm tra xem nội dung có khớp với tiêu chí tên + loại không.
Gishu

@Gishu - Tôi nghĩ nó nên hoạt động cho mục đích này. Bạn có thể sao chép và dán mã của mình để hiển thị cách bạn đang sử dụng cuộc gọi không? Tôi hy vọng nó sẽ là FindChild <ListBox> (Mở rộng myExpanderName, "myListBoxName").
CrimsonX

3
@CrimsonX Tôi nghĩ rằng tôi đã tìm thấy một trường hợp góc khác. Tôi đã cố gắng tìm PART_SubmenuPlaceholder trong RibbonApplicationMothyItem, nhưng đoạn mã trên không hoạt động. Để giải quyết nó, tôi cần thêm vào như sau: if (name == ElementName) other {FoundChild = FindChild (con, tên) if (FoundChild! = Null) break; }
kevindaub

6
Xin hãy cẩn thận, có một lỗi hoặc nhiều hơn trong câu trả lời. Nó sẽ dừng lại ngay khi nó đến được một đứa trẻ thuộc loại được tìm kiếm. Tôi nghĩ bạn nên xem xét / ưu tiên các câu trả lời khác.
Eric Ouellet

2
Mã này rất tuyệt, nhưng nó sẽ không hoạt động nếu bạn không tìm kiếm một loại phần tử cụ thể, ví dụ nếu bạn vượt qua FrameworkElementT, nó sẽ trả về null ngay khi vòng lặp đầu tiên kết thúc. Vì vậy, bạn sẽ cần phải làm một số sửa đổi.
Amir Oveisi

131

Bạn cũng có thể tìm thấy một phần tử theo tên bằng cách sử dụng FrameworkEuity.FindName (chuỗi) .

Được:

<UserControl ...>
    <TextBlock x:Name="myTextBlock" />
</UserControl>

Trong tệp mã phía sau, bạn có thể viết:

var myTextBlock = (TextBlock)this.FindName("myTextBlock");

Tất nhiên, vì được xác định bằng x: Name, bạn chỉ có thể tham chiếu trường được tạo, nhưng có lẽ bạn muốn tìm kiếm nó một cách linh hoạt hơn là tĩnh.

Cách tiếp cận này cũng có sẵn cho các mẫu, trong đó mục được đặt tên xuất hiện nhiều lần (một lần cho mỗi lần sử dụng mẫu).


6
Để làm việc này, bạn không nhất thiết phải thêm "x:" vào thuộc tính name.
brian buck

3
Điều này dường như không luôn luôn hoạt động. Tôi có UserControls được kết hợp với nhau theo chương trình trong các lưới lồng nhau như nội dung của một cửa sổ thuộc tính. Câu trả lời của CrimsonX hoạt động tốt tuy nhiên.
Matt

4
Điều này sẽ không hoạt động đối với các thành phần trong ItemControls, ListBoxes, v.v.
Sorensen

67

Bạn có thể sử dụng VisualTreeHelper để tìm các điều khiển. Dưới đây là phương pháp sử dụng VisualTreeHelper để tìm điều khiển chính của một loại được chỉ định. Bạn cũng có thể sử dụng VisualTreeHelper để tìm các điều khiển theo những cách khác.

public static class UIHelper
{
   /// <summary>
   /// Finds a parent of a given item on the visual tree.
   /// </summary>
   /// <typeparam name="T">The type of the queried item.</typeparam>
   /// <param name="child">A direct or indirect child of the queried item.</param>
   /// <returns>The first parent item that matches the submitted type parameter. 
   /// If not matching item can be found, a null reference is being returned.</returns>
   public static T FindVisualParent<T>(DependencyObject child)
     where T : DependencyObject
   {
      // get parent item
      DependencyObject parentObject = VisualTreeHelper.GetParent(child);

      // we’ve reached the end of the tree
      if (parentObject == null) return null;

      // check if the parent matches the type we’re looking for
      T parent = parentObject as T;
      if (parent != null)
      {
         return parent;
      }
      else
      {
         // use recursion to proceed with next level
         return FindVisualParent<T>(parentObject);
      }
   }
}

Gọi nó như thế này:

Window owner = UIHelper.FindVisualParent<Window>(myControl);

Làm thế nào để bạn nhận được hoặc myControl là gì?
Giải điều chế

21

Tôi có thể chỉ đang lặp lại những người khác nhưng tôi có một đoạn mã đẹp mở rộng lớp DependencyObject bằng phương thức FindChild () sẽ đưa bạn đứa trẻ theo loại và tên. Chỉ cần bao gồm và sử dụng.

public static class UIChildFinder
{
    public static DependencyObject FindChild(this DependencyObject reference, string childName, Type childType)
    {
        DependencyObject foundChild = null;
        if (reference != null)
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(reference);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(reference, i);
                // If the child is not of the request child type child
                if (child.GetType() != childType)
                {
                    // recursively drill down the tree
                    foundChild = FindChild(child, childName, childType);
                }
                else if (!string.IsNullOrEmpty(childName))
                {
                    var frameworkElement = child as FrameworkElement;
                    // If the child's name is set for search
                    if (frameworkElement != null && frameworkElement.Name == childName)
                    {
                        // if the child's name is of the request name
                        foundChild = child;
                        break;
                    }
                }
                else
                {
                    // child element found.
                    foundChild = child;
                    break;
                }
            }
        }
        return foundChild;
    }
}

Hi vọng bạn tìm được thứ hữu dụng.


2
Theo bài đăng của tôi ở trên, có một lỗi triển khai nhỏ trong mã của bạn: stackoverflow.com/questions/636383/wpf-ways-to-find-controls/
Lỗi

18

Phần mở rộng của tôi để mã.

  • Đã thêm quá tải để tìm một con theo loại, theo loại và tiêu chí (vị ngữ), tìm tất cả các loại con đáp ứng các tiêu chí
  • phương thức FindChildren là một trình vòng lặp ngoài việc là một phương thức mở rộng cho DependencyObject
  • FindChildren đi bộ cây con logic. Xem bài viết của Josh Smith được liên kết trong bài viết trên blog.

Nguồn: https://code.google.com.vn/p/gishu-util/source/browse/#git%2FWPF%2FUtilities

Bài đăng trên blog giải thích: http://madcoderspeak.blogspot.com/2010/04/wpf-find-child-control-of-specific-type.html


-1 Chính xác những gì tôi sắp thực hiện (vị ngữ, trình lặp và phương thức mở rộng), nhưng có 404 trên liên kết nguồn. Sẽ thay đổi thành +1 nếu mã được bao gồm ở đây hoặc liên kết nguồn được sửa!
cod3monk3y

@ cod3monk3y - Git di cư thiệt mạng liên kết có vẻ như :) Ở đây bạn đi .. code.google.com/p/gishu-util/source/browse/...
Gishu

18

Nếu bạn muốn tìm TẤT CẢ các điều khiển của một loại cụ thể, bạn cũng có thể quan tâm đến đoạn trích này

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject parent) 
        where T : DependencyObject
    {
        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);

            var childType = child as T;
            if (childType != null)
            {
                yield return (T)child;
            }

            foreach (var other in FindVisualChildren<T>(child))
            {
                yield return other;
            }
        }
    }

3
Tốt một nhưng đảm bảo kiểm soát được tải nếu không GetChildrenCount sẽ trả về 0.
Klaus Nji

@UrbanEsc, tại sao bạn lại chọn childlần thứ hai? Nếu bạn có childTypeloại T, bạn có thể viết bên trong if: yield return childType... không?
Massimiliano Kraus

@MassimilianoKraus Này, xin lỗi vì phản hồi muộn, nhưng bạn đã đúng. Tôi gán nó cho tôi viết lại đoạn trích này nhiều lần và do đó đây có thể là một đoạn của một kiểm tra khác
UrbanEsc

16

Điều này sẽ loại bỏ một số yếu tố - bạn nên mở rộng nó như thế này để hỗ trợ một loạt các điều khiển rộng hơn. Đối với một cuộc thảo luận ngắn gọn, hãy xem ở đây

 /// <summary>
 /// Helper methods for UI-related tasks.
 /// </summary>
 public static class UIHelper
 {
   /// <summary>
   /// Finds a parent of a given item on the visual tree.
   /// </summary>
   /// <typeparam name="T">The type of the queried item.</typeparam>
   /// <param name="child">A direct or indirect child of the
   /// queried item.</param>
   /// <returns>The first parent item that matches the submitted
   /// type parameter. If not matching item can be found, a null
   /// reference is being returned.</returns>
   public static T TryFindParent<T>(DependencyObject child)
     where T : DependencyObject
   {
     //get parent item
     DependencyObject parentObject = GetParentObject(child);

     //we've reached the end of the tree
     if (parentObject == null) return null;

     //check if the parent matches the type we're looking for
     T parent = parentObject as T;
     if (parent != null)
     {
       return parent;
     }
     else
     {
       //use recursion to proceed with next level
       return TryFindParent<T>(parentObject);
     }
   }

   /// <summary>
   /// This method is an alternative to WPF's
   /// <see cref="VisualTreeHelper.GetParent"/> method, which also
   /// supports content elements. Do note, that for content element,
   /// this method falls back to the logical tree of the element!
   /// </summary>
   /// <param name="child">The item to be processed.</param>
   /// <returns>The submitted item's parent, if available. Otherwise
   /// null.</returns>
   public static DependencyObject GetParentObject(DependencyObject child)
   {
     if (child == null) return null;
     ContentElement contentElement = child as ContentElement;

     if (contentElement != null)
     {
       DependencyObject parent = ContentOperations.GetParent(contentElement);
       if (parent != null) return parent;

       FrameworkContentElement fce = contentElement as FrameworkContentElement;
       return fce != null ? fce.Parent : null;
     }

     //if it's not a ContentElement, rely on VisualTreeHelper
     return VisualTreeHelper.GetParent(child);
   }
}

5
Theo quy ước, tôi sẽ mong đợi bất kỳ Try*phương thức nào trả về boolvà có một outtham số trả về loại được đề cập, như với:bool IDictionary.TryGetValue(TKey key, out TValue value)
Drew Noakes

@DrewKhông làm gì bạn đề nghị Philipp gọi nó, sau đó? Ngoài ra, ngay cả với kỳ vọng như vậy, tôi thấy mã của anh ta rõ ràng và rõ ràng để sử dụng.
ANeves

1
@ANeves, trong trường hợp này tôi sẽ chỉ gọi nó FindParent. Tên này với tôi ngụ ý rằng nó có thể trở lại null. Các Try*tiền tố được sử dụng trong suốt BCL trong cách tôi mô tả ở trên. Cũng lưu ý rằng hầu hết các câu trả lời khác ở đây sử dụng Find*quy ước đặt tên. Tuy nhiên, đó chỉ là một điểm nhỏ :)
Drew Noakes

16

Tôi đã chỉnh sửa mã của CrimsonX vì nó không hoạt động với các loại siêu lớp:

public static T FindChild<T>(DependencyObject depObj, string childName)
   where T : DependencyObject
{
    // Confirm obj is valid. 
    if (depObj == null) return null;

    // success case
    if (depObj is T && ((FrameworkElement)depObj).Name == childName)
        return depObj as T;

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(depObj, i);

        //DFS
        T obj = FindChild<T>(child, childName);

        if (obj != null)
            return obj;
    }

    return null;
}

1
Nếu bạn vượt qua phương pháp này DependencyObject, nó không phải là FrameworkElementngoại lệ. Cũng sử dụng GetChildrenCounttrên mỗi lần lặp của forvòng lặp nghe có vẻ là một ý tưởng tồi.
Tim Pohlmann

1
tốt, đây là từ 5 năm trước, vì vậy tôi thậm chí không biết nó có hoạt động nữa không :)
andresp

Tôi chỉ đề cập đến nó, bởi vì tôi tình cờ phát hiện ra nó và những thứ khác cũng có thể;)
Tim Pohlmann

13

Mặc dù tôi thích đệ quy nói chung, nhưng nó không hiệu quả như lặp lại khi lập trình trong C #, vậy có lẽ giải pháp nào sau đây gọn gàng hơn so với đề xuất của John Myczek? Điều này tìm kiếm một hệ thống phân cấp từ một điều khiển nhất định để tìm một điều khiển tổ tiên của một loại cụ thể.

public static T FindVisualAncestorOfType<T>(this DependencyObject Elt)
    where T : DependencyObject
{
    for (DependencyObject parent = VisualTreeHelper.GetParent(Elt);
        parent != null; parent = VisualTreeHelper.GetParent(parent))
    {
        T result = parent as T;
        if (result != null)
            return result;
    }
    return null;
}

Gọi nó như thế này để tìm Windowmột điều khiển có chứa ExampleTextBox:

Window window = ExampleTextBox.FindVisualAncestorOfType<Window>();

9

Đây là mã của tôi để tìm các điều khiển theo Loại trong khi kiểm soát mức độ chúng ta đi sâu vào cấu trúc phân cấp (maxDepth == 0 có nghĩa là sâu vô hạn).

public static class FrameworkElementExtension
{
    public static object[] FindControls(
        this FrameworkElement f, Type childType, int maxDepth)
    {
        return RecursiveFindControls(f, childType, 1, maxDepth);
    }

    private static object[] RecursiveFindControls(
        object o, Type childType, int depth, int maxDepth = 0)
    {
        List<object> list = new List<object>();
        var attrs = o.GetType()
            .GetCustomAttributes(typeof(ContentPropertyAttribute), true);
        if (attrs != null && attrs.Length > 0)
        {
            string childrenProperty = (attrs[0] as ContentPropertyAttribute).Name;
            foreach (var c in (IEnumerable)o.GetType()
                .GetProperty(childrenProperty).GetValue(o, null))
            {
                if (c.GetType().FullName == childType.FullName)
                    list.Add(c);
                if (maxDepth == 0 || depth < maxDepth)
                    list.AddRange(RecursiveFindControls(
                        c, childType, depth + 1, maxDepth));
            }
        }
        return list.ToArray();
    }
}

9

exciton80 ... Tôi gặp vấn đề với mã của bạn không được đệ quy thông qua các điều khiển người dùng. Nó đã nhấn vào gốc Grid và gây ra lỗi. Tôi tin rằng điều này sửa nó cho tôi:

public static object[] FindControls(this FrameworkElement f, Type childType, int maxDepth)
{
    return RecursiveFindControls(f, childType, 1, maxDepth);
}

private static object[] RecursiveFindControls(object o, Type childType, int depth, int maxDepth = 0)
{
    List<object> list = new List<object>();
    var attrs = o.GetType().GetCustomAttributes(typeof(ContentPropertyAttribute), true);
    if (attrs != null && attrs.Length > 0)
    {
        string childrenProperty = (attrs[0] as ContentPropertyAttribute).Name;
        if (String.Equals(childrenProperty, "Content") || String.Equals(childrenProperty, "Children"))
        {
            var collection = o.GetType().GetProperty(childrenProperty).GetValue(o, null);
            if (collection is System.Windows.Controls.UIElementCollection) // snelson 6/6/11
            {
                foreach (var c in (IEnumerable)collection)
                {
                    if (c.GetType().FullName == childType.FullName)
                        list.Add(c);
                    if (maxDepth == 0 || depth < maxDepth)
                        list.AddRange(RecursiveFindControls(
                            c, childType, depth + 1, maxDepth));
                }
            }
            else if (collection != null && collection.GetType().BaseType.Name == "Panel") // snelson 6/6/11; added because was skipping control (e.g., System.Windows.Controls.Grid)
            {
                if (maxDepth == 0 || depth < maxDepth)
                    list.AddRange(RecursiveFindControls(
                        collection, childType, depth + 1, maxDepth));
            }
        }
    }
    return list.ToArray();
}

8

Tôi có một hàm chuỗi như thế này (hoàn toàn chung):

    public static IEnumerable<T> SelectAllRecursively<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> func)
    {
        return (items ?? Enumerable.Empty<T>()).SelectMany(o => new[] { o }.Concat(SelectAllRecursively(func(o), func)));
    }

Bắt con ngay lập tức:

    public static IEnumerable<DependencyObject> FindChildren(this DependencyObject obj)
    {
        return Enumerable.Range(0, VisualTreeHelper.GetChildrenCount(obj))
            .Select(i => VisualTreeHelper.GetChild(obj, i));
    }

Tìm tất cả trẻ em xuống cây hiararchical:

    public static IEnumerable<DependencyObject> FindAllChildren(this DependencyObject obj)
    {
        return obj.FindChildren().SelectAllRecursively(o => o.FindChildren());
    }

Bạn có thể gọi nó trên Cửa sổ để có được tất cả các điều khiển.

Sau khi bạn có bộ sưu tập, bạn có thể sử dụng LINQ (ví dụ OfType, Where).


6

Vì câu hỏi đủ chung chung để nó có thể thu hút những người tìm kiếm câu trả lời cho những trường hợp rất tầm thường: nếu bạn chỉ muốn có một đứa trẻ chứ không phải là một hậu duệ, bạn có thể sử dụng Linq:

private void ItemsControlItem_Loaded(object sender, RoutedEventArgs e)
{
    if (SomeCondition())
    {
        var children = (sender as Panel).Children;
        var child = (from Control child in children
                 where child.Name == "NameTextBox"
                 select child).First();
        child.Focus();
    }
}

hoặc tất nhiên là rõ ràng cho vòng lặp lặp trên trẻ em.


3

Các tùy chọn này đã nói về việc duyệt qua Visual Tree trong C #. Cũng có thể duyệt qua cây trực quan trong xaml bằng cách sử dụng phần mở rộng đánh dấu RelativeSource.msd

tìm theo loại

Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type <TypeToFind>}}}" 

2

Đây là một giải pháp sử dụng một vị từ linh hoạt:

public static DependencyObject FindChild(DependencyObject parent, Func<DependencyObject, bool> predicate)
{
    if (parent == null) return null;

    int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < childrenCount; i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);

        if (predicate(child))
        {
            return child;
        }
        else
        {
            var foundChild = FindChild(child, predicate);
            if (foundChild != null)
                return foundChild;
        }
    }

    return null;
}

Ví dụ, bạn có thể gọi nó như thế này:

var child = FindChild(parent, child =>
{
    var textBlock = child as TextBlock;
    if (textBlock != null && textBlock.Name == "MyTextBlock")
        return true;
    else
        return false;
}) as TextBlock;

1

Mã này chỉ sửa lỗi của câu trả lời @CrimsonX:

 public static T FindChild<T>(DependencyObject parent, string childName)
       where T : DependencyObject
    {    
      // Confirm parent and childName are valid. 
      if (parent == null) return null;

      T foundChild = null;

      int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
      for (int i = 0; i < childrenCount; i++)
      {
        var child = VisualTreeHelper.GetChild(parent, i);
        // If the child is not of the request child type child
        T childType = child as T;
        if (childType == null)
        {
          // recursively drill down the tree
          foundChild = FindChild<T>(child, childName);

          // If the child is found, break so we do not overwrite the found child. 
          if (foundChild != null) break;
        }
        else if (!string.IsNullOrEmpty(childName))
        {
          var frameworkElement = child as FrameworkElement;
          // If the child's name is set for search
          if (frameworkElement != null && frameworkElement.Name == childName)
          {
            // if the child's name is of the request name
            foundChild = (T)child;
            break;
          }

 // recursively drill down the tree
          foundChild = FindChild<T>(child, childName);

          // If the child is found, break so we do not overwrite the found child. 
          if (foundChild != null) break;


        else
        {
          // child element found.
          foundChild = (T)child;
          break;
        }
      }

      return foundChild;
    }  

Bạn chỉ cần tiếp tục gọi phương thức đệ quy nếu loại được phù hợp với nhưng tên không (điều này xảy ra khi bạn vượt qua FrameworkElementnhư T). nếu không nó sẽ trở lại nullvà đó là sai.


0

Để tìm tổ tiên của một loại nhất định từ mã, bạn có thể sử dụng:

[CanBeNull]
public static T FindAncestor<T>(DependencyObject d) where T : DependencyObject
{
    while (true)
    {
        d = VisualTreeHelper.GetParent(d);

        if (d == null)
            return null;

        var t = d as T;

        if (t != null)
            return t;
    }
}

Việc thực hiện này sử dụng phép lặp thay vì đệ quy có thể nhanh hơn một chút.

Nếu bạn đang sử dụng C # 7, điều này có thể được thực hiện ngắn hơn một chút:

[CanBeNull]
public static T FindAncestor<T>(DependencyObject d) where T : DependencyObject
{
    while (true)
    {
        d = VisualTreeHelper.GetParent(d);

        if (d == null)
            return null;

        if (d is T t)
            return t;
    }
}

-5

Thử cái này

<TextBlock x:Name="txtblock" FontSize="24" >Hai Welcom to this page
</TextBlock>

Mã ẩn

var txtblock = sender as Textblock;
txtblock.Foreground = "Red"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.