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
