Add a button in a new column to all rows in the DataGrid

I have a DataGridView object:

 dataGridView1.DataSource = an.peaks; 

(an.peaks is a List<Point> object. Point type has 3 properties: x, y, z)

witch generates the following table at runtime: (Apparently, I cannot load Image , but because I am a new user, so I will try to do this :)

 ____|_x__|_y__|_z__|[new column ] ____|_11_|_12_|_13_|[text/button] <==\ ____|_20_|_30_|_40_|[text/button] <== } Add text if something or button if something else. ____|_50_|_60_|_70_|[text/button] <==/ 

I would like to add buttons (as shown in the figure / figure) in a new column for each row that satisfies some condition. If the condition is not met, add text instead.

Example: if a point already existing in the database shows the name of the substance (each point represents a substance). If you do not add the "ADD" button to the corresponding line, which will add a new point to the database.

Conditions are not problems - they are only for examples. The problem is adding buttons / text to each line and a click event for a new button / s.

+7
source share
2 answers

This is pretty easy to do with a DataGridView . What you need to do:

Add a column of type DataGridViewButtonColumn

DataGridViewButtonColumn is a standard type of DataGridView column. It can be added through the constructor, but I usually prefer to use code (usually in the form constructor).

 DataGridViewButtonColumn col = new DataGridViewButtonColumn(); col.UseColumnTextForButtonValue = True; col.Text = "ADD"; col.Name = "MyButton"; dataGridView1.Columns.Add(col); 

Setting UseColumnTextForButtonValue true means that the Text property is applied to all buttons giving them the text of the "ADD" button. You can also use DataPropertyName to specify a column in the grid data source to provide button text, or you can even set the value of each cell directly.

Change buttons to text

After you have a column with buttons, you want to turn individual buttons into text. You do this by replacing the button type cell with one text type. You can do this in many places, but one of the best in the DataBindingComplete event handler is that this event fires after the grid is attached and ready to be displayed, but before it is colored.

Below I just take the line with index 1, but you can also check the properties of each Value line.

 void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) { dataGridView1.Rows[1].Cells["MyButton"] = new DataGridViewTextBoxCell(); } 

Button Response

The last part of the problem responds to button presses. This is a bit awkward - you need to either use the CellClick event or the EditingControlShowing event for the entire grid.

  • Cellclick

     private void DataGridView1_CellClick(object sender, System.Windows.FormsDataGridViewCellEventArgs e) { if (DataGridView1.Columns[e.ColumnIndex].Name == "MyButton") { // button clicked - do some logic } } 
  • EditingControlShowing

     void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { if (e.Control is Button) { Button btn = e.Control as Button; btn.Click -= new EventHandler(btn_Click); btn.Click += new EventHandler(btn_Click); } } void btn_Click(object sender, EventArgs e) { int col = this.dataGridView1.CurrentCell.ColumnIndex; int row = this.dataGridView1.CurrentCell.RowIndex; // Rest of the logic goes here! } 

In your case, the editing control approach is probably best because it will not respond to clicking on buttons that have been replaced with text. Also, this method is more like how you react to any other button in the form.

+14
source

You can add WPF host control to your WinForms project and use the DataGrid with CellTemplateSelector . For example:

 <DataGrid x:Name="grid" AutoGenerateColumns="False" x:FieldModifier="private"> <DataGrid.Resources> <local:PointDataTemplateSelector x:Key="pointDataTemplateSelector" /> <DataTemplate x:Key="buttonTemplate"> <Button Click="OnAddButtonClick" Tag="{Binding Mode=OneWay}">Add</Button> </DataTemplate> <DataTemplate x:Key="textTemplate"> <TextBlock>Exists</TextBlock> </DataTemplate> </DataGrid.Resources> <DataGrid.Columns> <DataGridTextColumn Header="X" Binding="{Binding X}" /> <DataGridTextColumn Header="Y" Binding="{Binding Y}" /> <DataGridTemplateColumn Header="Select" CellTemplateSelector="{StaticResource pointDataTemplateSelector}"></DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> 

And selector class:

 public class PointDataTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { var element = container as FrameworkElement; if (element != null && item != null && item is Point) { var point = (Point)item; // Logic here. if (point.X >= 5) { return element.FindResource("buttonTemplate") as DataTemplate; } return element.FindResource("textTemplate") as DataTemplate; } return null; } } 

It may be simpler than the WinForms method.

0
source

All Articles