10-1.WPF模板

news2025/7/7 23:40:50

10-1.WPF模板

控件由“算法内容”和“数据内容”决定

  • 算法内容:指控件能展示哪些数据、具有哪些方法、能激发什么事件等,简而言之是控件的功能,一组相关逻辑
  • 数据内容:控件所展示的具体数据是什么

在WPF中,模板将数据和算法的内容和形式进行了解耦,模板分为两大类:

  • ControlTemplate:是算法内容的表现形式,决定了控件长什么样
  • DataTemplate:是数据内容的表现形式,也就是数据显示成什么样

DataTemplate

DataTemplate常用的地方有3处:

  1. ContentControl的ContentTemplate属性,相当于给ContentControl的内容穿上外衣
  2. ItemsControl的ItemTemplate属性,相当于给ItemTemplate的内容穿上外衣
  3. GridViewColumn的CellTemplate属性,相当于给GridViewColumn单元格里的数据穿上外衣

传统的事件驱动模式是控件和控件之间沟通,模型如下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b3BiGY74-1668484396161)(10.WPF模板.assets/image-20221114100004170.png)]

数据驱动则是数据与控件之间沟通,使用DataTemplate可以很方便的将事件驱动模式改为数据驱动模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W7GIc1Qv-1668484396162)(10.WPF模板.assets/image-20221114100340111.png)]

案例:有一列汽车的数据显示在ListBox里面,点击某条数据,详细数据显示在窗体左侧细节展示框中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f1B2cC1L-1668484396162)(10.WPF模板.assets/image-20221114100825704.png)]

将ListBox和细节展示框的窗体设计分别放进<DataTemplate>标签内包装,再放到主窗体的资源词典中。最重要的是为<DataTemplate>里的每个控件设置Binding,告诉各个控件应该关注数据的哪个属性。除此之外,有些属性不能直接使用,需要自定义Converter,在XAML中有两种方法使用Converter:

  • 把Converter以资源的形式放在资源词典里
  • 为Converter准备一个静态属性,在XAML中使用{x:Static}标签扩展来访问

定义Converter

//厂商名称转换为Logo路径
public class AutoMarkToLogoPathConverter:IValueConverter
{
    /// 正向转
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new BitmapImage(new Uri(string.Format(@"Resource/Image/{0}.png",(string)value),UriKind.Relative));
    }
    /// 逆向转未用到
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
//汽车名称转换为照片路径
public class NameToPhotoPathConverter:IValueConverter
{
    /// 正向转
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new BitmapImage(new Uri(string.Format(@"Resource/Image/{0}.jpg", (string)value), UriKind.Relative));
    }
    /// 逆向转未用到
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML代码如下:

