WPF(Windows Presentation Foundation)
- 英 /ˌpreznˈteɪʃn/ Presentationn. (颁奖等)仪式,典礼;授予,颁发;(在仪式上接受的)奖项,赠予物;展示会,介绍会,发布会;陈述,报告,说明;(事物的)呈现方式;(证件等的)出示;(证物的)提交,提供;(戏剧的)演出;(胎儿的)先露位置,产位;(尤指在帝王前)正式引见,引……朝见;<史>(圣职等的)推荐
XAML是eXtensible Application Markup Language的英文缩写,相应的中文名称为可扩展应用程序标记语言.
<Application x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp11"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
StartupUri: 该项目为项目启动
Application.Resources: 设置引用程序资源字典, MergedDictionaries用于定义各种资源字典的字典集合
.xaml文档最终被转换成BAML作为资源得形式嵌入到程序集当中。当应用程序工作得时候,会从构造函数的实现方法当中提取BAML资源,并用它来构建用户界面,通过解析BAML,会创建每个控件对象, 设置属性,关联事件等等…
编译过程:
WPF应用程序编译时 首先把XAML文件编译为BAML, (编过的过程当中, VisualStudio会在项目的文件夹当中生成一些临时文件,主要包含控件的相关内容)
编译结束后,编译过的代码会将所有BAML作为资源的形式嵌入到到应用程序或者DLL程序集当中,
以BAML资源的形式存在的优点:
BAML为XAML的二进制表达形式, 不仅小, 而且本身是经过优化的, 在运行时读取BAML比XAML的速度快
资源已经随着程序集嵌入其中, 不必担心丢失导致问题。
也提供程序内部进行读取。
XAML与WPF:
两者相互补充, 你可以完全使用C#来构建你的用户界面, 也可以使用未编译过的XAML文件。
不适用XAML则无法发挥WPF的优势, 但是两者之间是相互独立的。
读取XAML文件作为内容显示:
string xamlfile=“”;
DependencyObject dependency;
using (FileStream fs = new FileStream(xamlfile, FileMode.Open))
{
dependency = (DependencyObject)XamlReader.Load(fs);
}
this.Content = dependency;
读取程序集当中的BAML资源:
var resourcesName = this.GetType().Assembly.GetName().Name + ".g";
var manager = new ResourceManager(resourcesName, this.GetType().Assembly);
var resourceSet = manager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
var dictionaryEntries = resourceSet.OfType<DictionaryEntry>().ToList();
dictionaryEntries.ForEach(arg =>
{
Baml2006Reader reader = new Baml2006Reader((Stream)arg.Value);
var win = XamlReader.Load(reader) as Window;
Console.WriteLine(win.Name);
});
2.为什么有一些元素有Padding,而一些元素并没有?
3.Magin和Padding的区别是…?
4.关于Content…
在继承于Control下的大部分控件具备这个Padding属性, TextBlock则单独实现了Padding 属性。Content由于是object类型, 所以对于常用的, Button, CheckBox 等等类型控件来讲, 不仅仅可以设置字符串类型, 也可以设置各种复杂的对象类型
例如:
<Button>
<Button.Content>
<StackPanel Orientation="Horizontal">
<TextBlock Text="♥"/>
<TextBlock Text="Hello"/>
</StackPanel>
</Button.Content>
</Button>
样式介绍:
WPF中的各类控件元素, 都可以自由的设置其样式。 诸如:
字体(FontFamily)
字体大小(FontSize)
背景颜色(Background)
字体颜色(Foreground)
边距(Margin)
水平位置(HorizontalAlignment)
垂直位置(VerticalAlignment) 等等。
而样式则是组织和重用以上的重要工具。不是使用重复的标记填充XAML, 通过Styles创建一系列封装所有这些细节的样式。然后通过元素的Style属性设定其样式。
触发器介绍:
触发器可以理解为, 当达到了触发的条件, 那么就执行预期内的响应, 可以是样式、数据变化、动画等。触发器通过 Style.Triggers集合连接到样式中, 每个样式都可以有任意多个触发器, 并且每个触发器都是 System.Windows.TriggerBase的派生类实例, 以下是触发器的类型:
Trigger : 监测依赖属性的变化、触发器生效
MultiTrigger : 通过多个条件的设置、达到满足条件、触发器生效
DataTrigger : 通过数据的变化、触发器生效
MultiDataTrigger : 多个数据条件的触发器
EventTrigger : 事件触发器, 触发了某类事件时, 触发器生效。
控件模板介绍:
控件模板(ControlTemplate)不仅是用于来定义控件的外观、样式, 还可通过控件模板的触发器(ControlTemplate.Triggers)修改控件的行为、响应动画等。
案例
<Window x:Class="CrazyElephant.Client.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{Binding Restaurant.Name, StringFormat=\{0\}-在线订餐}" Height="600" Width="1000"
WindowStartupLocation="CenterScreen">
<Border BorderBrush="Orange" BorderThickness="3" CornerRadius="6" Background="Yellow">
<Grid x:Name="Root" Margin="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border BorderBrush="Orange" BorderThickness="1" CornerRadius="6" Padding="4">
<StackPanel>
<StackPanel Orientation="Horizontal">
<StackPanel.Effect>
<DropShadowEffect Color="LightGray" />
</StackPanel.Effect>
<TextBlock Text="欢迎光临-" FontSize="60" FontFamily="LiShu" />
<TextBlock Text="{Binding Restaurant.Name}" FontSize="60" FontFamily="LiShu" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="小店地址:" FontSize="24" FontFamily="LiShu" />
<TextBlock Text="{Binding Restaurant.Address}" FontSize="24" FontFamily="LiShu" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="订餐电话:" FontSize="24" FontFamily="LiShu" />
<TextBlock Text="{Binding Restaurant.PhoneNumber}" FontSize="24" FontFamily="LiShu" />
</StackPanel>
</StackPanel>
</Border>
<DataGrid AutoGenerateColumns="False" GridLinesVisibility="None" CanUserDeleteRows="False"
CanUserAddRows="False" Margin="0,4" Grid.Row="1" FontSize="16" ItemsSource="{Binding DishMenu}">
<DataGrid.Columns>
<DataGridTextColumn Header="菜品" Binding="{Binding Dish.Name}" Width="120" />
<DataGridTextColumn Header="种类" Binding="{Binding Dish.Category}" Width="120" />
<DataGridTextColumn Header="点评" Binding="{Binding Dish.Comment ,UpdateSourceTrigger=PropertyChanged}" Width="120" />
<DataGridTextColumn Header="推荐分数" Binding="{Binding Dish.Score}" Width="120" />
<DataGridTemplateColumn Header="选中" SortMemberPath="IsSelected" Width="120">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" HorizontalAlignment="Center"
Command="{Binding Path=DataContext.SelectMenuItemCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="2">
<TextBlock Text="共计" VerticalAlignment="Center" />
<TextBox IsReadOnly="True" TextAlignment="Center" Width="120" Text="{Binding Count}" Margin="4,0" />
<Button Content="Order" Height="24" Width="120" Command="{Binding PlaceOrderCommand}" />
</StackPanel>
</Grid>
</Border>
</Window>
namespace CrazyElephant.Client
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.ViewModel;
using CrazyElephant.Client.Models;
using CrazyElephant.Client.Services;
using Microsoft.Practices.Prism.Commands;
using System.Windows;
namespace CrazyElephant.Client.ViewModels
{
class MainWindowViewModel : NotificationObject
{
public DelegateCommand PlaceOrderCommand { get; set; }
public DelegateCommand SelectMenuItemCommand { get; set; }
private int count;
public int Count
{
get { return count; }
set
{
count = value;
this.RaisePropertyChanged("Count");
}
}
private Restaurant restaurant;
public Restaurant Restaurant
{
get { return restaurant; }
set
{
restaurant = value;
this.RaisePropertyChanged("Restaurent");
}
}
private List<DishMenuItemViewModel> dishMenu;
public List<DishMenuItemViewModel> DishMenu
{
get { return dishMenu; }
set
{
dishMenu = value;
this.RaisePropertyChanged("DishMenu");
}
}
public MainWindowViewModel()
{
this.LoadRestaurant();
this.LoadDishMenu();
this.PlaceOrderCommand = new DelegateCommand(new Action(this.PlaceOrderCommandExecute));
this.SelectMenuItemCommand = new DelegateCommand(new Action(this.SelectMenuItemExecute));
}
private void LoadRestaurant()
{
this.Restaurant = new Restaurant();
this.Restaurant.Name = "Crazy大象";
this.Restaurant.Address = "北京市海淀区万泉河路紫金庄园1号楼 1层 113室(亲们:这地儿特难找!)";
this.Restaurant.PhoneNumber = "15210365423 or 82650336";
}
private void LoadDishMenu()
{
IDataService ds = new XmlDataService();
var dishes = ds.GetAllDishes();
this.DishMenu = new List<DishMenuItemViewModel>();
foreach (var dish in dishes)
{
DishMenuItemViewModel item = new DishMenuItemViewModel();
item.Dish = dish;
this.DishMenu.Add(item);
}
}
private void PlaceOrderCommandExecute()
{
var selectedDishes = this.DishMenu.Where(i => i.IsSelected == true).Select(i => i.Dish.Name).ToList();
IOrderService orderService = new MockOrderService();
orderService.PlaceOrder(selectedDishes);
MessageBox.Show("订餐成功!");
}
private void SelectMenuItemExecute()
{
this.Count = this.DishMenu.Count(i => i.IsSelected == true);
}
}
}
XAML 介绍
可以说是用WPF创建应用程序必不可少的最基本的知识就是XAML 。理解它是 HTML的标记符号,用户定义WPF程序页面
xmlns 标记
“xmlns:mc=”为例,“mc”为前缀。,前缀名称 = 的右侧指定命名空间。前缀名称(类似于使用别名)可以为前缀指定任何名称。
在XAML主体中使用xmlns中指定的前缀时,使用“mc:Ignorable”=“ prefix:class name(property) ”的格式。
<Window 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">
XAML = “CLR 对象的实例化”
XAML 摸板中的元素 ,都是(CLR 对象)标记语言创建一个对象C#实例,因此使用XAML进行页面元素的描述来构建PWF页面内容。
定义一个CLR 类
using System.IO;
using System.Windows.Markup;
namespace Sample{
public class Point{
public int X { get; set; }
public int Y { get; set; }
}
}
class Program{
static void Main(string[] args){
var x = new Sample.Point { X = 1, Y = 2 };
using (var stream = File.Open("test.xaml", FileMode.Create))
XamlWriter.Save(x, stream);
}
}
xaml引入这个CLR描述
<Point X="1" Y="2"
xmlns="clr-namespace:Sample;assembly=SampleLibrary" />
相反,要从 XAML 代码反序列化为 CLR 对象,请使用 XamlReader.Load 方法
**XAML中元素对应CLR **
创建用户定义类“Point”( XAML 代码中的 元素)的实例(= CLR 对象)的示例。
<Point X="1" Y="2"
xmlns="clr-namespace:Sample;assembly=SampleLibrary" />
↑ 项目自定义的C#类 Sample.Point 与XAML标记关系 X,y 传递参数
var obj = new Sample.Point{
X = 1,
Y = 2
}
XML 命名空间(xmlns 属性)= CLR 命名空间 + 程序集信息
XML 元素名称 = CLR 类名称
XML 属性 = CLR 对象属性值设置(属性语法)
System.Uri 类的实例化示例
Uri 类(系统命名空间)(来自 XAML 代码中的 元素)的实例(= CLR 对象)的示例。
< Uri xmlns = "clr-namespace: System ; assembly = System">
http://www.atmarkit.co.jp/ </Uri>
var converter = new System.UriTypeConverter();
var obj = converter.ConvertFrom("http://www.atmarkit.co.jp/");
// ↑System.Uri类(=<Uri>元素)包含
// [TypeConverter(typeof(UriTypeConverter))]带属性
XAML 代码中每个元素的字符串根据分配到的CLR 类中的 TypeConverter 属性值进行传递参数。例如,根据给定的TypeConverter属性的“UriTypeConverter”,将XAML代码中元素的字符串转换为C#代码中Uri类的一个实例(=CLR对象)到 Uri 类.
TreeView
简单的方式
<Window x:Class="WpfTutorialSamples.TreeView_control.TreeViewSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TreeViewSample" Height="200" Width="250">
<Grid Margin="10">
<TreeView>
<TreeViewItem Header="Level 1" IsExpanded="True">
<TreeViewItem Header="Level 2.1" />
<TreeViewItem Header="Level 2.2" IsExpanded="True">
<TreeViewItem Header="Level 3.1" />
<TreeViewItem Header="Level 3.2" />
</TreeViewItem>
<TreeViewItem Header="Level 2.3" />
</TreeViewItem>
</TreeView>
</Grid>
</Window>
我们只是直接在 XAML 中声明 TreeViewItem 对象,在我们想要显示它们的相同结构中,其中第一个标记是 TreeView 控件的子项,其子对象也是其父对象的子标记。为了指定我们想要为每个节点显示的文本,我们使用Header属性。默认情况下,TreeViewItem 不会展开,但为了向您展示示例的结构,我使用了 IsExpanded属性来展开两个父项。
带有图像和其他控件的 TreeViewItem
不过,Header是一个有趣的属性。正如你所看到的,我可以只指定一个文本字符串,然后直接渲染它而不做任何其他事情,但这是 WPF 对我们很好 - 在内部,它将文本包装在 TextBlock 控件中,而不是强迫你做它。这向我们表明,我们可以将几乎任何我们想要的内容填充到 Header 属性中,而不仅仅是一个字符串,然后让 TreeView 呈现它 - 一个很好的例子,说明了为什么自定义 WPF 控件的外观如此容易。
来自 WinForms 甚至其他 UI 库的人们的常见要求之一是能够在 TreeView 项的文本标签旁边显示图像。使用 WinForms 很容易做到这一点,因为 TreeView 正是为此场景构建的。使用 WPF 树视图,它有点复杂,但您获得的灵活性比从 WinForms 树视图中获得的要多得多。这是一个例子:
<Window x:Class="WpfTutorialSamples.TreeView_control.TreeViewCustomItemsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TreeViewCustomItemsSample" Height="200" Width="250">
<Grid Margin="10">
<TreeView>
<TreeViewItem IsExpanded="True">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_blue.png" />
<TextBlock Text="Level 1 (Blue)" />
</StackPanel>
</TreeViewItem.Header>
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Level 2.1" Foreground="Blue" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem IsExpanded="True">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/bullet_green.png" />
<TextBlock Text="Level 2.2 (Green)" Foreground="Blue" />
</StackPanel>
</TreeViewItem.Header>
<TreeViewItem>
<TreeViewItem.Header>
<TextBlock Text="Level 3.1" Foreground="Green" />
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<TextBlock Text="Level 3.2" Foreground="Green" />
</TreeViewItem.Header>
</TreeViewItem>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<TextBlock Text="Level 2.3" Foreground="Blue" />
</TreeViewItem.Header>
</TreeViewItem>
</TreeViewItem>
</TreeView>
</Grid>
</Window>
我在这里做了很多事情,只是为了向您展示您获得的灵活性:我为子项着色,并为父项添加了图像甚至按钮。因为我们使用简单的标记来定义整个事物,所以您几乎可以做任何事情,但是正如您从示例代码中看到的那样,它确实有代价:大量的 XAML 代码,对于总共只有六个节点的树!
TreeView、数据绑定和多个模板
WPF TreeView 支持数据绑定,就像几乎所有其他 WPF 控件一样,但是因为 TreeView 本质上是分层的,所以普通的 DataTemplate 通常是不够的。相反,我们使用 HierarchicalDataTemplate,它允许我们对树节点本身进行模板化,同时控制将哪个属性用作节点子项的源。
一个基本的数据绑定 TreeView
<Window x:Class="WpfTutorialSamples.TreeView_control.TreeViewDataBindingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:WpfTutorialSamples.TreeView_control"
Title="TreeViewDataBindingSample" Height="150" Width="200">
<Grid Margin="10">
<TreeView Name="trvMenu">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type self:MenuItem}" ItemsSource="{Binding Items}">
<TextBlock Text="{Binding Title}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.IO;
using System.Collections.ObjectModel;
namespace WpfTutorialSamples.TreeView_control
{
public partial class TreeViewDataBindingSample : Window
{
public TreeViewDataBindingSample()
{
InitializeComponent();
MenuItem root = new MenuItem() { Title = "Menu" };
MenuItem childItem1 = new MenuItem() { Title = "Child item #1" };
childItem1.Items.Add(new MenuItem() { Title = "Child item #1.1" });
childItem1.Items.Add(new MenuItem() { Title = "Child item #1.2" });
root.Items.Add(childItem1);
root.Items.Add(new MenuItem() { Title = "Child item #2" });
trvMenu.Items.Add(root);
}
}
public class MenuItem
{
public MenuItem()
{
this.Items = new ObservableCollection<MenuItem>();
}
public string Title { get; set; }
public ObservableCollection<MenuItem> Items { get; set; }
}
}
在 XAML 标记中,我为TreeView的ItemTemplate指定了一个 HierarchicalDataTemplate 。我指示它使用 Items属性来查找子项,方法是设置模板的ItemsSource属性,并在其中定义实际模板,现在它只包含一个绑定到Title属性的 TextBlock 。
第一个示例非常简单,实际上非常简单,我们不妨手动添加 TreeView 项,而不是生成一组对象然后绑定到它们。然而,一旦事情变得更加复杂,使用数据绑定的优势就会变得更加明显。
不同类型的多个模板
在下一个示例中,我采用了一个稍微复杂一些的案例,我想在其中展示一棵家庭及其成员的树。一个家庭应该以一种方式表示,而它的每个成员都应该以另一种方式表示。我通过创建两个不同的模板并将它们指定为树(或窗口或应用程序 - 这真的取决于您)的资源来实现这一点,然后允许 TreeView 根据基础数据类型选择正确的模板。
这是代码 - 它的解释将紧随其后:
<Window x:Class="WpfTutorialSamples.TreeView_control.TreeViewMultipleTemplatesSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:WpfTutorialSamples.TreeView_control"
Title="TreeViewMultipleTemplatesSample" Height="200" Width="250">
<Grid Margin="10">
<TreeView Name="trvFamilies">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type self:Family}" ItemsSource="{Binding Members}">
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/group.png" Margin="0,0,5,0" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" [" Foreground="Blue" />
<TextBlock Text="{Binding Members.Count}" Foreground="Blue" />
<TextBlock Text="]" Foreground="Blue" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:FamilyMember}" ItemsSource="{Binding Members}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" [" Foreground="Blue" />
<TextBlock Text="{Binding Members.Count}" Foreground="Blue" />
<TextBlock Text="]" Foreground="Blue" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type self:FamilyMember}">
<StackPanel Orientation="Horizontal">
<Image Source="/WpfTutorialSamples;component/Images/user.png" Margin="0,0,5,0" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" (" Foreground="Green" />
<TextBlock Text="{Binding Age}" Foreground="Green" />
<TextBlock Text=" years)" Foreground="Green" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Collections.ObjectModel;
namespace WpfTutorialSamples.TreeView_control
{
public partial class TreeViewMultipleTemplatesSample : Window
{
public TreeViewMultipleTemplatesSample()
{
InitializeComponent();
List<Family> families = new List<Family>();
Family family1 = new Family() { Name = "The Doe's" };
family1.Members.Add(new FamilyMember() { Name = "John Doe", Age = 42 });
family1.Members.Add(new FamilyMember() { Name = "Jane Doe", Age = 39 });
family1.Members.Add(new FamilyMember() { Name = "Sammy Doe", Age = 13 });
families.Add(family1);
Family family2 = new Family() { Name = "The Moe's" };
family2.Members.Add(new FamilyMember() { Name = "Mark Moe", Age = 31 });
family2.Members.Add(new FamilyMember() { Name = "Norma Moe", Age = 28 });
families.Add(family2);
trvFamilies.ItemsSource = families;
}
}
public class Family
{
public Family()
{
this.Members = new ObservableCollection<FamilyMember>();
}
public string Name { get; set; }
public ObservableCollection<FamilyMember> Members { get; set; }
}
public class FamilyMember
{
public string Name { get; set; }
public int Age { get; set; }
}
}
如前所述,这两个模板被声明为 TreeView 资源的一部分,允许 TreeView 根据即将显示的数据类型选择适当的模板。为Family类型定义的模板是一个分层模板,使用Members 属性来显示其家庭成员。
为FamilyMember类型定义的模板是常规 DataTemplate,因为此类型没有任何子成员。但是,如果我们希望每个 FamilyMember 都保留他们的孩子以及他们孩子的孩子的集合,那么我们将改用分层模板。
在这两个模板中,我们使用代表家庭或家庭成员的图像,然后我们还展示了一些关于它的有趣数据,例如家庭成员的数量或人的年龄。文章来源:https://www.toymoban.com/news/detail-460956.html
在代码隐藏中,我们简单地创建两个 Family 实例,用一组成员填充每个实例,然后将每个系列添加到一个列表中,然后将其用作 TreeView 的项目源。文章来源地址https://www.toymoban.com/news/detail-460956.html
到了这里,关于WPF入门基础的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!