WPF中的自定义控件模板

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

开发工具与关键技术:Visual Studio 2017、模板

作者:邓崇富

撰写时间:2019 年 5 月 24 日

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在WPF中,通过引入模板(Template)微软将数据和算法的“内容”与“形式”解耦了。WPF中的Template分为两大类:

  1. ControlTemplate是算法内容的表现形式,一个控件怎样组织其内部结构才能让它更符合业务逻辑、让客户操作起来更加舒服就是由它来控制的。他决定了控件“长成什么样子”,并让程序员有机会在控件原有的内部逻辑基础上扩展自己的逻辑。
  2. DataTemplate是数据内容的表现形式,一条数据显示成什么样子,是简单的文本还是直观的图形动画就由它来决定。

总而言之,Template就是“外衣”,ControlTemplate是控件的外衣,DataTemplate是数据的外衣。

数据的外衣(DataTemplate):

DataTemplate常用的地方有3个,分别是:

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

下面用个例子来对比UserControl与DataTemplate的使用。假如有一列汽车的数据,这列数据显示在ListBox里,要求ListBox的条目显示汽车的厂商图标和简要的参数,单击某个条目后在窗体的详细内容区域显示汽车的图片和详细参数。

首先要为在项目里建立资源管理目录并把图片添加进来。Logo的文件名与厂商名称要一致,照片的文件名则与车名一致,因为无论是使用UserControl还是DataTemplate,厂商的Logo和汽车的照片都要用到的。

文件结构如下图:

首先创建一个Car数据类型的类文件:

namespace WPF练习

{

   public class Car

    {

        public string Automaker { get; set; }

        public string Name { get; set; }

        public string Year { get; set; }

        public string TopSpeed { get; set; }

    }

}

为了在ListBox里显示Car类型数据,我们需要创建一个UserControl,命名为CarListItemView。这个UserControl由一个Car类型实例在背后支持,当设置这个实例的时候,界面元素将实例的属性值显示在各个控件里。CarListItemView的XAML的代码如下:

<UserControl x:Class="WPF练习.CarListItemView"

             <!--省略了两个命名空间-->

    <Grid Margin="2">

        <StackPanel Orientation="Horizontal">

            <Image x:Name="ImageLogos" Grid.RowSpan="3" Width="64" Height="64"/>

            <StackPanel Margin="5,10">

                <TextBlock x:Name="textBlockName" FontSize="16" FontWeight="Bold"/>

                <TextBlock x:Name="textBlockYear" FontSize="14"/>

            </StackPanel>

        </StackPanel>

    </Grid>

</UserControl>

CarListItemView界面的后台代码如下:

public partial class CarListItemView : UserControl

    {

        public CarListItemView()

        {

            InitializeComponent();

        }

        private Car car;

        public Car Car

        {

            get { return car; }

            set

            {

                car = value;

                this.textBlockName.Text = car.Name;

                this.textBlockYear.Text = car.Year;

                string uriStr = string.Format(@"/Pitrues/Logos/{0}.PNG", car.Automaker);

                this.ImageLogos.Source = new BitmapImage(new Uri(uriStr, UriKind.Relative));

            }

        }

    }

类似于上面的原理,还需要为Car类型数据准备一个详细信息的视图,在创建一个UserControl命名为CarDetailView, XAML代码如下:

<UserControl x:Class="WPF练习.CarDetailView"

            <!--此处省略了两个命名空间-->

 

    <Border BorderBrush ="Black" BorderThickness="1" CornerRadius="6">

        <StackPanel Margin="5">

            <Image x:Name="ImagePhoto" Width="400" Height="250"/>

            <StackPanel Orientation="Horizontal" Margin="5,0">

                <TextBlock Text="Name:" FontWeight="Bold" FontSize="20"/>

                <TextBlock x:Name="textBlockName" FontSize="20" Margin="5,0"/>

            </StackPanel>

            <StackPanel Orientation="Horizontal" Margin="5,0">

                <TextBlock Text="Automaker:" FontWeight="Bold"/>

                <TextBlock x:Name="textBlockAutomaker" Margin="5,0"/>

                <TextBlock Text="Year:" FontWeight="Bold"/>

                <TextBlock x:Name="textBlockYear" Margin="5,0"/>

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

                <TextBlock x:Name="textBlockTopSpeed" Margin="5,0"/>

            </StackPanel>

        </StackPanel>

    </Border>

</UserControl>

XAML的后台代码:

public partial class CarDetailView : UserControl

    {

        public CarDetailView()

        {

            InitializeComponent();

        }

        private Car car;

        public Car Car

        {

            get { return car; }

            set

            {

                car = value;

                this.textBlockName.Text = car.Name;

                this.textBlockYear.Text = car.Year;

                this.textBlockTopSpeed.Text = car.TopSpeed;

                this.textBlockAutomaker.Text = car.Automaker;

                string uriStr = string.Format(@"/Pitrues/Images/{0}.jpg", car.Name);

                this.ImagePhoto.Source = new BitmapImage(new Uri(uriStr, UriKind.Relative));

            }

        }

}

最后把上面两个界面组装到主窗体上,下面是组窗体的XAML代码:

<Window x:Class="WPF练习.Window8"

       <!--此处省略里四个命名空间-->

        xmlns:local="clr-namespace:WPF练习"

        mc:Ignorable="d"

        Title="Window8" Height="350" Width="623">

    <StackPanel Orientation="Horizontal" Margin="5">

        <local:CarDetailView x:Name="detailView"/>

        <ListBox x:Name="ListBoxCars" Width="180" Margin="5,0" SelectionChanged="listBoxCars_SelectionChanged"/>

    </StackPanel>

</Window>

下面是组窗体的后台代码:

public partial class Window8 : Window

    {

        public Window8()

        {

            InitializeComponent();

            InitialCarList();

        }

        private void InitialCarList()

        {

            List<Car> carList = new List<Car>()

            {

                new Car(){Automaker = "Lamborghini",Name = "Diablo",Year = "1990",TopSpeed = "340"},

                new Car(){Automaker = "Lamborghini",Name = "Murcielago",Year = "2001",TopSpeed = "353"},

                new Car(){Automaker = "Lamborghini",Name = "Gallardo",Year = "2003",TopSpeed = "325"},

                new Car(){Automaker = "Lamborghini",Name = "Reventon",Year = "2008",TopSpeed = "356"}

 

            };

            foreach (Car car in carList)

            {

                CarListItemView view = new CarListItemView();

                view.Car = car;

                this.ListBoxCars.Items.Add(view);

            }

        }

        //选项变化事件的处理器

        private void listBoxCars_SelectionChanged(object sender,SelectionChangedEventArgs e)

        {

            CarListItemView view = e.AddedItems[0] as CarListItemView;

            if (view != null)

            {

                this.detailView.Car = view.Car;

            }

        }

}

运行后单击ListBox里的条目,效果图如下:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值