I have a DataGridView in a WinForm. I fill the DataGridView from a database table. I was wondering if there is any way to program my DataGridView so that I can choose which columns I want the gridview to show at runtime?
The simple answer is "yes".
In the first instance you need to set the AutoGenerateColumns property of the DataGridView to false then you can control which columns get displayed.
In the past I've created a context menu for the DGV:
ContextMenu = new ContextMenu();
foreach (var column in this.dataGridView.Columns)
{
this.AddContextMenuItem(ContextMenu, column.Name, column.Visible);
}
private void AddContextMenuItem(ContextMenu contextMenu,
string columnName,
bool visible)
{
var menuItem = new MenuItem(columnName,
new EventHandler(this.ContextMenu_onClick)) { Checked = visible };
contextMenu.MenuItems.Add(menuItem);
}
Then when the the menu option is toggled change the Visible property of the column.
private void ContextMenu_onClick(object sender, EventArgs e)
{
var clicked = sender as MenuItem;
if (clicked != null)
{
// Update the state of the context menu
clicked.Checked = !clicked.Checked;
// Update the visibity of this column
this.dataGridView.Columns[clicked.Text].Visible = clicked.Checked;
}
}
Use the DataGridView.AutoGenerateColumns property--set to false. Explicitly configure the columns you want, and you're good to go.
Related
I have a datagridview that when it loaded first row is selected. I want to delete a record but I don't want first row select. I want message to user that first select a row then click delete button. I try these code but they don't worked.
//kharidDataGridView.Rows[0].Selected = false;
//kharidDataGridView.ClearSelection();
//kharidDataGridView.CurrentCell = null;
I use below codes in WPF:
object item = datagrideview1.SelectedItem;
if (item == null)
{
//message to user
}
thank you
You can remove default selected row by handling data-grid loaded event
private void datagrideview1_Loaded(object sender, RoutedEventArgs e)
{
datagrideview1.SelectedIndex = -1;
}
private void dgGrid_CellListSelect(object sender, CellEventArgs e)
{
if (e.Cell.Column.Key == "ColumnA")
{
UltraGridRow selectedItem = ((UltraCombo)e.Cell.EditorControlResolved).SelectedRow;
if (selectedItem != null)
{
//Option A
cmbColumnB.DataSource = GetUISender<someBF>().RetrieveData(dataset).dataTable;
cmbColumnB.DataBind();
//Option B
//((UltraCombo)e.Cell.Row.Cells["ChipSetID"].EditorControlResolved).DataSource = GetUISender<someBF>().RetrieveData(dataset).dataTable;
}
}
}
There is a button that allow the datagrid to add new row.
This datagrid have 2 columns and both columns are UltraCombo. ColumnB combobox's dataSource will based on ColumnA. Based on the above code, it works if the datagrid only have 1 row, but once user add another row, both row's ColumnB will be sharing the same DataSource.
How to make sure ColumnB's DataSource stay independently without affecting other rows? It's very obvious that this happened because every row are sharing the same component which is cmbColumnB but I'm not sure on how to remove the reference
I've found the solution which is everytime create a new UltraCombo and bind it to the particular cell's EditorControl
private void dgGrid_CellListSelect(object sender, CellEventArgs e)
{
if (e.Cell.Column.Key == "ColumnA")
{
UltraGridRow selectedItem = ((UltraCombo)e.Cell.EditorControlResolved).SelectedRow;
if (selectedItem != null)
{
UltraCombo cmbValue = new UltraCombo();
cmbValue.LimitToList = true;
cmbValue.DropDownStyle = UltraComboStyle.DropDownList;
cmbValue.DataSource = GetUISender<someBF>().RetrieveData(dataset).dataTable;
cmbValue.ValueMember = someDS.someDT.someColumnIDColumn.ColumnName;
cmbValue.DisplayMember = someDS.someDT.someColumnDescriptionColumn.ColumnName;
cmbValue.BindingContext = someDg.BindingContext;
cmbValue.DataBind();
e.Cell.Row.Cells["ColumnB"].EditorControl = cmbValue;
e.Cell.Row.Cells["ColumnB"].Style = Infragistics.Win.UltraWinGrid.ColumnStyle.DropDownList;
}
}
}
I have a DataGridView with a TextBoxColumn. I would like to be able to click on the cell to enter edit mode, and when I do a drop down will appear with options for the user to pick, or if the user does not want one of those options, they are able to edit the cell (as if there was no drop down). Then when the user leaves the cell, the value (either what they typed, or what they chose) will be saved.
There are lots of answers to adding the user typed choice to the drop down list, but this is not what I want. I just want to have some common options for the user to consider before they go off and make their own choice.
I do not want to have a button to popup another input dialog. I do not want to chanbe the column to a ComboBoxColumn. I do not care if the dropdown arrow is shown at all times or not.
I have tried to change the TextBoxCell to a ComboBoxCell on EditingContolShowing, but this is proving to be a pointless effort.
Are there any suggestions for this?
One option you could use is AutoComplete. This can mimic most of the desired behavior on a DataGridViewTextCell, with exception of displaying all options on entering the textcell, and without the need of converting the cell type to a ComboBox.
This could be handled in the DataGridView EditingControlShowing event:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (e.Control is TextBox)
{
TextBox box = e.Control as TextBox;
box.AutoCompleteCustomSource = new AutoCompleteStringCollection();
box.AutoCompleteCustomSource.AddRange(new string[] { "Foo", "Bar", "Baz" });
box.AutoCompleteMode = AutoCompleteMode.Suggest;
box.AutoCompleteSource = AutoCompleteSource.CustomSource;
}
}
Given, the user must enter text for any option to show. If the desired behavior requires all options to show upon entering the textbox, this would not be your best option. But if that is secondary to all other required behaviors (suggested options, accepts non-option entries, doesn't always have to show, etc), this is a viable solution.
Edit
This worked in all the following situations:
DataGridView is data bound.
Binding the DataSource:
public BindingList<Example> Examples { get; set; }
this.Examples = new BindingList<Example>();
dataGridView1.DataSource = this.Examples;
Where Example is a simple class:
public class Example
{
public string First { get; set; }
public string Last { get; set; }
public string Test { get; set; }
}
Manually adding column(s).
Just an empty column:
DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();
col.Name = "Extra";
col.HeaderText = "Extra";
this.dataGridView1.Columns.Add(col);
Both 1 and 2 combined.
Just set the cells you want to be a ComboBox to the DataGridViewComboBoxCell type:
var cb1 = new DataGridViewComboBoxCell();
cb1.Items.Add("Yes");
cb1.Items.Add("No");
dgv.Rows[1].Cells[1] = cb1;
var cb2 = new DataGridViewComboBoxCell();
cb2.Items.Add("Blue");
cb2.Items.Add("Red");
dgv.Rows[3].Cells[1] = cb2;
Then use the EditingControlShowing event to change the style of the DropDown to allow editing:
void dgv_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e) {
ComboBox cb = e.Control as ComboBox;
if (cb != null) {
cb.DropDownStyle = ComboBoxStyle.DropDown;
}
}
Use the CellValidating event to add any typed items into the list that aren't already there:
void dgv_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
var cb = dgv.Rows[e.RowIndex].Cells[e.ColumnIndex] as DataGridViewComboBoxCell;
if (cb != null && !cb.Items.Contains(e.FormattedValue)) {
cb.Items.Add(e.FormattedValue);
if (dgv.IsCurrentCellDirty) {
dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = e.FormattedValue;
}
}
I've a custom combobox template because of some binding stuff that won't work with the 'default' ComboBoxColumn.
To make it look 'nice' I've one template for the edit mode (a Combobox) and one for the 'normal' mode (a Label).
Now, because of that I've to commit the edit made to the combobox manually inside the CellEditEnding event
private bool changeCommitInProgress = false;
private void table_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.EditingElement is ContentPresenter && e.EditAction == DataGridEditAction.Commit)
{
if (!changeCommitInProgress)
{
changeCommitInProgress = true;
DataGrid grid = (DataGrid)sender;
grid.CommitEdit(DataGridEditingUnit.Row, false);
changeCommitInProgress = false;
}
}
}
The problem with this is, that it'll remove the focus from the entire datagrid. Just to be on the safe side, these are the only properties I changed on the datagrid (aside from the Name property and the ItemsSource):
grid.AutoGenerateColumns = false;
grid.IsSynchronizedWithCurrentItem = true;
grid.SelectionUnit = DataGridSelectionUnit.Cell;
This is a fun question. I have done similar with a nested DataList where I had to add a new row after last entry and focus on the first textbox of the newly generated row, maybe you can extrapolate my strategy to fit your situation?
protected void calcAvg(object sender, CommandEventArgs e)
{
int row = Convert.ToInt32(e.CommandArgument.ToString()) - 1;
DataListItem ActiveRow = dlMeasurements.Items[row];
// Snipped code doing stuff with current row
// Compare how many rows completed to number of rows requested
if (!(row + 1 == Convert.ToInt32(txtSample.Text)))
{
// Create new row
DataRow drNew = nextMeas.Tables[0].NewRow();
nextMeas.Tables[0].Rows.Add(drNew);
// Change item index and rebind
dlMeasurements.EditItemIndex = row + 1;
dlMeasurements.DataSource = nextMeas.Tables[0];
dlMeasurements.DataBind();
//Set focus with the Script Manager
smInspection.SetFocus((TextBox)(dlMeasurements.Items[row + 1].FindControl("txtRead1")));
}
else
{
// Otherwise close the measurements and show exit button
dlMeasurements.EditItemIndex = -1;
dlMeasurements.DataSource = nextMeas.Tables[0];
dlMeasurements.DataBind();
btnSaveAndPrint.Visible = true;
}
}
}
I need to show a datagrid inside another datagrid. I have done this by using RowDetailsTemplate and adding a datagrid in it. But the main problem is, I need to show multiple inner grids at same time. When the selected item is changed, the inner datagrid of the previous selected item is not displayed. Any suggestions :(
I am using expander control to show/hide the details. When expander control is opened, I am changing the RowDetailstemplate's visiblity to true.
When the selected item is changed, RowDetailsTemplate of the current selected row is only being visible if I expand the expander.
You can control the visibility of the row details of each row using the DataGridRow.DetailsVisibility property.
Perhaps you also need to change DataGrid.RowDetailsVisibilityMode to another value than VisibleWhenSelected
Found the answer,
private void Expander_Expanded(object sender, RoutedEventArgs e)
{
int rowIndex = this.DataGridForEvents.SelectedIndex;
List<DataGridRow> rows = GetRows();
rows[rowIndex].DetailsVisibility = Visibility.Visible;
}
private void Expander_Collapsed(object sender, RoutedEventArgs e)
{
int rowIndex = this.DataGridForEvents.SelectedIndex;
List<DataGridRow> rows = GetRows();
rows[rowIndex].DetailsVisibility = Visibility.Collapsed;
}
public List<DataGridRow> GetRows()
{
List<DataGridRow> rows = new List<DataGridRow>();
foreach (var rowItem in this.DataGridForEvents.ItemsSource)
{
this.DataGridForEvents.ScrollIntoView(rowItem, this.DataGridForEvents.Columns.Last());
FrameworkElement el = this.DataGridForEvents.Columns.Last().GetCellContent(rowItem);
DataGridRow row = DataGridRow.GetRowContainingElement(el.Parent as FrameworkElement);
if (row != null)
rows.Add(row);
}
return rows;
}