WPF DataGrid是一個非常強大的元件, 也超級難懂. 這元件可以將資料顯示於其中. 資料的來源, 可以是資料庫, 也可以是ObservableCollection<T> 型別
欄位設定
使用DataGrid之前, 先於xaml裏設定欄位, 並繫結每個欄位要顯示的資料欄
<DataGrid x:Name="dataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="項次" Width="50" Binding="{Binding 項次}"/> <DataGridTextColumn Header="缺失路段" Width="200" Binding="{Binding 缺失路段}"/> <DataGridTextColumn Header="經緯度" Width="100" Binding="{Binding 經緯度}"/> </DataGrid.Columns> </DataGrid>
Item類別
此步驟是將上述要顯示的欄位, 集合成一個類別, 訂定每個欄位的名稱, 型態如下
class Item { public int 項次 { get; set; } public string 缺失路段 { get; set; } public string 經緯度 { get; set; } }
資料收集
將要顯示於DataGrid裏的資料, 利用ObservableCollection<T> 集合在一起, 再使用DataGrid的DataContext 指向集合即可, 如下程式碼
public partial class MainWindow : Window { public String strConn = "server=ip;database=資料庫;uid=帳號;pwd=密碼;MultipleActiveResultSets=true"; public SqlConnection conn; ObservableCollection<Item> data; public MainWindow() { InitializeComponent(); data = new ObservableCollection<Item>(); conn = new SqlConnection(strConn); conn.Open(); string str = String.Format("select * from RoadData where 地區='{0}' and 日期 ='{1}' and 是否列印 ='是'", "內湖區", "2018/04/10"); SqlCommand cmd = new SqlCommand(str, conn); SqlDataReader dr = cmd.ExecuteReader(); int index = 1; while (dr.Read()) { Item item = new Item(); item.項次 = index++; item.缺失路段 = dr["缺失路段"].ToString(); item.經緯度 = string.Format("{0}\n{1}",dr["緯度"].ToString(), dr["經度"].ToString()); data.Add(item); } dataGrid.ItemsSource = data; //dataGrid.DataContext = data; } } class Item { public int 項次 { get; set; } public string 缺失路段 { get; set; } public string 經緯度 { get; set; } }
執行結果如下
DataGrid選取模式
DataGrid 預設選取模式為多列選取, 可以於xaml裏透過SelectionMode及SelectionUint進行設定
SelectionMode:有Exentded及Single二種模式
Single:只能選取一個單元(單元是指單一儲存格或整列, 由SelectionUnit 定義)
Extended:可選取多個單元(單元同上)
SelectionUnit:包含Cell, FullRow, CellOrRowHeader三種模式
Cell:選取單一儲存格
FullRow:整列選取
CellOrRowHeader:選取單一儲存格, 或點擊行首進行整列選取
DataContext 與ItemSource差異
ItemSource只能加入String等基本資料, 無法加入按鈕等元件, 且只要使用List<T>即可
而DataContext, 可以在DataGrid中加入如按鈕等元件, 但需使用ObservableCollection<T>, 且XAML必需指定每欄要綁定欄位名稱
DataGrid搜尋
可於DataGrid上方加個TextBox, 然後撰寫如下程式碼即可
private void textBox1_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) { var filtered = animals.Where(animal => animal.Type.StartsWith(textBox1.Text)); dataGrid1.DataContext = filtered; }
DataGrid 與按鈕
若需於DataGrid內加入其他控制元件, 比如按鈕, 則於xaml裏加入<DataGridTemplateColumn>, 如下所示
<DataGrid x:Name="datagrid" Grid.Row="0" ItemsSource="{Binding}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="Com Port" Width="80" Binding="{Binding comport}"/> <DataGridTextColumn Header="Addr_1" Width="50" Binding="{Binding ip1}"/> <DataGridTextColumn Header="Addr_0" Width="50" Binding="{Binding ip0}"/> <DataGridTextColumn Header="Name" Width="50" Binding="{Binding name}"/> <DataGridTextColumn Header="X" Width="50" Binding="{Binding x}"/> <DataGridTextColumn Header="Y" Width="50" Binding="{Binding y}"/> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button x:Name="btnDelete" Width="100" Content="刪除" Click="BtnDelete_Click"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
致於在C#代碼中, 要刪除指定的列數, 可由如下代碼完成
private void BtnDelete_Click(object sender, RoutedEventArgs e) { dt.Rows.RemoveAt(datagrid.SelectedIndex); }
欄位寬度自動縮放
欄位寬度若沒有設定Width, 則會隨著內容放大, 但當內容縮小後, 寬度並不會跟著縮小, 所以必需設定如下
1. 在DataGrid設定TargetUpdated觸發的方法
2. DataGridTextColumn 綁定資料欄位外, 還要綁定NotifyOnTargetUpdated=True. 致於Width可以設定為Auto, 或者不設定
<DataGridTextColumn Header="標線" IsReadOnly="True" Binding="{Binding 標線_show, NotifyOnTargetUpdated=True}" Width="Auto">
3. 程式碼需多加 dg_TargetUpdated方法. 完整代碥如下
請注意, DataGrid並不設定Height, 所以高度會依每列的大小而不同
<DataGrid x:Name="grid2" Grid.Row="2" CanUserDeleteRows="False" ItemsSource="{Binding}" AutoGenerateColumns="False" SelectionMode="Extended" SelectionUnit="CellOrRowHeader" CanUserAddRows="False" ScrollViewer.CanContentScroll="False" FontSize="16" Margin="0,0,0,5" TargetUpdated="dg_TargetUpdated"> <DataGrid.Resources> <Style TargetType="{x:Type DataGridCell}"> <Style.Triggers> <Trigger Property="DataGridCell.IsSelected" Value="True"> <Setter Property="Background" Value="#FFFF00" /> <Setter Property="Foreground" Value="Black"/> </Trigger> </Style.Triggers> </Style> </DataGrid.Resources> <DataGrid.Columns> <DataGridTextColumn Header="深" Width="50" Binding="{Binding 深}" IsReadOnly="True" /> <DataGridTextColumn Header="標線" IsReadOnly="True" Binding="{Binding 標線_show, NotifyOnTargetUpdated=True}" Width="Auto"> <DataGridTextColumn.ElementStyle> <Style TargetType="TextBlock"> <Setter Property="TextWrapping" Value="Wrap"/> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn> <DataGridTextColumn Header="標線面積" Width="80" Binding="{Binding 標線面積_show}" IsReadOnly="True"/> </DataGrid.Columns> </DataGrid>
private void dg_TargetUpdated(object sender, DataTransferEventArgs e) { grid2.Columns[12].Width = 0; grid2.UpdateLayout(); grid2.Columns[12].Width = new DataGridLength(1, DataGridLengthUnitType.Auto); }
結果請看如下二個圖的 “標線” 欄位
todo