<Window x:Class="WpfApplication1.Window36"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1.Model"
        Title="Window36" Height="350" Width="623">
    <Window.Resources>
        <!--Converter-->
        <local:AutoMarkToLogoPathConverter x:Key="amp"/>
        <local:NameToPhotoPathConverter x:Key="npp"/>
        <!--DataTemplate For DatialView-->
        <DataTemplate x:Key="DatialViewTemplate">
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6">
                <StackPanel>
                    <Image x:Name="imgPhoto" Width="400" Height="250" Source="{Binding AutoMark,Converter={StaticResource npp}}"></Image>
                    <StackPanel Orientation="Horizontal" Margin="5,0">
                        <TextBlock Text="Name:" FontSize="20" FontWeight="Bold"></TextBlock>
                        <TextBlock FontSize="20" Margin="5,0" Text="{Binding Name}"></TextBlock>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="5,0">
                        <TextBlock Text="AutoMark:" FontWeight="Bold"></TextBlock>
                        <TextBlock  Margin="5,0" Text="{Binding AutoMark}"></TextBlock>
                        <TextBlock Text="Year:" FontWeight="Bold">

                        </TextBlock>
                        <TextBlock Text="{Binding Year}" Margin="5,0">

                        </TextBlock>
                        <TextBlock Text="Top Speed:" FontWeight="Bold">

                        </TextBlock>
                        <TextBlock Text="{Binding TopSpeed}" Margin="5,0">

                        </TextBlock>
                    </StackPanel>
                </StackPanel>
            </Border>
        </DataTemplate>
        <!--Data Template For ItemView-->
        <DataTemplate x:Key="ItemView">
            <Grid Margin="2">
                <StackPanel Orientation="Horizontal">
                    <Image x:Name="igLogo" Grid.RowSpan="3" Width="64" Height="64" Source="{Binding Name,Converter={StaticResource amp}}"></Image>
                    <StackPanel Margin="5,10">
                        <TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Bold"></TextBlock>
                        <TextBlock Text="{Binding Year}" FontSize="14"></TextBlock>
                    </StackPanel>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </Window.Resources>
   <!--窗体内容-->
    <StackPanel Orientation="Horizontal">
        <UserControl ContentTemplate="{StaticResource DatialViewTemplate}" Content="{Binding Path=SelectedItem,ElementName=lbInfos}"></UserControl>
        <ListBox x:Name="lbInfos" ItemTemplate="{StaticResource ItemView}"></ListBox>
    </StackPanel>
</Window>

初始化数据

private void InitialCarList()
{
    List<Car> infos = new List<Car>() { 
    new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="200", Year="1990"},
    new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="250", Year="1998"},
    new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="300", Year="2002"},
    new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="350", Year="2011"},
    new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="500", Year="2020"}
    };
    this.lbInfos.ItemsSource = infos;
}

ControlTemplate

ControlTemplae可以控制控件的外表样式,在实际项目中ControlTemplate主要用来:

  1. 通过更换ControlTemplate来改变控件外观
  2. 借助ControlTemplate,程序员和UI设计可以并行工作,程序员可以使用WPF标准控件来编程,等设计师工作完成后,只需把新的ControlTemplate应用到程序就可以

在Blend中的Application资源词典中增加一个TextBoxStyle

<Application.Resources>
        <Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TextBox}">
                        <Border x:Name="border" 
                                BorderBrush="{TemplateBinding BorderBrush}" 
                                BorderThickness="{TemplateBinding BorderThickness}" 
                                Background="{TemplateBinding Background}" 
                                CornerRadius="10">
                            <ScrollViewer x:Name="PART_ContentHost"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
</Application.Resources>

注意点:

  1. 作为资源不是单纯的ControlTemplate,而是Style。使用style时,如果value值比较简单,则直接使用Attribute就可以,如果比较复杂,则只能使用XAML的属性对象语法,如TextBox的Template属性是一个ControlTemplate对象。
  2. TemplateBinding,ControlTemplate被应用到一个控件上,我们称之为目标控件,TemplateBinding的意思是将自己的属性关联到目标控件上的某个属性值上,如Background="{TemplateBinding Background}" 意思是让Border的Background与目标控件保持一致。

TextBox应用上面的style

<TextBox  Style="{DynamicResource TextBoxStyle}"/>
<TextBox  Style="{DynamicResource TextBoxStyle}"/>

其实每个控件本身就是一颗UI元素树,WPF可以看做两颗树,LogicalTree和VisualTree树,这两棵树的交点就是ControlTemplate。

ItemsControl的PanelTemplate

ItemsControl具有一个名为ItemsPanel的属性,其数据类型为ItemsPanelTemplate,它的作用是控制ItemsControl的条目容器。比如,ListBox条目都是纵向排列,现在改为横向排列。

<Grid Margin="2">
    <ListBox>
        <TextBlock Text="A"/>
        <TextBlock Text="B"/>
        <TextBlock Text="C"/>
        <TextBlock Text="D"/>
        <TextBlock Text="E"/>
    </ListBox>
</Grid>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v3Ft1iwg-1668484396163)(10.WPF模板.assets/image-20221114105432328.png)]

