UWP 利用VisualTreeHelper查找页面中的元素
一般我们在展示数据的时候,都会采用DataTemplate的预先设置数据模板,再使用Set ItemsSource的方式进行数据绑定
这样就能满足大部分的需求。
不过有时候需要对页面已经展示出来的元素进行调整,这个时候就需要利用UWP自带的VisualTreeHelper来进行查找🔍。
下面列举一些我常用的方法,并且做一些说明和使用范例。
注:有的是从网找摘抄的代码。
1、FindVisualChild:查找一个页面元素中包含的特定元素
public static TChild FindVisualChild<TChild>(DependencyObject obj) where TChild : DependencyObject { if (obj == null) return null; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child != null && child is TChild found) return found; else { TChild childOfChild = FindVisualChild<TChild>(child); if (childOfChild != null) return childOfChild; } } return null; }
代码示例:
从一个页面的Border元素中,查找它其中包裹的TextBlock控件,然后设置各种属性。
var textBlock = TreeHelper.FindVisualChild<TextBlock>(border); textBlock.Foreground = new SolidColorBrush(Colors.Black);
使用场景:
一个列表中,当鼠标移动到某一个Item上的时候,查找其中的控件,并做一些放大缩小操作等。
2、FindVisualChildren:查找页面元素中包含的所有特定元素。这个和上面的类似,只不过返回的是一个List
public static List<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject { List<T> list = new List<T>(); if (depObj != null) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { DependencyObject child = VisualTreeHelper.GetChild(depObj, i); if (child != null && child is T) { list.Add((T)child); } List<T> childItems = FindVisualChildren<T>(child); if (childItems != null && childItems.Count() > 0) { foreach (var item in childItems) { list.Add(item); } } } } return list; }
代码示例:
var listTextBlock = TreeHelper.FindVisualChildren<TextBlock>(ListView_V); foreach (var textblock in listTextBlock) { textblock.Foreground = new SolidColorBrush(Colors.White); }
3、FindChildByName:根据Name进行查找,前提是你需要在数据模板中设置了Name属性
public static DependencyObject FindChildByName(DependencyObject parant, string ControlName) { int count = VisualTreeHelper.GetChildrenCount(parant); for (int i = 0; i < count; i++) { var MyChild = VisualTreeHelper.GetChild(parant, i); if (MyChild is FrameworkElement && ((FrameworkElement)MyChild).Name == ControlName) return MyChild; var FindResult = FindChildByName(MyChild, ControlName); if (FindResult != null) return FindResult; } return null; }
代码示例:
var appBarButton = TreeHelper.FindChildByName(MediaTransportControls_Custom, "CompactOverlayButton") as AppBarButton; FontIcon fi = new FontIcon(); fi.FontFamily = new FontFamily("ms-appx:///Assets/Fonts/VMDL2.ttf#Calculator MDL2 Assets"); if (view.ViewMode == ApplicationViewMode.CompactOverlay) fi.Glyph = "\uEE49"; else fi.Glyph = "\uEE47"; appBarButton.Icon = fi;
注意parent的范围不要太大,否则查找的时间太长,但是一般的应该没问题。
4、FindChildrenByName:同上,只不过返回的是一个List而已
public static List<T> FindChildrenByName<T>(DependencyObject parant, string ControlName) where T : DependencyObject { List<T> list = new List<T>(); if (parant != null) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parant); i++) { DependencyObject child = VisualTreeHelper.GetChild(parant, i); if (child != null && child is T && child is FrameworkElement && ((FrameworkElement)child).Name == ControlName) { list.Add((T)child); } List<T> childItems = FindChildrenByName<T>(child, ControlName); if (childItems != null && childItems.Count() > 0) { foreach (var item in childItems) { list.Add(item); } } } } return list; }
代码示例:
var cardGridList = TreeHelper.FindChildrenByName<Grid>(GridView_Episodes, "Grid_Card");
这个示例是我要从一个GridView控件中找出所有Name为“Grid_Card“的Grid,然后在窗体大小改变的时候,设置每一个Grid的大小。
这样可以做到GridView中动态改变每一个Item的大小了。