前幾天打算嘗試下DataGrid的用法,起初以為應該很簡單,可後來被各種使用方法和功能實現所折磨。網路上的解決方法太多,但也太雜。沒法子,我只好硬著頭皮閱覽各種文獻資料,然後不斷的去嘗試,總算小有成果。因此,把我學到的和大家分享一下,相信這篇文章會讓你再很短的時間內學會DataGrid的大部分主要功 ...
前幾天打算嘗試下DataGrid的用法,起初以為應該很簡單,可後來被各種使用方法和功能實現所折磨。網路上的解決方法太多,但也太雜。沒法子,我只好硬著頭皮閱覽各種文獻資料,然後不斷的去嘗試,總算小有成果。因此,把我學到的和大家分享一下,相信這篇文章會讓你再很短的時間內學會DataGrid的大部分主要功能,而且很多難點都可以在裡面找到解決方案。
由於涉及的應用比較多,所以篇幅會很長。但可以確保各個版塊相互獨立,總共4個部分
先上一張截圖,讓你大概知道自己需要的功能是否在這張圖裡有所實現。
PS:使用技術:WPF + ADO.NET Entity Framework
1.數據綁定(涉及DataGrid綁定和Combox綁定)
在DataGrid 中同時包含“自動生成列”與“用戶自定義列” 由屬性AutoGenerateColumns控制。
預設情況下, DataGrid 將根據數據源自動生成列。 下圖列出了生成的列類型。
如果AutoGenerateColumns="True" ,我們只需要如下幾行代碼
<DataGrid Name="dataGrid1" AutoGenerateColumns="True" />
後臺dataGrid1.ItemsSource = infoList; //infoList為內容集合(這是我從資料庫中獲取的記錄集合 類型為List<T>)
PS:因為這裡給dataGrid1綁定了數據源,所以下麵綁定的欄位都是infoList中的欄位名稱,同樣也對應著我數據表中的欄位名。裡面包含FID,公司名稱,職員姓名,性別,年齡,職務。解釋下,怕大家無法理解Binding 後面的值是如何來的了
顯然這種數據綁定非常的容易,如果對錶格要求不高,這中無疑是最簡單方便的。
如果AutoGenerateColumns="False" 表格欄位的顯示就要靠我們手動去完成了。這個也是數據綁定的重點,因為實際應用中我們大多都是自定義去完成DataGrid的數據綁定。
接下來貼出代碼(後面的所有功能都可以在此代碼基礎上添加和修改)
<Window x:Class="CSDN_C.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:assembly="clr-namespace:System;assembly=mscorlib" xmlns:local="clr-namespace:Demo" Title="MainWindow" Loaded="Window_Loaded"> <Window.Resources> <ObjectDataProvider x:Key="keySex" MethodName="GetValues" ObjectType="{x:Type assembly:Enum}"> <ObjectDataProvider.MethodParameters> <x:Type Type="local:Sex"></x:Type> <!--引用後臺的枚舉類型,為欄位‘性別’提供數據源。上面引用了命名空間Demo--> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </Window.Resources> <Grid> <DataGrid Name="dataGrid1" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTemplateColumn Header="操作" Width="40"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox ></CheckBox> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTextColumn Header="公司名稱" Width="80" Binding="{Binding 公司名稱, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <DataGridTextColumn Header="姓名" Width="80" Binding="{Binding 職員姓名, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <DataGridComboBoxColumn Header="sex" SelectedItemBinding="{Binding 性別}" ItemsSource="{Binding Source={StaticResource keySex}}"/> <!--Combox綁定,獲取上面定義的資源keySex.綁定性別--> <DataGridTextColumn Header="年齡" Width="80" Binding="{Binding 年齡, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <DataGridTextColumn Header="職務" Width="80" Binding="{Binding 職務, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </DataGrid.Columns> </DataGrid> </Grid> </Window>
後臺
namespace Demo{ /// <summary> /// MainWindow.xaml 的交互邏輯 /// </summary> public enum Sex { 男,女 }; //註意 寫在命名空間內 ,不要寫在類里,否則台前local:Sex找不到路徑 }
當我們綁定好數據運行程式的時候,會發現 DataGridComboBoxColumn下拉框里雖然綁定了值,但是他不會預設顯示出已經設定好的值。所以我們就可以擯棄這種現有的 DataGridComboBoxColumn,我們用DataGrid樣板標簽DataGridTemplateColumn。
我們在DataGridTemplateColumn標簽里要用到2個控制項,一個 TextBlock控制項來顯示內容,另一個ComBox來提供選擇。
所以我們可以用如下代碼替換掉
<DataGridComboBoxColumn Header="sex" SelectedItemBinding="{Binding 性別}" ItemsSource="{Binding Source={StaticResource keySex}}"/>
<DataGridTemplateColumn Header="性別"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=性別}"/> <!--顯示狀態時顯示 TextBlock里的值--> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <!--編輯狀態就切換到ComboBox里進行下拉選擇操作--> <ComboBox x:Name="taskCombo" ItemsSource="{Binding Source={StaticResource keySex}}" SelectedItem ="{Binding Path=性別}" IsSynchronizedWithCurrentItem="False"/> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn>
註意 CellTemplate和 CellEditingTemplate的區別
2.DataGrid的增改刪功能
①添加記錄行+編輯記錄行
由於增加和編輯有一定的聯繫,所以就放一起來討論
在上面的代碼處添加2個Button按鈕,DataGrid預設是輸入一行記錄後自動會生成一個新行(類似MSSQL資料庫添加表記錄)。由屬性 CanUserAddRows來控制 當 CanUserAddRows=false的時候就不會自動生成新行。為了方便我們自己來控制,所以在DataGrid裡面設置CanUserAddRows為false.
<Grid> <Button Content="添加" Name="btnAdd" Click=" btnAdd_Click" /> <Button Content="保存" Name="btnSave" Click="btnSave_Click" /> <DataGrid Name="dataGrid1" AutoGenerateColumns="False" CanUserAddRows="False"> <!--此時的DataGrid就無法自己生成新行了--> </DataGrid> </Grid>
後臺事件
int judge = 0; //0表示編輯狀態,1為添加狀態。因為後面的增加和編輯都在同一個事件中,所以建一個變數來區分操作 TB_Information tbInfo = new TB_Information(); //這個類可以供我調用裡面的方法來進行增刪改查的操作 private void btnAdd_Click(object sender, RoutedEventArgs e) { judge = 1; //現在為添加狀態 dataGrid1.CanUserAddRows = true; //點擊添加後 將CanUserAddRows重新設置為True,這樣DataGrid就會自動生成新行,我們就能在新行中輸入數據了。 } //現在我們可以添加新記錄了,我們接下來要做的就是獲取這些新添加的記錄 //先聲明一個存儲新建記錄集的List<T> 這裡的Information是我的數據表實體類 裡面包含FID ,公司名稱,職員姓名,性別,年齡,職務 List<Information> lstInformation = new List<Information>(); //我們通過 RowEditEnding來獲取新增的記錄,就是每次編輯完行後,行失去焦點激發該事件。 更新記錄也是執行該事件 private void dataGrid1_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e) { Information info = new Information(); //我自己的數據表實例類 info = e.Row.Item as Information; //獲取該行的記錄 if (judge == 1) //如果是添加狀態就保存該行的值到lstInformation中 這樣我們就完成了新行值的獲取 { lstInformation.Add(info); } else { tbInfo.UpdInformation(info); //如果是編輯狀態就執行更新操作 更新操作最簡單,因為你直接可以在DataGrid裡面進行編輯,編輯完成後執行這個事件就完成更新操作了 } } //獲取到記錄後,單擊保存按鈕就可以保存lstInformation中的每一條記錄 private void btnSave_Click(object sender, RoutedEventArgs e) { foreach (Information info in lstInformation) { tbInfo.InsInformation(info); //執行插入方法,將記錄保存到資料庫 } judge = 0; //重新回到編輯狀態 lstInformation.Clear(); dataGrid1.CanUserAddRows = false; //因為完成了添加操作 所以設置DataGrid不能自動生成新行了 Binding(Num, 1); }
這裡又會遇到一個問題。那就是更新數據的時候,發現數據更本就沒更新。跟蹤代碼會發現後臺得到的值還是原來的,無法獲取編輯後的值。這個問題就是綁定模式的問題,我們只需設置雙向綁定就可以了。且作用對象是在屬性值更改的情況下進行雙向綁定。 只要在前面的每個表欄位處加上 Mode=TwoWay, UpdateSourceTrigger=PropertyChanged問題就解決了
例如:
<DataGridTextColumn Header="公司名稱" Width="80" Binding="{Binding 公司名稱, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
②刪除記錄
為了有良好的用戶體驗,我就做了個可以批量刪除的刪除功能。就是利用到CheckBox控制項來完成。
以綁定代碼為基礎添加代碼
<Grid> <Button Content="添加" Name="btnAdd" Click="btnAdd_Click" /> <Button Content="保存" Name="btnSave" Click="btnSave_Click" /> <Button Content="刪除" Name="btnDelete" Click="btnDelete_Click" /> </Grid>
首先我們要獲取CheckBox中的值,有哪些是被選中的。顯然CheckBox裡面還必須綁定值,並且還需要一個事件。給CheckBox添加的代碼如下
<DataTemplate> <CheckBox Click="CheckBox_Click" Tag="{Binding FID}" ></CheckBox> </DataTemplate>
後臺代碼
//由ChecBox的Click事件來記錄被選中行的FID List<int> selectFID = new List<int>(); //保存選中要刪除行的FID值 private void CheckBox_Click(object sender, RoutedEventArgs e) { CheckBox dg = sender as CheckBox; int FID = int.Parse(dg.Tag.ToString()); //獲取該行的FID var bl = dg.IsChecked; if (bl == true) { selectFID.Add(FID); //如果選中就保存FID } else { selectFID.Remove(FID); //如果選中取消就刪除裡面的FID } } //已經獲取到裡面的值了,接下來就只要完成刪除操作就可以了 刪除事件如下 private void btnDelete_Click(object sender, RoutedEventArgs e) { foreach (int FID in selectFID) { tbInfo.DelInformation(FID); //迴圈遍歷刪除裡面的記錄 } //Binding(Num, 1); //這個是我綁定的一個方法,作用是刪除記錄後重新給DataGrid賦新的數據源 }
3.DataGrid的分頁實現
原理:其實分頁功能的實現大家都清楚,無非就是把一個記錄集通過運算來刷選裡面對應頁碼的記錄。
接來下我們再次添加新的代碼
<Grid> <DataGrid Name="dataGrid1" AutoGenerateColumns="False"> <!--省略N個代碼--> </DataGrid> <StackPanel Orientation="Horizontal"> <TextBlock Text="轉到" Margin="5"/> <TextBox Name="tbxPageNum" Text="" /> <TextBlock Text="頁" /> <Button Content="GO" Click="btnGo_Click"/> <Button Name="btnUp" Content="上一頁" VerticalAlignment="Center" Click="btnUp_Click"/> <Button Name="btnNext" Content="下一頁" VerticalAlignment="Center" Click="btnNext_Click"/> <TextBlock Height="20"> <TextBlock Text="【共" /> <TextBlock Name="tbkTotal" Foreground="Red" /> <TextBlock Text="頁】" /> <TextBlock Text="【當前" /> <TextBlock Name="tbkCurrentsize" Foreground="Red" /> <TextBlock Text="頁】" /> </TextBlock> </StackPanel> </Grid>
首先我們先寫個分頁的方法,供上面這些事件調用
後臺代碼
//number表示每個頁面顯示的記錄數 currentSize表示當前顯示頁數 private void Binding(int number, int currentSize) { List<Information> infoList = new List<Information>(); infoList = tbInfo.GetInformationList(); //獲取數據源 int count = infoList.Count; //獲取記錄總數 int pageSize = 0; //pageSize表示總頁數 if (count % number == 0) { pageSize = count / number; } else { pageSize = count / number + 1; } tbkTotal.Text = pageSize.ToString(); tbkCurrentsize.Text = currentSize.ToString(); infoList = infoList.Take(number * currentSize).Skip(number * (currentSize - 1)).ToList(); //刷選第currentSize頁要顯示的記錄集 dataGrid1.ItemsSource = infoList; //重新綁定dataGrid1 } //分頁方法寫好了 接下來就是響應下一頁,上一頁,和跳轉頁面的事件了 //先定義一個常量 const int Num=12; //表示每頁顯示12條記錄 //上一頁事件 private void btnUp_Click(object sender, RoutedEventArgs e) { int currentsize = int.Parse(tbkCurrentsize.Text); //獲取當前頁數 if (currentsize > 1) { Binding(Num, currentsize - 1); //調用分頁方法 } } //下一頁事件 private void btnNext_Click(object sender, RoutedEventArgs e) { int total = int.Parse(tbkTotal.Text); //總頁數 int currentsize = int.Parse(tbkCurrentsize.Text); //當前頁數 if (currentsize < total) { Binding(Num, currentsize + 1); //調用分頁方法 } } //跳轉事件 private void btnGo_Click(object sender, RoutedEventArgs e) { int pageNum = int.Parse(tbxPageNum.Text); int total = int.Parse(tbkTotal.Text); //總頁數 if (pageNum >= 1 && pageNum <= total) { Binding(Num, pageNum); //調用分頁方法 } }
4.DataGrid的樣式設計
為什麼用WPF,不就是因為WPF擁有絢麗的設計頁面功能麽(當然遠不止這些)。雖然我美工這方面很差勁,但是最基本的設計我們還是要會一些。所以接下來做的工作主要就是給DataGrid上色了。(有些需要用到後臺代碼,也許不屬於樣式這類,但總歸是改變外觀,所以就放在一起歸納了)
①給DataGrid自動添加行序號+修改行表頭顏色
後臺代碼
//窗體載入事件 private void Window_Loaded(object sender, RoutedEventArgs e) { Binding(Num, 1); //調用分頁方法 顯示第一頁 dataGrid1.LoadingRow += new EventHandler<DataGridRowEventArgs>(dataGrid_LoadingRow); //自動添加序號的事件 調用下麵的dataGrid_LoadingRow } public void dataGrid_LoadingRow(object sender, DataGridRowEventArgs e) { e.Row.Header = e.Row.GetIndex() + 1; //設置行表頭的內容值 }
接下來就可以修改行表頭的顏色了
<DataGrid Name="dataGrid1"> <DataGrid.RowHeaderStyle> <Style TargetType="DataGridRowHeader"> <Setter Property="Width" Value="15"/> <Setter Property="Background"> <Setter.Value> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="White" Offset="0"/> <!--這裡用到了兩種顏色 也可以多層 這樣就可以產生一種漸變的效果或立體感--> <GradientStop Color="SkyBlue" Offset="1"/> </LinearGradientBrush> </Setter.Value> </Setter> </Style> </DataGrid.RowHeaderStyle> <!--省略N個代碼--> </DataGrid>
②給列表頭添加顏色
<DataGrid Name="dataGrid1"> <!--給整個表頭添加顏色開始--> <DataGrid.ColumnHeaderStyle> <Style TargetType="DataGridColumnHeader"> <Setter Property="Background"> <Setter.Value> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="White" Offset="0"/> <GradientStop Color="LightBlue" Offset="0.5"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Setter.Value> </Setter> <Setter Property="Foreground" Value="Black"/> <Setter Property="FontSize" Value="13" /> </Style> </DataGrid.ColumnHeaderStyle> <!--給整個表頭添加顏色結束--> <!--給單個列表頭添加顏色開始(以操作列表頭為例)--> <DataGrid.Columns> <DataGridTemplateColumn Header="操作" Width="40"> <DataGridColumn.HeaderStyle> <Style TargetType="DataGridColumnHeader"> <Setter Property="Background"> <Setter.Value> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="White" Offset="0"/> <GradientStop Color="Yellow" Offset="0.5"/> <GradientStop Color="White" Offset="1"/> </LinearGradientBrush> </Setter.Value> </Setter> <Setter Property="Foreground" Value="Black"/> <Setter Property="FontSize" Value="13"/> <Setter Property="Width" Value="70"/> </Style> </DataGridColumn.HeaderStyle> </DataGridTemplateColumn> </DataGrid.Columns> <!--給單個列表頭添加顏色結束--> <!--省略N個代碼--> </DataGrid>
③給行添加顏色+滑鼠事件
<DataGrid Name="dataGrid1"> <DataGrid.RowStyle> <Style TargetType="DataGridRow"> <Setter Property="Background" Value="LightBlue" /> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <!--當滑鼠經過時 改變顏色--> <Setter Property="Background" Value="SkyBlue"/> <Setter Property="Foreground" Value="White"/> </Trigger> </Style.Triggers> </Style> </DataGrid.RowStyle> <!--省略N個代碼--> </DataGrid>
④給單元格添加顏色
<DataGrid Name="dataGrid1"> <DataGrid.CellStyle> <Style TargetType="DataGridCell"> <Style.Triggers