wpf中数据的外衣DataTemplate的应用

 

在WPF中,通过引入模版将数据和算法的“内容” 与“形式”解隅了,WPF中木板可以分为两大类

  •   ContrlTemplate是算法内容的表现形式,一个控件怎么样去组织他的内部结构才能符合他的逻辑、让用户体验起来更舒服,他可以让程序员在内部逻辑的基本之上去扩展自己的逻辑。
  •      DataTemplate是数据内容的表现形式,一条数据显示成什么样子,是简单的文本呢,还是具有直观的动画效果等等都是由他来控制的。

换句话说  Template就是木板,也可以称作“外衣”,而ContrlTemplate是控件的外衣,DataTemplate是数据的外衣,下面我们就看看数据外衣的一个实列。我们要做成下图的一个 列子。

从上面的图片中我们可以了解到,最右边是一个面板,面板中存放的是一些格式相同的数据,而左边的部分显示的明细,我们可以想象出来是点击右边的内容,左边的框框展示详细的信息,这些都是我们看到上图之后的猜想,具体是什么呢?右边是一个listbox 存放logo图,以及名称,年份等信息,右边是具体的详细信息

      肯定有不少同学会想到这个可以用用户控件啊,这些不就是“数据-视图”吗?视图的话不就是靠userControl来实现嘛?是的,你想的是对的,但是我要说的是WPF不仅支持UserControl还可以支持DataTemplate的视图为数据形成视图。DataTemplate是什么呢?我个人感觉就是UserControl,内容基本都是一样的,升级版本,从UserControl到DataTemplate也就是复制,再改几个数据绑定的字符串(个人理解),没什么不同的。

      在DataTemplate中常常用到的3个地方

  1. ContentControl中的ContentTemplate属性,就是模板的意思,相当于给ContentControl的内容穿外衣
  2. itemsControl中的ItemTemplate属性,和上面是一样的意思,相当于给itemsControl的数据穿上外衣
  3. GridViewColumn中CellTemplate属性,相当于给GridViewColumn的数据穿上外衣

上面的我们先以用户控件的形式实现:

先建一个汽车类,其中包含下面一些属性

public class Car
    {
        public string AutoMark { get; set; }
        public string Name { get; set; }
        public string Year { get; set; }
        public string Speed { get; set; }
    }

看上面的图中,我们可以发现右边的内容是一个listbox,里面有一个用户控件CarListItemView,包含图片和内容的用户控件,代码如下

<UserControl x:Class="WpfApplication4.CarListItemView"
             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" >
    <Grid Margin="2">
        <StackPanel Orientation="Horizontal">
            <Image Width="64" Height="64" Name="imageLogo"></Image>
            <StackPanel Margin="5,10">
                <TextBlock Name="txtBlockName" FontSize="16" FontWeight="Bold"></TextBlock>
                <TextBlock Name="txtBlockYear" FontSize="16" FontWeight="Bold"></TextBlock>
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>
///下面是后台代码

 private Car car;

 public Car Car {

            get { return car; }          

   set {      car = value;                    

this.txtBlockName.Text = car.Name;                 

    this.txtBlockYear.Text = car.Year;              

       string uriStr = string.Format(@"/pic/logo/{0}.jpg", car.AutoMark) ;                   

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

    }                

}

右边的内容也是一个模板

<UserControl x:Class="WpfApplication4.CarDetailView"
             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" 
             >
    <Border BorderBrush="Aquamarine" BorderThickness="1" CornerRadius="6">
        <StackPanel Margin="5">
            <Image Width="500" Height="300" Name="image"></Image>
            <StackPanel Margin="5,0" Orientation="Horizontal">
                <TextBlock Text="Name:" FontWeight="Bold" FontSize="20"></TextBlock>
                <TextBlock Name="txtName" FontSize="20" Margin="5,0"></TextBlock>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="5,0">
                <TextBlock Text="AutoMark:" FontWeight="Bold" FontSize="20"></TextBlock>
                <TextBlock Name="txtAutoMark" FontWeight="Bold" FontSize="20" Margin="5,0"></TextBlock>
                <TextBlock Text="Year:" FontWeight="Bold" FontSize="20"></TextBlock>
                <TextBlock Name="txtYear" FontWeight="Bold" FontSize="20" Margin="5,0"></TextBlock>
                <TextBlock Text="ToSpeed:" FontWeight="Bold" FontSize="20"></TextBlock>
                <TextBlock Name="txtToSpeed" FontWeight="Bold" FontSize="20" Margin="5,0"></TextBlock>
            </StackPanel>
        </StackPanel>
    </Border>
</UserControl>


2个用户控件创建完之后,我们就可以使用组装了,首先分成2块,第一块左边放的是详细信息,右边其实就是一个listbox,listbox的item就是CarListItemView,所以下面我们的主窗口代码就不难写了

<Window x:Class="WpfApplication4.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:loc="clr-namespace:WpfApplication4"
        Title="Window1" Height="440" Width="720">
    <StackPanel Margin="5" Orientation="Horizontal">
        <loc:CarDetailView x:Name="detailView">
            
        </loc:CarDetailView>
        <ListBox x:Name="listCar" Width="160" Margin="5,0" SelectionChanged="listCar_SelectionChanged">
            
        </ListBox>
    </StackPanel>
</Window>