<Grid Margin="2">
    <ListBox>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <TextBlock Text="A"/>
        <TextBlock Text="B"/>
        <TextBlock Text="C"/>
        <TextBlock Text="D"/>
        <TextBlock Text="E"/>
    </ListBox>
</Grid>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-15atntjv-1668484396163)(10.WPF模板.assets/image-20221114105501185.png)]

DataTemplate和ControlTemplate的关系

控件只是个数据和行为的载体,它的外观由ControlTemplate决定,数据外观由DataTemplate决定,他们正对应着Control类的Template和ContentTemplate两个属性。

凡是Template都要作用在控件上,这个控件叫做Template的目标控件,也叫做模板化控件。DataTemplate同样也是,它施加在数据对象上,但是展示数据对象(一组展示数据的控件)也要有一个载体,该载体一般落实在一个ContentPresenter对象上,该对象只有一个ContentTemplate属性,表明它的功能就是承载由DataTemplate生成的一组控件。因为ContentPresenter是ControlTemplate控件树的一个节点,所以DataTemplate是ControlTemplate一颗子树。

由Template生成的控件树都有根,每个控件都有个TemplateParent属性,如果值不为NULL,说明这个控件是由Template自动生成的,而属性值就是应用了该模板的控件。如果由Template生成的控件使用了TemplateBinding获取属性值,则TemplateBinding的数据源就是应用了这个模板的目标控件。

应用

为Template设置应用目标有两种方法

  1. 逐个设置控件的Template/ContentTemplate/ItemsTemplate/CellTemplate等属性
  2. 整体应用,借助Style来实现,但是Style不能标记x:Key,如果不想应用则设置控件的Style为{x:Null}
<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="300">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TextBox}">
                        <StackPanel Background="Orange"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Margin" Value="5"/>
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="Height" Value="25"/>
        </Style>
    </Window.Resources>
    <StackPanel>
        <TextBox/>
        <TextBox/>
        <TextBox Style="{x:Null}" Margin="5"/>
    </StackPanel>
</Window>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LzBTYkZi-1668484396164)(10.WPF模板.assets/image-20221114195728350.png)]

把DataTemplate应用在某个数据类型上的方法时设置DataTemplate的DataType属性,并且DataTemplate作为资源时不能带x:Key标记。

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Unit}">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <Grid>
                        <Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding Price}"/>
                        <TextBlock Text="{Binding Year}"/>
                    </Grid>
                </StackPanel>
            </Grid>
        </DataTemplate>
        <c:ArrayList x:Key="ds">
            <local:Unit Year="2001" Price="100"/>
            <local:Unit Year="2002" Price="120"/>
            <local:Unit Year="2003" Price="130"/>
            <local:Unit Year="2004" Price="150"/>
            <local:Unit Year="2005" Price="160"/>
            <local:Unit Year="2006" Price="180"/>
            <local:Unit Year="2007" Price="190"/>
        </c:ArrayList>
    </Window.Resources>
    <StackPanel>
        <ListBox ItemsSource="{StaticResource ds}"/>
        <ComboBox ItemsSource="{StaticResource ds}" Margin="5"/>
    </StackPanel>
</Window>
public class Unit
{
    public int Price { set; get; }
    public string Year { set; get; }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MHTpxunK-1668484396164)(10.WPF模板.assets/image-20221115091306919.png)]

XML数据源

DataTemplate可以把XML数据中的元素名作为DataType,元素子节点和Attribute可以使用xpath来访问。

