• WPF 元素的查找


     预设置元素名字

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

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

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

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

    查找已设置Name的元素

    WPF的基类元素FrameworkElement提供了FindName方法以提供查找设定的元素

    image

    以Code的形式添加元素

    var label = new Label();
    label.Name = "label3";
    panel.Children.Add(label);

    注意已经设置了Name

    添加好以后,然后查找这个元素,会发现并不能查找到这个元素

    image

    上面就说过xaml是有魔力的,并非设置一个Name属性就可以了的,其内部还有了一个叫RegisterName的方法,以注册元素的Name(想象一下,如果有1000个树节点,从根节点开始找最内部的节点那得多慢),有了Name就跟元素绑到一起了.
    现修改如下,用RegisterName方法注册(注意:即使注释了Name 属性也不会有影响)

     var label = new Label();
    // label.Name = "label3";
     this.RegisterName("label3", label);
     panel.Children.Add(label);

    现在查找恢复成功

    image


    但会发现查找出来的元素Name还是空的.这就会造成歧义,建议应该Name属性和RegisterName方法一起设置,

    不仅仅是注册元素的名字

    除了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>
    

    现在查找结果如下

    image

    若使用主窗体去无法查找到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命名是有规定的,所以不要将其注册在内.

    下篇将继续讨论NameScope,绑定,视觉树,逻辑树之间的关系

  • 相关阅读:
    【一天一个canvas】制作渐变式PPT背景(十五)
    【一天一个canvas】写文字(十四)
    【一天一个canvas】图像切割函数clip(十三)
    ThinkPHP 3.2 大写字母函数封装方法实例
    百度echarts 地图使用实例
    随机数生成
    需要修改php.ini文件支持操作,可不用直接操作php.ini
    定时多少时间调用指定URL
    自动调用接口
    tp5 Excel 批量导入
  • 原文地址:https://www.cnblogs.com/changbaishan/p/3308467.html
Copyright © 2020-2023  润新知