ListView從ListBox派生,只增長了View屬性。若是你沒有設置View屬性,ListView行爲正如ListBox。html
從技術上,View屬性指向任何ViewBase派生類的一個實例。ViewBase類是簡單的;事實上,它是兩個樣式。同樣式應用於ListView控件(DefaultStyleKey屬性),和另外一樣式應用於ListView項目(ItemContainerDefaultStyleKey屬性)。DefaultStyleKey和ItemContainerDefaultStyleKey屬性實際上沒有提供樣式;代替,他們返回一個指向樣式的ResourceKey對象。算法
GridView是一個類。派生自ViewBase。表明帶有多個列的一個列表視圖。你定義那些列依靠添加GridViewColumn對象到GridView.Columns集合。編程
GridView和GridViewColumn都提供幾個有用的方法。你能用於自定義列表的外觀。爲創造最簡單的列表,你須要爲每一個GridViewColumn設置二個屬性:Header和DisplayMemberBinding。Header屬性提供被放置在列頂的文本。DisplayMemberBinding屬性包含一個綁定,從每一個數據項目提取你但願顯示的信息。app
這是標記,定義了三列被用在這個例子中。函數
<ListView Margin="5" Name="lstProducts"> <ListView.View> <GridView> <GridView.Columns> <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=ModelName}" /> <GridViewColumn Header="Model" DisplayMemberBinding="{Binding Path=ModelNumber}" /> <GridViewColumn Header="Price" DisplayMemberBinding= "{Binding Path=UnitCost, StringFormat={}{0:C}}" /> </GridView.Columns> </GridView> </ListView.View> </ListView>
沒有一列有硬編碼的尺寸。工具
DisplayMemberBinding屬性使用一個綁定表達式。佈局
當聲明列時,能夠指定列寬:字體
<GridViewColumn Width="300" ... />
這只是設定了列的最初尺寸,沒有阻止用戶修改列尺寸。大數據
CellTemplate屬性取一個數據模板。它只應用於一列。每列能夠擁有它本身的數據模板。ui
定義一個能夠換行的列:
<GridViewColumn Header="Description" Width="300"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=Description}" TextWrapping="Wrap"></TextBlock> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn>
注意,爲了換行有效果,你須要約束列的寬度。
由於數據模板使用了數據綁定,因此只能爲每一個字段建立一個單獨的模板。
下面的列使用一個數據模板顯示一個圖像。
<GridViewColumn Header="Picture" > <GridViewColumn.CellTemplate> <DataTemplate> <Image Source= "{Binding Path=ProductImagePath,Converter={StaticResource ImagePathConverter}}"> </Image> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn>
當創造一個數據模板,你選擇內聯定義它或引用一個在別處定義的資源。由於列模板不能被重用於不一樣的字段,最清晰的一般是內聯定義他們。
你能使用模板選擇器,設置GridViewColumn.CellTemplateSelector屬性。
自定義列標頭
見670頁。
WPF的樹視圖充分支持數據綁定。
樹視圖是一個特殊的ItemsControl,容納TreeViewItem對象。可是不一樣於ListViewItem,TreeViewItem不是一個內容控件。代替,每一個TreeViewItem是一個獨立的ItemsControl,可以持有更多TreeViewItem對象。
從技術上,TreeViewItem派生自HeaderedItemsControl,這派生自ItemsControl。HeaderedItemsControl類添加一個Header屬性,這持有你但願顯示的樹項目內容(一般文本)。WPF包含二另外的HeaderedItemsControl類:MenuItem和ToolBar。
用標記創建一個樹:
<TreeView> <TreeViewItem Header="Fruit"> <TreeViewItem Header="Orange"/> <TreeViewItem Header="Banana"/> <TreeViewItem Header="Grapefruit"/> </TreeViewItem> <TreeViewItem Header="Vegetables"> <TreeViewItem Header="Aubergine"/> <TreeViewItem Header="Squash"/> <TreeViewItem Header="Spinach"/> </TreeViewItem> </TreeView>
樹視圖能夠包括非TreeViewItem對象。Header屬性是一個內容,能夠包括一個其餘元素。也能夠經過HeaderTemplate,或HeaderTemplateSelector屬性。
你只是須要指定正確的數據模板。你的模板指明不一樣水平的數據之間的關係。
首先,定義Category類,Category類暴露Product對象的一個集合:
public class Category : INotifyPropertyChanged { private string categoryName; public string CategoryName { get { return categoryName; } set { categoryName = value; OnPropertyChanged(new PropertyChangedEventArgs("CategoryName")); } } private ObservableCollection<Product> products; public ObservableCollection<Product> Products { get { return products; } set { products = value; OnPropertyChanged(new PropertyChangedEventArgs("Products")); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) PropertyChanged(this, e); } public Category(string categoryName, ObservableCollection<Product> products) { CategoryName = categoryName; Products = products; } }
創造一個集合經過一個屬性暴露另外一個集合是用WPF數據綁定父子關係導航的關鍵。
爲顯示目錄,你須要提供一個TreeView.ItemTemplate,能處理綁定對象。在這個例子中,你須要顯示每一個Category對象的CategoryName屬性。這裏是數據模板:
<TreeView Name="treeCategories" Margin="5"> <TreeView.ItemTemplate> <HierarchicalDataTemplate> <TextBlock Text="{Binding Path=CategoryName}" /> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView>
使用一個HierarchicalDataTemplate對象而不是一個DataTemplate設置TreeView.ItemTemplate。HierarchicalDataTemplate能包裹第二層模板。而後,HierarchicalDataTemplate能從第一層提取一個項目集合而且提供集合到第二層模板。你只設置ItemsSource屬性去識別有子項目的屬性,以及設置ItemTemplate屬性指明每一個對象應該如何被格式化。
這是修改後的代碼:
<TreeView Name="treeCategories" Margin="5"> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Path=Products}"> <TextBlock Text="{Binding Path=CategoryName}" /> <HierarchicalDataTemplate.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Path=ModelName}" /> </DataTemplate> </HierarchicalDataTemplate.ItemTemplate> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView>
本質上,你如今有二模板,一對於樹的每一個水平。第二模板從第一模板使用被選擇項目做爲它的數據源。
儘管這標記工做完美,廣泛的是提取每一個數據模板和應用它到你的數據對象依靠數據類型而不是依靠位置。爲理解那意味着什麼,有幫助的是考慮一個修訂版本的標記對於數據綁定樹視圖:
<Window x:Class="DataBinding.BoundTreeView" ... xmlns:local="clr-namespace:DataBinding"> <Window.Resources> <HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding Path=Products}"> <TextBlock Text="{Binding Path=CategoryName}"/> </HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="{x:Type local:Product}"> <TextBlock Text="{Binding Path=ModelName}" /> </HierarchicalDataTemplate> </Window.Resources> <Grid> <TreeView Name="treeCategories" Margin="5"> </TreeView> </Grid> </Window>
在這個例子中樹視圖沒有顯式地設置它的ItemTemplate。代替,基於綁定對象的數據類型合適的ItemTemplate被使用。相似地,Category模板沒有指定ItemTemplate那應該被用於處理Products集合。它也依靠數據類型被自動地選擇。這樹如今能顯示一列產品或一列目錄那包含組的產品。
顧名思義,DataGrid是一個顯示數據控件,從對象的一個集合取信息和呈現它在一個行和列的網格。每一個行對應於一個獨立的對象,以及每一個列對應於那對象一個屬性。
DataGrid選擇模型容許你選擇是否用戶能選擇一個行,多個行,或一些單元格的聯合。
爲創造一個DataGrid,你能使用自動的列生成。你須要設置AutoGenerateColumns屬性爲真(這是默認值):
<DataGrid x:Name="gridProducts" AutoGenerateColumns="True"> </DataGrid>
如今你能填充DataGrid,像填充列表控件同樣,依靠設置ItemsSource屬性:
gridProducts.ItemsSource = products;
對於自動的列生成,DataGrid使用反射在綁定數據對象中查找每一個公開的屬性。它爲每一個屬性創造一個列。
爲顯示非字符串屬性,DataGrid調用ToString()。對於數字,日期,和另外的簡單的數據類型工做良好。
DataGrid的基本顯示屬性:
名字 | 描述 |
RowBackground 和 AlternatingRowBackground |
|
ColumnHeaderHeight | |
RowHeaderWidth | |
ColumnWidth | |
RowHeight | |
GridLinesVisibility | |
VerticalGridLinesBrush | |
HorizontalGridLinesBrush | |
HeadersVisibility | |
HorizontalScrollBarVisibility和 VerticalScrollBarVisibility |
爲設置ColumnWidth屬性,你提供一個DataGridLength對象。你的DataGridLength能指定一個精確的尺寸或一個特殊的尺寸方式。若是你選擇使用一個精確的尺寸,只是設置ColumnWidth相等的爲合適的數(在XAML)或提供數做爲一個構造函數實參當創造DataGridLength(在代碼):
grid.ColumnWidth = new DataGridLength(150);
你經過DataGridLength類的靜態的屬性訪問特殊的尺寸模式。這是一個例子,使用默認DataGridLength.SizeToHeader尺寸方式,這意味着列被製造足夠寬容納它們的標頭文本:
grid.ColumnWidth = DataGridLength.SizeToHeader;
另外一個流行的選項是DataGridLength.SizeToCells。列只能自動加寬,不能自動收縮。
DataGridLength.Auto,每一個列的寬度適合最大的單元格或列標頭文本。
DataGrid支持使用星號設置寬度。你須要顯式地設置每一個列對象的Width屬性。
修改列尺寸之後,列就失去自動增長列寬的功能。
你能阻止用戶修改DataGrid的列尺寸,依靠設置CanUserResizeColumns屬性爲假。你能阻止用戶修改單獨列尺寸,依靠設置那列的CanUserResize屬性爲假。你也能阻止用戶使列極端地窄,依靠設置列的MinWidth屬性。
若是你不但願用戶拖拽列位置,設置DataGrid的CanUserReorderColumns屬性或指定的列的CanUserReorder屬性爲假。
設置AutoGenerateColumns爲假。而後顯式地定義列,設置列配置,指定列順序。用正確的列對象填充DataGrid.Columns集合。
目前,DataGrid支持幾個類型的列,這表現爲派生自DataGridColumn不一樣的類:
例如,這裏是一個修訂DataGrid那創造一個2列的顯示帶有產品名字和價格。它也應用更清楚的列標題和放寬產品列適合它的數據:
<DataGrid x:Name="gridProducts" Margin="5" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="Product" Width="175" Binding="{Binding Path=ModelName}"></DataGridTextColumn> <DataGridTextColumn Header="Price" Binding="{Binding Path=UnitCost}"></DataGridTextColumn> </DataGrid.Columns> </DataGrid>
當你定義一個列,你幾乎老是設置三細節:標頭文本,列的寬度,和綁定得到數據。
一般,你將使用一個簡單字符串設置DataGridColumn.Header屬性,可是不侷限於普通文本。
DataGridColumn.Width屬性支持硬編碼的值和幾個自動的尺寸模式,正如DataGrid.ColumnWidth屬性。惟一不一樣是DataGridColumn.Width應用於單個的列,然而DataGrid.ColumnWidth設置全體表默認。當DataGridColumn.Width被設置,它覆蓋DataGrid.ColumnWidth。
DataGridColumn.Binding屬性中的綁定表達式爲列提供正確的信息。Binding方法比DisplayMemberPath更靈活,它容許你使用字符串格式化和值轉換器,無需使用複雜的列模板。
<DataGridTextColumn Header="Price" Binding= "{Binding Path=UnitCost, StringFormat={}{0:C}}"> </DataGridTextColumn>
列的另外兩個屬性包括:Visibility,DisplayIndex屬性。
正如DataGridTextColumn,Binding屬性提取數據—在這種狀況下,真或假值,那被用於設置內部複選框元素的IsChecked屬性。DataGridCheckBoxColumn也添加一個屬性命名Content那讓你顯示可選的內容複選框旁邊。最後,DataGridCheckBoxColumn包含一個IsThreeState屬性,這決定是否複選框支持未定狀態也更明顯的選中和未選中狀態。若是你使用DataGridCheckBoxColumn顯示從一個可空Boolean值信息,你能設置IsThreeState屬性爲真。那樣,用戶能點擊向後未定狀態(這顯示一個輕陰影複選框)返回綁定值爲空。
見691頁。
DataGridComboBoxColumn最初顯示普通文本,可是在編輯模式時,容許用戶從組合框控件選取一個項目。(事實上,用戶將被迫從列表選擇,由於組合框不容許直接輸入文本。)
爲使用DataGridComboBoxColumn,你須要決定如何填充組合框。你只設置DataGridComboBoxColumn.ItemsSource集合。能夠在標記中用手填充它。下面的例子添加一列字符串到組合框:
<DataGridComboBoxColumn Header="Category" SelectedItemBinding="{Binding Path=CategoryName}"> <DataGridComboBoxColumn.ItemsSource> <col:ArrayList> <sys:String>General</sys:String> <sys:String>Communications</sys:String> <sys:String>Deception</sys:String> <sys:String>Munitions</sys:String> <sys:String>Protection</sys:String> <sys:String>Tools</sys:String> <sys:String>Travel</sys:String> </col:ArrayList> </DataGridComboBoxColumn.ItemsSource> </DataGridComboBoxColumn>
在許多狀況下,你顯示在列表值不是你但願存儲在數據對象值。
代替一列簡單的字符串,你綁定一個整個的Category對象的列表到DataGridComboBoxColumn.ItemsSource屬性:
categoryColumn.ItemsSource = App.StoreDB.GetCategories();
gridProducts.ItemsSource = App.StoreDB.GetProducts();
而後你配置DataGridComboBoxColumn。你必須設置三屬性:
<DataGridComboBoxColumn Header="Category" x:Name="categoryColumn" DisplayMemberPath="CategoryName" SelectedValuePath="CategoryID" SelectedValueBinding="{Binding Path=CategoryID}"></DataGridComboBoxColumn>
DisplayMemberPath告訴列從Category對象抽取哪個文本並在列表中顯示。SelectedValuePath告訴列從Category對象抽取什麼數據。SelectedValueBinding說明在Product對象的連接字段。
DataGridTemplateColumn使用一個數據模板,這工做方式等同於列表控件數據模板特徵。DataGridTemplateColumn在惟一不一樣是它容許你定義二模板:一對於數據顯示(CellTemplate)和一對於數據編輯(CellEditingTemplate)。這是一個例子那使用模板數據在網格列放置每一個產品的圖像:
<DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Image Stretch="None" Source= "{Binding Path=ProductImagePath, Converter={StaticResource ImagePathConverter}}"> </Image> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
添加ImagePathConverter值轉換器到Window.Resources集合:
<Window.Resources> <local:ImagePathConverter x:Key="ImagePathConverter"></local:ImagePathConverter> </Window.Resources>
你能以格式一個TextBlock元素的方式格式一個DataGridTextColumn,依靠設置Foreground,FontFamily,FontSize,FontStyle,和FontWeight屬性。可是,DataGridTextColumn沒有暴露TextBlock全部的屬性。例如,沒辦法設置Wrapping屬性,若是你但願創造一個列顯示多行的文本。在這種狀況下,你須要使用ElementStyle屬性代替。
本質上,ElementStyle屬性讓你創造一個樣式,那被應用於DataGrid單元格的內部元素。在一個簡單的DataGridTextColumn的狀況,那是一個TextBlock。在一個DataGridCheckBoxColumn,它是一個複選框。在一個DataGridTemplateColumn,它是你在數據模板中創造的元素。
這裏是一個簡單的樣式,那容許在一個列文本換行:
<DataGridTextColumn Header="Description" Width="400" Binding="{Binding Path=Description}"> <DataGridTextColumn.ElementStyle> <Style TargetType="TextBlock"> <Setter Property="TextWrapping" Value="Wrap"></Setter> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn>
不幸地,DataGrid不能像WPF佈局容器同樣靈活地修改它本身的尺寸。代替,你被迫設置一個固定行高度,依靠使用DataGrid.RowHeight屬性。這高度應用於全部的行,無論它包含內容的數量。
你能使用EditingElementStyle設置編輯時的被僱用元素樣式。在DataGridTextColumn的狀況,編輯元素是TextBox控件。
DataGrid的樣式屬性
屬性 | 樣式應用到 |
ColumnHeaderStyle | |
RowHeaderStyle | |
DragIndicatorStyle | |
RowStyle | TextBlock那被用於普通的行(行在沒有被明確地經過列的ElementStyle屬性自定義的列) |
在許多狀況下,須要標記包含指定的數據的行。你能以編程方式應用這類格式化,依靠處理DataGrid.LoadingRow事件。
LoadingRow事件對於行格式化是一個強力的工具。經過它能訪問當前的行的數據對象,執行簡單的範圍覈對,比較,和更復雜的操做。它也提供DataGridRow對象對於行,讓你格式行帶有不一樣的顏色或一個不一樣的字體。可是,你不能格式剛好一個單個的單元格在那行—對於那,你須要DataGridTemplateColumn和一個自定義值轉換器。
對於每一個行當它出如今屏幕上時,LoadingRow事件激發一次。
//由於大數據顯示的效率,重用刷子對象 private SolidColorBrush highlightBrush = new SolidColorBrush(Colors.Orange); private SolidColorBrush normalBrush = new SolidColorBrush(Colors.White); private void gridProducts_LoadingRow(object sender, DataGridRowEventArgs e) { //從這一行取出數據對象 var product = (Product)e.Row.DataContext; //應用條件格式化 if (product.UnitCost > 100) { e.Row.Background = highlightBrush; } else { //恢復默認的白背景。這確保被使用的, //格式化的DataGrid對象被重設爲原始的外觀 e.Row.Background = normalBrush; } }
記住,你能使用一個值轉換器那檢查綁定數據而且轉換它到其餘的某物。這技術當結合DataGridTemplateColumn尤爲強力的。
首先你須要定義在行細節區域顯示內容,依靠設置DataGrid.RowDetailsTemplate屬性。在這種狀況下,行細節區域使用一個基本模板,包含一個TextBlock顯示完整產品文本和添加一個它周圍邊界:
<DataGrid.RowDetailsTemplate> <DataTemplate> <Border Margin="10" Padding="10" BorderBrush="SteelBlue" BorderThickness="3" CornerRadius="5"> <TextBlock Text="{Binding Path=Description}" TextWrapping="Wrap" FontSize="10"> </TextBlock> </Border> </DataTemplate> </DataGrid.RowDetailsTemplate>
你能配置行細節區域的顯示行爲,依靠設置DataGrid.RowDetailsVisibilityMode屬性。默認狀況下,這屬性被設置爲VisibleWhenSelected,這意味着行細節區域被顯示當行被選擇。可選地,你能設置它爲Visible,這意味着將馬上顯示每行的細節區域。或你能使用Collapsed,這意味着細節區域將不被顯示對於任何行—至少,不直到你改變RowDetailsVisibilityMode在代碼(例如,當用戶選擇一個確信的類型的行)。
爲使用列凍結,你設置DataGrid.FrozenColumnCount屬性爲一個比0更大的數。例如,一個值1剛好凍結第一列:
<DataGrid x:Name="gridProducts" Margin="5" AutoGenerateColumns="False" FrozenColumnCount="1">
若是你凍結一列,它是最左列;若是你凍結二列,他們將是左邊前二列;等等。
如同一個普通的列表控件,DataGrid讓用戶選擇單獨的項目。你能反應SelectionChanged事件當這發生。爲找出哪個數據對象是目前選擇,你能使用SelectedItem屬性。若是你但願用戶能選擇多個行,設置SelectionMode屬性爲Extended。(Single是惟一另外的選項和默認。)爲選擇多個行,用戶必須按下Shift或Ctrl鍵。你能從SelectedItems屬性取回選擇項目的集合。
你能以編程方式設置選擇,依靠使用SelectedItem屬性。若是你設置的選擇項目當前看不到,隨後調用DataGrid.ScrollIntoView()方法,滾動表格使被選擇項可見。
DataGrid內建排序特徵只要你綁定的集合實現IList(諸如List<T>和ObservableCollection<T>集合)。
一般,DataGrid使用出如今列中的綁定數據排序算法。可是,你能選擇一個不一樣的屬性從綁定數據對象依靠設置一個列的SortMemberPath。和若是你有一個DataGridTemplateColumn,你須要使用SortMemberPath,由於不存在綁定屬性提供綁定數據。若是你沒有,你的列將不支持排序。
你也能使排序不可用依靠設置CanUserSortColumns屬性爲假(或對於指定的列關掉它依靠設置列的CanUserSort屬性)。
DataGrid的最大便利之一是它對於編輯的支持。一個DataGrid單元格切換到編輯方式當用戶雙擊它。可是DataGrid用幾個方法讓你限制這編輯能力:
依賴於列類型,當一個單元格切換到編輯模式,發生什麼。DataGridTextColumn顯示一個文本框。DataGridCheckBox列顯示一個複選框你能選中或不選。可是DataGridTemplateColumn容許你用一個更專門的輸入控件替換標準編輯文本框。
例以下面的列顯示一個日期。當用戶雙擊去編輯那值,它轉到一個帶有預選擇當前值的下拉DatePicker:
<DataGridTemplateColumn Header="Date Added"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Margin="4" Text= "{Binding Path=DateAdded, Converter={StaticResource DateOnlyConverter}}"> </TextBlock> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <DatePicker SelectedDate="{Binding Path=DateAdded, Mode=TwoWay}"> </DatePicker> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn>
DataGrid一樣自動地支持基本驗證系統。這是一個例子,使用一個自定義驗證規則驗證UnitCost字段:
<DataGridTextColumn Header="Price"> <DataGridTextColumn.Binding> <Binding Path="UnitCost" StringFormat="{}{0:C}"> <Binding.ValidationRules> <local:PositivePriceRule Max="999.99" /> </Binding.ValidationRules> </Binding> </DataGridTextColumn.Binding> </DataGridTextColumn>
DataGrid的編輯事件。
名稱 | 描述 |
BeginningEdit | 發生在單元格準備進入編輯時。你能檢查目前被編輯的列和行,檢查單元格值,和依靠使用DataGridBeginningEditEventArgs.Cancel屬性取消操做。 |
PreparingCellForEdit | 用於模板列。這時,你能執行任何編輯控件要求的最後初始化。使用DataGridPreparingCellForEditEventArgs.EditingElement訪問在CellEditingTemplate中的元素。 |
CellEditEnding | 發生在單元格準備退出編輯模式時。DataGridCellEditEndingEventArgs.EditAction告訴你是否用戶嘗試接受編輯(例如,依靠按壓Enter或點擊另外一個單元格)或取消它(依靠按壓Esc鍵)。你能檢查新的數據和設置Cancel屬性回滾一個試圖的改變。 |
RowEditEnding | 發生在用戶編輯當前行以後導航到新行。正如CellEditEnding,你能使用這指向執行驗證和取消改變。典型地,你將執行牽涉幾個列的驗證—例如,確保某列的值不比另外一列的值更大。 |
若是你須要一個地方執行你頁面的驗證邏輯,你能寫自定義驗證邏輯響應CellEditEnding和RowEditEnding事件。檢查列規則在CellEditEnding事件處理器,和驗證整行的一致性在RowEditEnding事件。而且記住若是你取消一個編輯,你應該提供一個問題的解釋(一般在頁面別處的一個TextBlock中)。