上面的案例改造

 <Window.Resources>
     <DataTemplate DataType="Unit">
         <Grid>
             <StackPanel Orientation="Horizontal">
                 <Grid>
                     <Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding XPath=@Price}"/>
                     <TextBlock Text="{Binding XPath=@Year}"/>
                 </Grid>
             </StackPanel>
         </Grid>
     </DataTemplate>
     <XmlDataProvider x:Key="ds" XPath="Units/Unit">
         <x:XData>
             <Units xmlns="">
                 <Unit Year ="2001" Price="100"/>
                 <Unit Year ="2002" Price="110"/>
                 <Unit Year ="2003" Price="120"/>
                 <Unit Year ="2004" Price="130"/>
                 <Unit Year ="2005" Price="140"/>
                 <Unit Year ="2006" Price="150"/>
             </Units>
         </x:XData>
     </XmlDataProvider>
 </Window.Resources>
 <StackPanel>
     <ListBox ItemsSource="{Binding Source={StaticResource ds}}"/>
     <ComboBox ItemsSource="{Binding Source={StaticResource ds}}" Margin="5"/>
 </StackPanel>

层级结构

WPF中TreeView和MenuItem控件用来显示层级,能够帮助层级控件显示层级数据的模板是HierarchicalDataTemplate

案例1:Data.xml文件

<?xml version="1.0" encoding="utf-8" ?> 
<Data xmlns="">
  <Grade Name="一年级">
    <Class Name="甲班">
      <Group Name="A组"/>
      <Group Name="B组"/>
      <Group Name="C组"/>
    </Class>
  <Class Name="乙班">
      <Group Name="A组"/>
      <Group Name="B组"/>
      <Group Name="C组"/>
    </Class>
  </Grade>
  <Grade Name="二年级">
    <Class Name="甲班">
      <Group Name="A组"/>
      <Group Name="B组"/>
      <Group Name="C组"/>
    </Class>
  <Class Name="乙班">
      <Group Name="A组"/>
      <Group Name="B组"/>
      <Group Name="C组"/>
    </Class>
  </Grade>
</Data>

程序的XAML:

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <XmlDataProvider x:Key="ds" Source="Data.xml" XPath="Data/Grade"/>
        <!--年级-->
        <HierarchicalDataTemplate DataType="Grade" ItemsSource="{Binding XPath=Class}">
            <TextBlock Text="{Binding XPath=@Name}"/>
        </HierarchicalDataTemplate>
        <!--班级-->
        <HierarchicalDataTemplate DataType="Class" ItemsSource="{Binding XPath=Group}">
            <RadioButton Content="{Binding XPath=@Name}" GroupName="gn"/>
        </HierarchicalDataTemplate>
        <!--小组-->
        <HierarchicalDataTemplate DataType="Group" ItemsSource="{Binding XPath=Student}">
            <CheckBox Content="{Binding XPath=@Name}" />
        </HierarchicalDataTemplate>
    </Window.Resources>
    <Grid>
        <TreeView Margin="5" ItemsSource="{Binding Source={StaticResource ds}}"/>
    </Grid>
</Window>

在这里插入图片描述

案例2:同一种数据类型的嵌套,只需设置一个HierarchicalDataTemplate,他会自动迭代

data.xml

<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns="">
  <Operation Name="文件" Gesture="F">
    <Operation Name="新建" Gesture="N">
      <Operation Name="项目" Gesture="N"/>
      <Operation Name="网站" Gesture="N"/>
      <Operation Name="文档" Gesture="N"/>
    </Operation>
    <Operation Name="保存" Gesture="N"/>
    <Operation Name="打印" Gesture="N"/>
    <Operation Name="退出" Gesture="N"/>
  </Operation>
  <Operation Name="编辑" Gesture="E">
    <Operation Name="拷贝" Gesture="N"/>
    <Operation Name="剪切" Gesture="N"/>
    <Operation Name="粘贴" Gesture="N"/>
  </Operation>
</Data>

XAML:

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <XmlDataProvider x:Key="ds" Source="Data1.xml" XPath="Data/Operation"/>
        <HierarchicalDataTemplate DataType="Operation" ItemsSource="{Binding XPath=Operation}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding XPath=@Name}" Margin="10,0"/>
                <TextBlock Text="{Binding XPath=@Gesture}"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <StackPanel>
        <Menu ItemsSource="{Binding Source={StaticResource ds}}"/>
    </StackPanel>
