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是對數據的模板化封裝。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM