WPF FindName()查找命名注册的元素

时间:2022-03-16 03:15:08

一、查找xaml中命名注册的元素

<Button x:Name="btn1" Content="显示内容" HorizontalAlignment="Left" Margin="25,115,0,0" VerticalAlignment="Top"/> <TextBox x:Name="txtOne" HorizontalAlignment="Left" Margin="25,62,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top"/> //使用FindName() 查找 TextBox txtOne = this.FindName("txtOne") as TextBox; if (txtOne != null) { MessageBox.Show(txtOne.Text); //可以访问到 } TextBox txtTwo = btn1.FindName("txtOne") as TextBox; if (txtTwo != null) { MessageBox.Show(txtTwo.Text); //也可以访问到 }
二、查找后台代码命名注册的元素
后台添加方式 TextBlock block = new TextBlock(); block.Text = "海上生明月"; panelOne.RegisterName("block1", block); //将block命名block1名称注册到panelOne上 panelOne.Children.Add(block); //从当前窗口获取,可以访问到 TextBlock block1 = btn1.FindName("block1") as TextBlock; if (block1 != null) { MessageBox.Show(block1.Text); } //从Panel获取,可以访问到 TextBlock block2 = panelOne.FindName("block1") as TextBlock; if (block2 != null) { MessageBox.Show("panelOne:"+block2.Text); }
注释:元素名称Name注册,, 不能重复。 预设置元素名字

WPF有两种方式设置元素的Name

<StackPanel x:Name="panel"> <Label Content="Name1Label"/> <Label x:Name="name2" Content="Name2Label"/> </StackPanel>

这里我们的重点不在于讨论Name和x:Name的区别,

Name是真正元素上的属性,x:Name而则xaml(语法解析)的魔力,我们所看到的只能是表象.

不仅仅是注册元素的名字

除了Element之外,其他类型也是可以的,如

<Label> <Label.BorderBrush> <SolidColorBrush x:Name="brushName"></SolidColorBrush> </Label.BorderBrush> </Label>

有些基本类型在xaml中无法设置,如String,Int类型等.但可以通过代码设置

this.RegisterName("str", "Hello");

这里只有功能示例而已,但实际中千万别这么做,本身不为此设计.

查找UserControl的元素

先定义一个UserControl

<UserControl x:Class="NameScopeDemo.MyUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <Button HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="btn">UserControl Button</Button> </Grid> </UserControl>
在主窗体中使用UserControl <StackPanel x:Name="panel"> <local:MyUserControl x:Name="myControl"></local:MyUserControl> </StackPanel>
现在查找结果如下

若使用主窗体去无法查找到btn的话,但通过UserControl就可以.

在设计上将UI切分了,但却给查找元素造成了麻烦了。

命名范围(NameScope)

若以Code方式,添加方式则如下

uc = new MyUserControl(); var ns = new NameScope(); this.RegisterName("myControl", uc); panel.Children.Add(uc);
为UserControl创建了一个独立的命名范围,想要查找MyUserControl的元素可以通过MyUserControl的级别的FindName来查找 模板取元素 <ContentControl x:Name="cc"> <ContentControl.ContentTemplate> <DataTemplate> <Button HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="btn">UserControl Button</Button> </DataTemplate> </ContentControl.ContentTemplate> </ContentControl>

看到上面代码,cc无法通过FindName查找到btn,只有模板的根元素才可以,这个根元素一般是ContentPresenter,所以当在模板内查找元素时,必须告诉其根元素

public Object FindName( string name, FrameworkElement templatedParent ) 那么首先我们就必须找到ContentPresenter,而只能通过视觉树上面找,整体而言还是比较麻烦的,不知道为何内部API不封装一下. 将模板内的元素名字注册到父级

var ns = uc.GetValue(NameScope.NameScopeProperty) as IDictionary<string, object>; var localNS = this.GetValue(NameScope.NameScopeProperty) as IDictionary<string, object>; foreach (var n in ns) { if (localNS.ContainsKey(n.Key)) { this.RegisterName(n.Key, n.Value); } }
首先获取当前元素的NameScope,然后再将其注册到父级命名范围内以方便查找,值得注意的是模板内部的有些Name是固定的,如ScrollBar,其内部模板元素Name命名是有规定的,所以不要将其注册在内.

WPF FindName()查找命名注册的元素