</Window>

在这里插入图片描述

HierarchicalDataTemplate的作用目标不是MenuItem的内容,而是它的Header。如果对MenuItem的单击事件进行侦听,可以从单击MenuItem的Header中提取XML数据。

<StackPanel MenuItem.Click="StackPanel_Checked">
    <Menu ItemsSource="{Binding Source={StaticResource ds}}"/>
</StackPanel>
private void StackPanel_Checked(object sender, RoutedEventArgs e)
{
    MenuItem mi = e.OriginalSource as MenuItem;
    XmlElement xe = mi.Header as XmlElement;
    MessageBox.Show(xe.Attributes["Name"].Value);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2R6lOGte-1668484396166)(10.WPF模板.assets/image-20221115100908738.png)]

控件内部的树形结构

如果UI元素树上有个x:Name="txt"的控件,而某个控件内部有个由Template生成的x:Name="txt"的控件,他们不会产生冲突,因为LogicTree不会看到控件内部的细节。由ControlTemplate和DataTemplate有一个FindName的方法供我们检索其中的内部控件,也就是说,只要我们拿到Template就能找到内部的控件。

获取ControlTemplate对象

想拿到ControlTemplate对象,直接访问目标对象的Template就可以。

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="172" Width="300">
    <Window.Resources>
        <ControlTemplate x:Key="cTmp">
            <StackPanel Background="Orange">
                <TextBox x:Name="txt1" Margin="6"/>
                <TextBox x:Name="txt2" Margin="6"/>
                <TextBox x:Name="txt3" Margin="6"/>
            </StackPanel>
        </ControlTemplate>
    </Window.Resources>
    <StackPanel Background="Yellow">
        <UserControl x:Name="uc" Template="{StaticResource cTmp}" Margin="5"/>
        <Button Content="Find by Name" Width="120" Height="30" Click="Button_Click"/>
    </StackPanel>
