设置ItemSource后为DataGrid每行添加CheckBox的实现问题
Hey there! Let's figure out how to add a CheckBox to each row of your DataGrid without modifying your entity classes or creating tons of derived classes. First, let's clear up why your initial approach didn't work—C# doesn't let you inherit directly from a generic type parameter T like that (even with constraints, it's not a practical solution here, especially with lots of entity classes).
Now, here are two solid, workable solutions:
Solution 1: Add a DataGridTemplateColumn directly in XAML (simplest option)
If you just need a CheckBox in each row and don't need to track the checked state in code (or can handle it via events), this is the easiest way. You don't have to touch your existing List<TblCity> at all—just modify your DataGrid's XAML to add a template column before the auto-generated ones:
<DataGrid x:Name="yourDataGrid" ItemsSource="{Binding YourCityList}" AutoGenerateColumns="True"> <DataGrid.Columns> <!-- Add this CheckBox column first --> <DataGridTemplateColumn Header="Select"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
If you need to track which rows are selected, handle the Checked/Unchecked events in code-behind to get the corresponding TblCity item:
private void CheckBox_Checked(object sender, RoutedEventArgs e) { var checkBox = sender as CheckBox; var city = checkBox.DataContext as TblCity; // Do something with the selected city, like add it to a selected items list } private void CheckBox_Unchecked(object sender, RoutedEventArgs e) { var checkBox = sender as CheckBox; var city = checkBox.DataContext as TblCity; // Remove from selected items list if needed }
Solution 2: Use a generic wrapper class (great for tracking selection in MVVM)
If you need a clean way to track checked states (especially if you're using MVVM), create a generic wrapper class that holds your entity and an IsSelected boolean property—no inheritance required, so it works with all your entity classes:
First, create the wrapper:
public class SelectableItem<T> { // Your original entity object public T Item { get; set; } // Track if the row is selected public bool IsSelected { get; set; } }
Then convert your existing List<TblCity> to a list of these wrapper objects:
// Assuming your original list is called cityList var selectableCities = cityList.Select(city => new SelectableItem<TblCity> { Item = city }).ToList(); // Set this as your DataGrid's ItemsSource yourDataGrid.ItemsSource = selectableCities;
Now, set up your DataGrid columns. You can either define them manually (for full control) or adjust auto-generation to show the entity's properties:
Option A: Define columns manually
<DataGrid ItemsSource="{Binding SelectableCities}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridCheckBoxColumn Header="Select" Binding="{Binding IsSelected}" /> <DataGridTextColumn Header="ID" Binding="{Binding Item.id}" /> <DataGridTextColumn Header="Name" Binding="{Binding Item.Name}" /> <DataGridTextColumn Header="Country ID" Binding="{Binding Item.CountryId}" /> </DataGrid.Columns> </DataGrid>
Option B: Keep auto-generated columns for the entity properties
If you don't want to manually define columns for every entity, handle the AutoGeneratingColumn event to skip the wrapper's Item property and generate columns for its sub-properties instead:
private void YourDataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { // Skip the "Item" property of the wrapper if (e.PropertyName == nameof(SelectableItem<TblCity>.Item)) { e.Cancel = true; // Generate columns for each property of TblCity foreach (var prop in typeof(TblCity).GetProperties()) { var textColumn = new DataGridTextColumn(); textColumn.Header = prop.Name; textColumn.Binding = new Binding($"Item.{prop.Name}"); ((DataGrid)sender).Columns.Add(textColumn); } } }
Don't forget to hook up the event in your XAML:
<DataGrid x:Name="yourDataGrid" ItemsSource="{Binding SelectableCities}" AutoGenerateColumns="True" AutoGeneratingColumn="YourDataGrid_AutoGeneratingColumn"> <DataGrid.Columns> <DataGridCheckBoxColumn Header="Select" Binding="{Binding IsSelected}" /> </DataGrid.Columns> </DataGrid>
This way, you get the auto-generated columns for your entity properties plus the CheckBox column, all without modifying your original TblCity class.
内容的提问来源于stack exchange,提问作者Sadra M.