后台代码:

 public void init()
        {
            List<Car> list = new List<Car>() {
              new Car(){ AutoMark="bieke", Name="bieke", Speed="200", Year="1938"},
              new Car(){ AutoMark="bmw", Name="bmw", Speed="240", Year="1998"},
              new Car(){ AutoMark="dazhong", Name="dazhong", Speed="130", Year="1948"},
              new Car(){ AutoMark="jiebao", Name="jiebao", Speed="300", Year="1998"},
              new Car(){ AutoMark="lotus", Name="lotus", Speed="500", Year="1968"}
            
            };

            foreach(Car  car in list){
                CarListItemView carDetai = new CarListItemView();
                carDetai.Car = car;
                this.listCar.Items.Add(carDetai);
            
            }


        }

        private void listCar_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            CarListItemView item = e.AddedItems[0] as CarListItemView;
            if (item!=null)
            {
                detailView.Car = item.Car;
            }

        }

这样程序就写完了,运行看看效果哦。

其实在wpf中最最核心的东西还是数据绑定,和路由事件,我们不需要像传统的形式那样浪费wpf中数据驱动界面的重要功能,这种方法完全没有借助与wpf中Bingding实现数据驱动界面,上面的列子中我们必须借助listBox事件去推动CarDetailView的数据显示,这种模式叫事件驱动(控件与控件之间的沟通),下面我们要使用DataTemplate的数据驱动模式(数据与控件之间的沟通,是由内容决定的)代码其实就是userControl的代码,只是稍加改动。

<Window x:Class="WpfApplication4.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:loc="clr-namespace:WpfApplication4"
        Title="Window2" Height="440" Width="720">
    <Window.Resources>
        <loc:AutoMarkToLogoPathConver x:Key="logoPath"></loc:AutoMarkToLogoPathConver>
        <loc:NameToPhotoPathConver  x:Key="imagePath"></loc:NameToPhotoPathConver>
        <DataTemplate  x:Key="CarDetailTemplate">
            <Border BorderBrush="Aquamarine" BorderThickness="1" CornerRadius="6">
                <StackPanel Margin="5">
                    <Image Width="500" Height="300" Name="image" Source="{Binding Name, Converter={StaticResource ResourceKey= imagePath}}"></Image>
                    <StackPanel Margin="5,0" Orientation="Horizontal">
                        <TextBlock Text="Name:" FontWeight="Bold" FontSize="20"></TextBlock>
                        <TextBlock Name="txtName" FontSize="20" Margin="5,0" Text="{Binding Name}"></TextBlock>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="5,0">
                        <TextBlock Text="AutoMark:" FontWeight="Bold" FontSize="20"></TextBlock>
                        <TextBlock Name="txtAutoMark" FontWeight="Bold" FontSize="20" Margin="5,0" Text="{Binding AutoMark}"></TextBlock>
                        <TextBlock Text="Year:" FontWeight="Bold" FontSize="20"></TextBlock>
                        <TextBlock Name="txtYear" FontWeight="Bold" FontSize="20" Margin="5,0" Text="{Binding Year}"></TextBlock>
                        <TextBlock Text="ToSpeed:" FontWeight="Bold" FontSize="20"></TextBlock>
                        <TextBlock Name="txtToSpeed" FontWeight="Bold" FontSize="20" Margin="5,0" Text="{Binding Speed}"></TextBlock>
                    </StackPanel>
                </StackPanel>
            </Border>
        </DataTemplate>
        <DataTemplate x:Key="CarListItemTemplate">
            <Grid Margin="2">
                <StackPanel Orientation="Horizontal">
                    <Image Width="64" Height="64" Name="imageLogo" Source="{Binding Name, Converter={StaticResource ResourceKey=logoPath}}"></Image>
                    <StackPanel Margin="5,10">
                        <TextBlock Name="txtBlockName" FontSize="16" FontWeight="Bold" Text="{Binding Name}"></TextBlock>
                        <TextBlock Name="txtBlockYear" FontSize="16" FontWeight="Bold" Text="{Binding Year}"></TextBlock>
                    </StackPanel>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    
    <StackPanel Orientation="Horizontal" Margin="5">
        <UserControl ContentTemplate="{StaticResource ResourceKey=CarDetailTemplate}" Content="{Binding SelectedItem, ElementName=listBoxCar}">
            
        </UserControl>
        <ListBox x:Name="listBoxCar" Width="180" Margin="0,5" ItemTemplate="{StaticResource ResourceKey=CarListItemTemplate}">
            
        </ListBox>
    </StackPanel>
    
</Window>
View Code
 public class AutoMarkToLogoPathConver : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {

          return new BitmapImage(new Uri(string.Format(@"/pic/logo/{0}.jpg", value.ToString()), UriKind.Relative));

        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class NameToPhotoPathConver : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return new BitmapImage(new Uri(string.Format(@"/pic/img/{0}.jpg", value.ToString()), UriKind.Relative));
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

这里需要解释一下,这上面2个类,图片的image,而上面Car类中全是string类型,这样无法实现图片的展示,那我们该这么做呢,这时候需要用到Converter?在wpf中有一种类型转换,只要实行IValueConverter接口就可以了。在xmal中这样用Source="{Binding Name, Converter={StaticResource ResourceKey= imagePath}}",在这句代码中我们可以看出来,绑定是Name这个属性,然后通过Converter,把它转换成image的形式,其实Name的属性还是string,根本就没影响本身的Name属性,怎么样很强大吧。
大概理解的就这么多。呵呵。。。。。

需要源代码的来这里下载。

http://download.csdn.net/detail/hanhaijin_007/4829584

 

 

posted @ 2012-11-30 11:46  Joly-Han  阅读(422)  评论(0编辑  收藏  举报