</Window>
private void Button_Click(object sender, RoutedEventArgs e)
{
    //通过目标对象的Template就可以获得ControlTemplate
    TextBox tb = this.uc.Template.FindName("txt1", this.uc) as TextBox;
    tb.Text = "Hello";
    StackPanel sp= tb.Parent as StackPanel;
    (sp.Children[1] as TextBox).Text = "Hi";
    (sp.Children[2] as TextBox).Text = "XXX";
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n6E0WOXZ-1668514330794)(C:\Users\54302\Desktop\wpf教程#\使用LogicalTree控件.assets\image-20221115191011155.png)]

获取DataTemplate对象

如果找到DataTemplate生成的控件后,如果想获得与控件相关的数据,如长宽高,这种做法是正确的。而如果想获得数据,那一般是逻辑出现了问题,因为WPF采用数据驱动的方式,获取数据一般在底层就可以实现。

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="175" Width="220">
    <Window.Resources>
        <!--数据对象-->
        <local:Student x:Key="stu" Id="1" Name="Tom" Skill="WPF" HasJob="True"/>
        <!--DataTemplate-->
        <DataTemplate x:Key="stuDT">
            <Border BorderBrush="Orange" BorderThickness="2" CornerRadius="5">
                <StackPanel>
                    <TextBlock Text="{Binding Id}" Margin="5"/>
                    <TextBlock x:Name="txtName" Text="{Binding Name}" Margin="5"/>
                    <TextBlock Text="{Binding Skill}" Margin="5"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <StackPanel Background="Yellow">
        <ContentPresenter x:Name="cp" Content="{StaticResource stu}" ContentTemplate="{StaticResource stuDT}" Margin="5"/>
        <Button Content="Find" Margin="5" Click="Button_Click_1"/>
    </StackPanel>
</Window>
public class Student
{
    public int Id { set; get; }
    public string Name { set; get; }
    public string Skill { get; set; }
    public bool HasJob { set; get; }
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
    TextBlock tb = this.cp.ContentTemplate.FindName("txtName", this.cp) as TextBlock;
    MessageBox.Show(tb.Text);

    //如果只是使用数据,最好这样
    //Student st = this.cp.Content as Student;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SzQAqwXy-1668514330795)(C:\Users\54302\Desktop\wpf教程#\使用LogicalTree控件.assets\image-20221115192756579.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-azTZJfQs-1668514330796)(C:\Users\54302\Desktop\wpf教程#\使用LogicalTree控件.assets\image-20221115192806347.png)]

GridView使用Template

DataTemplate的常用之处是GridViewColumn的CellTemplate属性。GridViewColumn默认的CellTemplate属性使用了一个TextBlock,如果想使用CheckBox呢?

案例:

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="175" Width="220">
    <Window.Resources>
        <!--数据集合-->
        <c:ArrayList x:Key="stuList">
            <local:Student Id="1" Name="A" Skill="C" HasJob="True"/>
            <local:Student Id="2" Name="B" Skill="C++" HasJob="True"/>
            <local:Student Id="3" Name="C" Skill="C#" HasJob="True"/>
            <local:Student Id="4" Name="D" Skill="jAVA" HasJob="False"/>
            <local:Student Id="5" Name="E" Skill="PYTHON" HasJob="True"/>
            <local:Student Id="6" Name="F" Skill="SQL" HasJob="True"/>
        </c:ArrayList>
        <!--DataTemplate-->
        <DataTemplate x:Key="nameDT">
            <TextBox x:Name="txtName" Text="{Binding Name}"/>
        </DataTemplate>
        <DataTemplate x:Key="skillDT">
            <TextBox x:Name="txtSkill" GotFocus="TxtSkill_GotFocus" Text="{Binding Skill}"/>
        </DataTemplate>
        <DataTemplate x:Key="hjDT">
            <CheckBox x:Name="chkJob" IsChecked="{Binding HasJob}"/>
        </DataTemplate>
    </Window.Resources>
    <Grid Margin="5">
        <ListView x:Name="listView" ItemsSource="{StaticResource stuList}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}"/>
                    <GridViewColumn Header="姓名" CellTemplate="{StaticResource nameDT}"/>
                    <GridViewColumn Header="技术" CellTemplate="{StaticResource skillDT}"/>
                    <GridViewColumn Header="已工作" CellTemplate="{StaticResource hjDT}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>
private void TxtSkill_GotFocus(object sender, RoutedEventArgs e)
{
    //访问数据
    TextBox tb = e.OriginalSource as TextBox;//事件发起源头
    ContentPresenter cp = tb.TemplatedParent as ContentPresenter;//获取模板
    Student su = cp.Content as Student;//获取业务数据
    this.listView.SelectedItem = su;

    //访问界面元素
    ListViewItem vi = this.listView.ItemContainerGenerator.ContainerFromItem(su) as ListViewItem;
    CheckBox crb = FindVisualChild<CheckBox>(vi);
    MessageBox.Show(crb.Name);
}
private T FindVisualChild<T>(DependencyObject obj) where T:DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        if (child!=null && child is T)
        {
            return child as T;
        }
        else
        {
            T childOfChild = FindVisualChild<T>(child);
            if (childOfChild !=null)
            {
                return childOfChild;
            }
        }
    }
    return null;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zkcX0HoD-1668514330797)(C:\Users\54302\Desktop\wpf教程#\使用LogicalTree控件.assets\image-20221115195825110.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Gi12oWI-1668514330798)(C:\Users\54302\Desktop\wpf教程#\使用LogicalTree控件.assets\image-20221115195834126.png)]

  • 案例中为模板中显示姓名的TextBox增加了GetFocus事件,界面上任何一个姓名TextBox获得焦点后都会调用该事件。

  • 每个ItemsControl派生类(ListBox、ListView)都有自己的条目容器,使用ItemContainerGenerator.ContainerFromItem方法能获得包装着指定条目数据的容器。

  • VisualTreeHelper类可以遍历控件内部的各个节点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/6945.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis数据类型

1.String(字符串) 在任何一种编程语言中&#xff0c;字符串都是最基础的数据结构&#xff0c;在Redis中String是可以修改的称之为&#xff1a;动态字符串(简称SDS) Redis的内存分配机制&#xff1a; - 当字符串的长度小于1MB时&#xff0c;每次扩容都是加倍现有的空间 - 如果字…

离散数学:图的基本概念

本帖子讨论图的基本概念&#xff0c;这一章&#xff0c;我们将利用有序对和二元关系的概念定义图。图分为了无向图和有向图&#xff0c;他们有共性也有区别&#xff0c;请大家注意体会&#xff0c;用联系和辩证的观点去认识。 1、无向图和有向图 注意无向图和有向图的表示&…

Servlet【 ServletAPI中的会话管理Cookie与Session】

Servlet【 ServletAPI中的会话管理Cookie与Session】&#x1f352;一.回顾Cookie与Session&#x1f34e;1.1 Cookie&#x1f34e;1.2 Session&#x1f34e;1.3Cookie 和 Session 的区别&#x1f352;二.Servlet会话管理操作&#x1f34e;2.1核心方法&#x1f352;三.常见案例实…

【服务器搭建】教程一:没钱买服务器怎么玩 进来看

前言&#xff1a; 最近看到有一些网上的大佬把自己的爱心网页&#xff08;没领到的小伙伴看一下前几篇文章&#xff09;部署到了自己的服务器上&#xff0c;使得可以直接通过链接就实现访问。属实不错&#xff01; 自己内心就产生了这样一个想法&#xff1a;购买一台服务器&a…

Whisper论文阅读笔记

Whisper论文阅读笔记Robust Speech Recognition via Large-Scale Weak Supervision1. 引言2. 方法2.1 数据处理2.2 模型2.3 多任务设置2.4 训练细节3. 实验结果3.1 Zero-shot3.2 多语言语音识别3.3 多语言机器翻译3.4 语种检测3.5 对加性噪声的鲁棒性3.6 长语音转录3.7 人类基线…

基于向量加权平均值的高效优化算法(Matlab代码实现)

&#x1f4dd;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;…

学习 RabbitMQ 这一篇就够了

文章目录一、MQ相关概念二、RabbitMQ相关概念三、安装四、HelloWorld五、工作队列5.1、轮询分发消息5.2、消息应答5.2.1、自动应答5.2.2、手动应答5.2.3、消息自动重新入队5.2.4、消息手动应答代码5.3、持久化5.4、不公平分发&#xff08;能者多劳&#xff09;5.5、预取值5.6、…

读书笔记3|使用Python,networkx对卡勒德胡赛尼三部曲之——《群山回唱》人物关系图谱绘制

读书笔记3|《群山回唱》-卡勒德胡赛尼 踉跄前行中&#xff0c;你总能在他们身上找到丢失的那一部分记忆。 一度看不下去这本书&#xff0c;因为最开始的章节里太痛了&#xff0c;加上我也离开我的孩子&#xff0c;生活已经够苦&#xff0c;我需要一点糖。这次实在太无聊了&…

php-上传图片加水印(文字水印图片水印)

img.php <?php $img 1.jpg; //获取图片信息 $info getimagesize($img); //获取图片类型 $type image_type_to_extension($info[2],false); //在内容中创建一个和图片一模一样的图片 $ext "imagecreatefrom{$type}"; //图片复制到内存中 $image $ext($img);…

基于SpringBoot前后端分离的网吧管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SpringBoot 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目…

PICO《轻世界》体验:随心畅玩,洒脱创作,潜力无限

不少玩家应该还记得&#xff0c;PICO 4发布会上曾宣布将在VR运动健身、VR视频、VR娱乐、VR创造四大方向展开内容布局。而目前&#xff0c;前三个完成了基本部署&#xff0c;在创造方向上则依托于刚刚上线的《轻世界》这款应用。《轻世界》是一款3D内容UGC创作产品&#xff0c;目…

php宝塔部署实战thinkphp考试平台管理系统源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 有个朋友发消息跟我说&#xff0c;在网上下载了一套thinkphp考试管理系统的源码&#xff0c;在搭建的时候遇到问题一直部署不起来&#xff0c;让我帮他看看&#xff0c;我看了下代码&#xff0c;里面有些部分代码…

2022年11月华南师范大学自考本科网络工程-本科实践题目

《互联网及其应用&#xff08;03142&#xff09;&#xff08;实践&#xff09;》课程试卷 答卷提交说明&#xff1a;编程代码与输出结果截图&#xff0c;放到一个文件中&#xff0c;文件以“序号 姓名 课程名 ”命名&#xff0c;本试卷有三门课程&#xff0c;请根据不同的课程…

k8s训练营

一、linux命名空间和docker 1.linux的7大ns--------------ipc,net,pid,mnt.uts.user 查看linux的ns lsns查看不同类型的ns [rootmaster ~]# lsns -t netNS TYPE NPROCS PID USER COMMAND 4026531956 net 116 1 root /usr/lib/systemd/systemd --system --deserialize …

公司代码全局参数设置及其意义

在SAP中配置公司时&#xff0c;会配置公司的全局参数&#xff0c;但这些参数具体的意思是什么估计很多同学都搞不懂&#xff0c;我也找了下资料&#xff0c;贴出来供大家参考。 设置参数路径&#xff1a;IMG→财务会计→财务会计全局设置→公司代码的全球参数→输入全局参数 账…

C++Qt开发——Linguist语言家

Qt Linguist 简介 Qt提供了一款优秀的支持Qt C和Qt Quick应用程序的翻译工具。发布者、翻译者和开发者可以使用这款工具来完成他们的任务。 发布者&#xff1a;承担了全面发布应用程序的责任。通常&#xff0c;他们协调开发者和翻译者的工作&#xff0c;可以使用lupdate工具…

激光雷达的厮杀18年:西方“诸神黄昏”,东方“新王隐现”

鼻祖、发明家、神童、梦想家、特种兵和中国双星&#xff0c;激光雷达“诸神混战”&#xff0c;行业疯狂洗牌。 风云激荡中&#xff0c;每个人都在亲身见证历史。 2004年&#xff0c;美国发起DARPA挑战赛&#xff0c;无人车上路&#xff0c;汽车上首次出现激光雷达。 2010年之…

原型工具墨刀的使用

刚开始接触原型工具是大学时候了&#xff0c;大学参加大创的时候第一次接触并使用原型工具做了小程序项目原型。那时候是下载的客户端。 最近&#xff0c;又开始思考在用户沟通过程中为方便沟通&#xff0c;可以先自己用原型工具简单的设计一下先。 首先&#xff1a;网页版好用…

JavaScript流程控制-循环(循环(for 循环,双重 for 循环,while 循环,do while 循环,continue break))

目录 JavaScript流程控制-循环 循环 for 循环 执行过程&#xff1a; 断点调试&#xff1a; 案例一&#xff1a;求1-100之间所有整数的累加和 案例二&#xff1a;求1-100之间所有数的平均值 案例三&#xff1a;求1-100之间所有偶数和奇数的和 案例四&#xff1a;求1-10…

哈希(Hash) - 开散列/闭散列

文章目录&#xff1a;认识哈希哈希函数处理冲突的方法闭散列&#xff08;开放定址法&#xff09;开散列&#xff08;链地址法&#xff09;哈希表闭散列实现闭散列基本框架哈希表闭散列插入&#xff08;insert&#xff09;哈希表闭散列删除&#xff08;erase&#xff09;哈希表闭…