• WPF中UserControl和DataTemplate


    最新更新: http://denghejun.github.io

    前言

      前言总是留给我说一些无关主题的言论,WPF作为全新Microsoft桌面或web应用程序显示技术框架,

          从08年开始,一直到现在,我也是在工作第一年后尝试去了解。且在网上也有很多对于该技术框架的

      评论,有好也有坏的,有一部分同学说WPF只是在刚出来的时候才火,后边就落寞了,且现在国内外

          通过WPF做出来的大型应用也没多少;另外一部分同学则认为,技术不论好坏,存在即合理,学习WPF

      一定不会亏。不知道你们是怎么想的。我是觉得,本身对技术方面比较感兴趣,有时候会有自己的想法

      来做一些东西,所以学习它会让我在想要做些东西的时候能有可用的技术,或是当别人谈及此事的时候,

      至少我还知道。

    UserControl

      做过web开发或是winform的同学都知道,UserControl即是用户控件,是程序员根据需要自定义的一组

      控件集合。WPF中当然也有,相比起来,更为简单,如下将会是一个简单的定义UserControl和使用的例子。

      

    大概要实现的UI是这样子的,右边的是一组在ListBox内的CarItem集合,点击后在左边显示对应大图。

    首先我们定义Car数据结构:

    1    // 简单起见,就一个Name属性
    2    public class MCar
    3     {
    4         public string Name { get; set; }
    5     }

      接下来,设计右边的ItemTemplate,使用UserControl的方式,以下依次是UserControl的XAML和后台逻辑。

    <UserControl x:Class="WPFUserControl.CarsView.MainForm.CarItem"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <StackPanel>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition ></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="60"></ColumnDefinition>
                    <ColumnDefinition Width="1*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Image Grid.Row="0" Grid.Column="0" x:Name="imgLogo"  ></Image>
                <TextBlock Grid.Row="0" Grid.Column="1" x:Name="tbName"></TextBlock>
            </Grid>
        </StackPanel>
    </UserControl>
     1 /// <summary>
     2     /// CarItem.xaml 的交互逻辑
     3     /// </summary>
     4     public partial class CarItem : UserControl
     5     {
     6         private MCar car;
     7         public CarItem()
     8         {
     9             InitializeComponent();
    10         }
    11 
    12         public MCar Car
    13         {
    14             get { return this.car; }
    15             set
    16             {
    17                 this.car = value;
    18                 if (this.car == null)
    19                 {
    20                     return;
    21                 }
    22 
    23                 this.tbName.Text = this.car.Name;
    24                 string uriStr = string.Format(@"/images/car/{0}.png", this.car.Name);
    25                 this.imgLogo.Source = new BitmapImage(new Uri(uriStr, UriKind.Relative));
    26             }
    27         }
    28     }

      然后是左边的详细模板,同样采用UserControl的方式:

    <UserControl x:Class="WPFUserControl.CarsView.MainForm.CarDetail"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <StackPanel>
            <Image x:Name="imgCarDetail"></Image>
        </StackPanel>
    </UserControl>
     1   /// <summary>
     2     /// CarDetail.xaml 的交互逻辑
     3     /// </summary>
     4     public partial class CarDetail : UserControl
     5     {
     6         private MCar car;
     7         public CarDetail()
     8         {
     9             InitializeComponent();
    10         }
    11 
    12         public MCar Car
    13         {
    14             get { return this.car; }
    15             set
    16             {
    17                 this.car = value;
    18                 if (this.car == null)
    19                 {
    20                     return;
    21                 }
    22 
    23                 string uriStr = string.Format(@"/images/car/{0}.png", this.car.Name);
    24                 this.imgCarDetail.Source = new BitmapImage(new Uri(uriStr, UriKind.Relative));
    25             }
    26         }
    27     }

      最后是主窗体的XAML布局代码:

    <Window x:Class="WPFUserControl.CarsView.MainForm.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:local="clr-namespace:WPFUserControl.CarsView.MainForm"
            Title="WPF_USECONTROL_MAINWINDOWS" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
    
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3*"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <local:CarDetail x:Name="carDetail" Grid.Row="0" Grid.Column="0"></local:CarDetail>
            <ListBox x:Name="lbCarBox" Grid.Row="0" Grid.Column="1"></ListBox>
        </Grid>
    </Window>

      让我们来看看后台的数据绑定是怎样实现的:

     1  /// <summary>
     2     /// MainWindow.xaml 的交互逻辑
     3     /// </summary>
     4     public partial class MainWindow : Window
     5     {
     6         public MainWindow()
     7         {
     8             InitializeComponent();
     9             this.InitializeCarView();
    10         }
    11 
    12         public void InitializeCarView()
    13         {
    14             BCarManagement carManager = new BCarManagement();
    15             List<MCar> carList = carManager.GetCarItemList();
    16             List<CarItem> carItemList = (from c in carList select new CarItem() { Car = c }).ToList();
    17             this.lbCarBox.ItemsSource = carItemList;
    18             this.lbCarBox.SelectionChanged += new SelectionChangedEventHandler((o, e) =>
    19             {
    20                 CarItem item = e.AddedItems[0] as CarItem;
    21                 if (item == null)
    22                 {
    23                     return;
    24                 }
    25 
    26                 this.carDetail.Car = item.Car;
    27             });
    28         }
    29     }

      初一看,和之前的webform或是winform中的用户控件相差无几,基本未用到WPF的一些特性,

      所以WPF中较为重要的Template就是接下来所要提及的。

    DataTemplate

      Template实际上包括DataTemplate和ControlTemplate,ControlTemplate我们将会在下一章节详细介绍,

      这里我们先用DataTemplate来改造之前的UserControl。将UserControl改造为DataTemplate十分简单,

      只需要做部分调整即可,显示效果和前者是一模一样,但是,结构上较之前者来讲,清晰很多,这正是我们想要的。

      我们将DataTemplate统一放到资源字典中,以便在不同的window中作为外部引用:

      

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:local="clr-namespace:WPFDataTemplate.CarsView.MainForm">
        <local:ImgUriConverter x:Key="imgConverter"></local:ImgUriConverter>
        <DataTemplate x:Key="carItemTemplate">
            <StackPanel>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition ></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*"></ColumnDefinition>
                        <ColumnDefinition Width="1*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Image MaxWidth="100" Grid.Row="0" Grid.Column="0" Source="{Binding Name,Converter={StaticResource imgConverter}}" ></Image>
                    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}"></TextBlock>
                </Grid>
            </StackPanel>
        </DataTemplate>
        <DataTemplate x:Key="carDetailTemplate">
            <StackPanel>
                <Image Source="{Binding Name,Converter={StaticResource  imgConverter}}"></Image>
            </StackPanel>
        </DataTemplate>
    </ResourceDictionary>

      以下是MainWindow的XAML代码:

    <Window x:Class="WPFDataTemplate.CarsView.MainForm.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="WPF_DATATEMPLATE_MAINWINDOWS"   Height="350"  Icon="images/car/bc0.png" Width="525"  WindowStyle="None" BorderThickness="0" >
        <Window.Resources>
            <ResourceDictionary Source="CarViewTemplate.xaml"></ResourceDictionary>
        </Window.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="9*"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3*"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <UserControl  Grid.Column="0" Content="{Binding SelectedItem,ElementName=lbCarBox}" ContentTemplate="{StaticResource carDetailTemplate}"></UserControl>
            <ListBox x:Name="lbCarBox" Grid.Row="0" Grid.Column="1" ItemTemplate="{StaticResource carItemTemplate}"></ListBox>
            <Button x:Name="btnOpen" Width="125" Height="20" Grid.Row="1" Grid.Column="1"></Button>
        </Grid>
    </Window>

      其中要注意的地方是,需要提前将外部资源引用进来。

      接下来事ManWindow的分离代码(CodeBehind):

    18     /// <summary>
    19     /// MainWindow.xaml 的交互逻辑
    20     /// </summary>
    21     public partial class MainWindow : Window
    22     {
    23         public MainWindow()
    24         {
    25             InitializeComponent();
    26             this.lbCarBox.ItemsSource = new BCarManagement().GetCarItemList();
    27             this.KeyDown += new KeyEventHandler(MainWindow_KeyDown);
    28             this.MouseDown += new MouseButtonEventHandler(MainWindow_MouseDown);
    29                   }
    30 
    31         void MainWindow_MouseDown(object sender, MouseButtonEventArgs e)
    32         {
    33             if (e.LeftButton == MouseButtonState.Pressed)
    34             {
    35                 this.DragMove();
    36             }
    37         }
    38 
    39         void MainWindow_KeyDown(object sender, KeyEventArgs e)
    40         {
    41             if (e.Key == Key.Escape)
    42             {
    43                 this.Close();
    44             }
    45         }
    46     }

      你只需要关心窗体加载时的初始化函数即可。

      至此,DataTemplate的改造结束。

    小结

      UserControl准确的讲是完全将view与data分离,分别对应在UserControl的XAML代码和CodeBehind代码,是一种显式

      的将数据从UI中移植到后台,实际上他们最终会被编译成同一个类;

      DataTemplate则是利用WPF的数据绑定特性,利用Bind将数据隐式的与XAML结合,是一种对数据如何展示的模板封装,

      其便易性较好。

      其实,UserControl与DataTemplate并无直接关系,UserControl直接体现在Control上,DataTemplate直接体现在

      Template上。从上例中可看出我们将DataTemplate赋值给了UserControl的ContentTemplate属性。所以UserControl

      是宏观上的控件,DataTemplate是对数据的模板化封装。

      

  • 相关阅读:
    光场显微成像----整理
    清华大学自动化系友论坛——光电智能计算:笔记
    大创记录——Day3.12
    2.17UI bug修复
    beta阶段UI界面改进
    关于UI设计的心得体会-alpha和beta交界期间
    1.30进度
    2018.1.28进度更新
    心·迹 项目简介
    项目组成员介绍
  • 原文地址:https://www.cnblogs.com/denghejun/p/3671061.html
Copyright © 2020-2023  润新知