DataGrid

      在〈DataGrid〉中尚無留言

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_1

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);
 }

結果請看如下二個圖的 “標線” 欄位

datagrid_1

datagrid_2

todo

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *