WPF中的自定义控件模板

    xiaoxiao2022-07-14  157

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

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

    作者:邓崇富

    撰写时间:2019 年 5 月 24 日

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

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

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

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

    数据的外衣(DataTemplate):

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

    ContentControl的ContentTemplate属性,相当于给ContentControl的内容穿衣服。ItemsControl的ItemTemplate属性,相当于给ItemsControl的数据条目穿衣服。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)