WPF 數據模板


數據模板和控件模板的區別在哪?

控件模板是用來修改某個控件內部的布局結構,不涉及到把一些數據(類對象)綁定到控件模板內部

數據模板是用來定義數據怎么顯示,數據通常是來自數據集合,把一個數據集合和一個集合控件關聯起來,如ListBox,ComboBox,ItemContcrol這種集合形式的控件,數據怎么顯示其實也涉及到布局

可以簡單理解,只修改控件布局,則使用控件模板,如果想把一個集合控件關聯到一個數據集合並自定義顯示的方法,則使用數據模板

1.Datatemplate

舉個簡單的例子,定義一個集合控件ListBox,其中每個數據項是一個TextBlock,TextBlock的Text屬性的值 來自一個數據集合List<string>

先定義一個簡單的數據模板

Xaml代碼:

 <ListBox ItemsSource="{Binding list}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
 </ListBox>

MainWindow代碼:

 public partial class MainWindow : Window
    {
       public List<string> list { get; set; } = new List<string>();
        public MainWindow()
        {
            InitializeComponent();
           
            list.Add("111");
            list.Add("222");
            list.Add("333");
            list.Add("444");
            this.DataContext = this;
        }
    }

運行結果:

 其中的邏輯關系如下:

 每一個ListBoxitem對應一條數據。listboxitem是動態生成的,數據集合list中有多少條數據,listbox就會生成多少個listboxitem。

(當然如果想要實現添加數據,UI界面自動更新,需要使用帶有通知功能的ObservableCollection代替list)

重點是 為什么說數據模板可以定義數據怎么顯示?

還是上面的例子,我們定義了一個簡單的數據模板

<DataTemplate>
  <TextBlock Text="{Binding}"/>
</DataTemplate>

這時候,每個ListboxItem實際是一個TextBlock,在數據集合list不做任何更改的情況下,我們可以修改數據模板,讓數據集合中的數據顯示成別的方式,

比如:把listboxitem改成button

數據模板代碼:

<ListBox ItemsSource="{Binding list}">
     <ListBox.ItemTemplate>
        <DataTemplate>
           <!--<TextBlock Text="{Binding}"/>-->
               <Button Content="{Binding}"/>
           </DataTemplate>
       </ListBox.ItemTemplate>
</ListBox>

運行結果:

在數據模板中可以做任何布局,從而實現讓數據有各種各樣的顯示形式

再比如:

 <ListBox ItemsSource="{Binding list}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="每一行都是數據模板的數據"/>
                        <Button Content="{Binding}"/>
                        <Button Content="{Binding}"/>
                        <TextBox Text="{ Binding Path=.}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

結果:

 這就是數據模板的作用,可以讓數據以任意形式顯示。

一個地方需要理解一下:

對於一個集合控件,定義的數據模板是針對每個集合控件的子項來說的。是每個子項的數據模板。或者說,集合控件在生成子項時,根據定義好的數據模板去定義出每個子項。

復雜數據集合的例子

listbox和list<ClassName>數據集合

 Book類代碼:

public class Book
    {
        public string BookName { get; set; }
        public string Title { get; set; }
    }

數據集合list2代碼:

     public List<Book> list2 { get; set; } = new List<Book>();
        public MainWindow()
        {
            InitializeComponent();

            list2.Add(new Book() { BookName ="語文",Title="出師表"});
            list2.Add(new Book() { BookName ="數學",Title="3.14"});
            list2.Add(new Book() { BookName ="英語",Title="Hello"});
     }

xaml代碼:

<ListBox ItemsSource="{Binding list2}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Border Background="DarkOliveGreen">
                                <TextBlock Text="{Binding BookName}"/>
                            </Border>
                            <Border Background="Aqua">
                                <TextBlock Text="{Binding Title}"/>
                            </Border>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

運行結果:

 對應關系:

 

 每個ListBoxItem對應一個Book對象,每個Book對象包含2個屬性,ListBoxItem中怎么顯示Book對象的屬性,就是取決於我們如何處理數據模板了。

(對於Book類,如果需要通知功能,則需要繼承INotifyPropertyChanged並實現接口)

上面是把DataTemplate定義在控件內部,為了可復用,可抽離出來定義在資源或資源字典中

<Window.Resources>
        <DataTemplate x:Key="MyDataTemplate">
            <StackPanel Orientation="Horizontal">
                <Border Background="DarkOliveGreen">
                    <TextBlock Text="{Binding BookName}"/>
                </Border>
                <Border Background="Aqua">
                    <TextBlock Text="{Binding Title}"/>
                </Border>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
View Code

引用定義好的DataTemplate

<ListBox ItemsSource="{Binding list2}" ItemTemplate="{StaticResource MyDataTemplate}"/>

2.ItemPanelTemplate

 繼續拿ListBox舉例,ListBox集合中的每個ListBoxItem是按照從上往下的排列順序,如果想要更改內部子項的布局順序,則需要修改ListBox的ItemPaneltemplate

<ItemsPanelTemplate x:Key="panel">
            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
 <ListBox ItemsSource="{Binding list2}" ItemTemplate="{StaticResource MyDataTemplate}" ItemsPanel="{StaticResource panel}"/>

3.ItemContainerStyle

修改每個ListboxItem的style。看一個簡單的例子,還是對上面的例子做拓展,每個子項使用一個Border包起來,並在下方添加一個CheckBox

<ListBox ItemsSource="{Binding list2}" ItemTemplate="{StaticResource MyDataTemplate}" ItemsPanel="{StaticResource panel}" >
                <ListBox.ItemContainerStyle>
                    <Style TargetType="ListBoxItem">
               <Setter Property="Foreground" Value="Blue"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> <StackPanel> <Border Name="border" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderBrush="Green" BorderThickness="1"> <ContentPresenter /> </Border> <CheckBox/> </StackPanel> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="BorderThickness" Value="2" TargetName="border"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListBox.ItemContainerStyle> </ListBox>

 運行結果:

Triggers:

 結果:

 


免責聲明!

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



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