10-1.WPF模板

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>

在这里插入图片描述
DataType指定了HierarchicalDataTemplate模板用哪种数据类型
ItemsSource指定下一层显示哪些数据

案例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类可以遍历控件内部的各个节点。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 机械设备的WPF界面模板可以在设计制造机械设备的过程中,用于呈现控制和监控功能。在这种模板中,可以使用诸如机器状态、设备运行参数、报警和故障信息等要素来展示设备的工作情况。与普通的图形用户界面相比,WPF界面具备更丰富的功能性和强大的可配置性,具体表现在以下几个方面。 首先,WPF界面模板可以适配不同尺寸的显示器。机械设备通常需要监控多种参数,因此需要显示器大尺寸,但也有少数情况下需要小尺寸显示器来满足不同的监控场景。WPF界面模板可以根据实际情况灵活切换界面尺寸,保证显示效果。 其次,WPF界面模板可以提高设备的易用性和用户体验。在大型机械设备操作过程中,常常需要进行快速调节参数,这就要求界面设计时兼顾易操作性和人机交互效果。WPF界面模板可以灵活运用诸如按钮、滑块、开关等用户界面元素,通过实现鼠标点击、拖动、键盘输入等方式,使用户能够轻松地掌握设备的操作。 最后,WPF界面模板可以为机械设备提供更丰富的控制和监测功能。通过可视化操作,可以对设备的控制函数和监测参数进行分析和调整,从而提升设备的工作效率和可靠性。通过WPF界面模板可以使机械设备的制造和管理变得更加高效,提高制造商和用户的竞争力。 ### 回答2: 机械设备wpf界面模板是一种基于Windows Presentation Foundation(WPF)技术的用户界面模板,用于设计和开发机械设备控制系统的界面。这种模板主要包括一系列预定义的UI控件和布局,帮助开发人员实现高效且易于操作的机械设备界面,从而提高生产效率和降低设备操作难度。 机械设备wpf界面模板的特点是使用了多种UI控件,例如按钮、滑块、输入框等,组合形成了一组完整的用户界面设计元素。这些元素可以轻松定制和调整,以便满足特定机械设备控制系统的需求。 此外,机械设备wpf界面模板还具有灵活性和可扩展性。开发人员可以根据具体需求添加自定义UI控件或修改现有UI模板,以便更好地满足机械设备界面的需求。 总之,机械设备wpf界面模板为机械设备控制系统开发人员带来了很大的便利,使他们能够更加轻松地设计出直观、易操作、高效的机械设备控制界面。 ### 回答3: 机械设备wpf界面模板是一种用于开发机械设备相关软件的界面模板,基于WPF技术实现。 机械设备wpf界面模板包括各种机械设备通用的界面元素,如实时数据监测、设备控制、报警信息等。在使用模板时,用户可以根据自己的需求和设备的特性进行自定义配置,使得软件界面更加符合实际操作需求。 通过使用机械设备wpf界面模板,不仅可以提高开发效率,减少开发成本,还可以提供更好的用户体验和操作便利性。此外,模板还提供了安全可靠的数据传输和处理机制,确保设备的稳定运行和数据的精准处理。 因此,机械设备wpf界面模板在机械设备相关软件开发中具有广泛的应用价值和意义,能够为机械设备的自动化控制、数字化管理和可视化操作提供强有力的技术支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

步、步、为营

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值