I have a problem with checkbox. I'm trying to explain.
My Datagrid can have multiple row, so multiple checkbox.
When one or many checkbox is true, so a button IsEnable=true. But if no checkbox is true, so the button is disable.
Maybe an issue with a count of checkbox IsChecked ? Or maybe the click processus is not appropriate?
Here is my code :
private void Chk_UID_IsSelected_Click(object sender, RoutedEventArgs e)
{
var Chkbox = sender as CheckBox;
if (Chkbox.IsChecked == true)
{
UID_Disconnect.IsEnabled = true;
}
else
{
UID_Disconnect.IsEnabled = false;
}
}
But my code check only one checkbox in fact. If i click on 2 checkbox and uncheck one, my button have an incorrect state.
My design :
Another try with no result:
private void Chk_UID_IsSelected_Click(object sender, RoutedEventArgs e)
{
foreach (CheckBox c in dgConnected_Users.ItemsSource)
{
var Chkbox = sender as CheckBox;
UID_Disconnect.IsEnabled = Chkbox.IsChecked == true;
}
}
Here another try with no result:
private void Chk_UID_IsSelected_Click(object sender, RoutedEventArgs e)
{
int checkedBoxes = dgConnected_Users.Items
.OfType<CheckBox>().Count(c => (bool)c.IsChecked == true);
if (checkedBoxes > 0)
{
// You shall pass!
UID_Disconnect.IsEnabled = true;
}
else
{
// None shall pass
UID_Disconnect.IsEnabled = false;
}
}
OK I have progress in my code, here the new one :
private void Chk_UID_IsSelected_Click(object sender, RoutedEventArgs e)
{
foreach (DataRowView dr in dgConnected_Users.ItemsSource)
{
var Chkbox = sender as CheckBox;
if (Chkbox.IsChecked == true)
{
isAnyChecked++;
}
else
{
isAnyChecked--;
}
}
if (isAnyChecked > 0)
{
UID_Disconnect.IsEnabled = true;
}
else
{
UID_Disconnect.IsEnabled = false;
}
}
That do the staff, but i know that if I check just one checkbox, 'isAnyChecked' = 2, or it must be equal 1.
I have a Syncfusion's GridGroupingControl. I would like to do a custom action with the column, say a custom "hide column".
There is a way to identify the column name when right clicking (I display a context menu by the way) on the column's header or cell?
I have a *ContextMenuStrip_Opening*, but it does not bring any info about the column.
I have also *myGrid_TableControlCellClick* but this one action only on the cell and only on the left click...
Well, think it
int selected_colum; // "selected_colum " need be a global var
private void dtg_contatos_MouseDown(object sender, MouseEventArgs e)
{
try
{
if (e.Button == MouseButtons.Right)
{
dtg_contatos.ClearSelection();
var hti = dtg_contatos.HitTest(e.X, e.Y);
dtg_contatos.Columns[hti.ColumnIndex].Selected = true;
selected_colum = hti.ColumnIndex; // here you set to global var de colum to use at contextmenustrip click
dtg_contatos.Columns[selected_colum].Visible = false; // this you will place at contextmenustrip to hide the column
}
}
catch
{
}
}
You could handle the TableControlMouseDown event on the GridGroupingControl, check for the right mouse button, and then get the ColumnDescriptor from the mouse event location, and save the column name (and maybe HeaderText to show in the menu):
this.gridGroupingControl1.TableControlMouseDown += gridGroupingControl1_TableControlMouseDown;
private string rightClickCol;
void gridGroupingControl1_TableControlMouseDown(object sender, Syncfusion.Windows.Forms.Grid.Grouping.GridTableControlMouseEventArgs e)
{
if (e.Inner.Button == System.Windows.Forms.MouseButtons.Right)
{
rightClickCol = string.Empty;
Syncfusion.Windows.Forms.Grid.Grouping.GridColumnDescriptor columnDescriptor =
gridGroupingControl1.TableControl.GetHeaderColumnDescriptorAt(e.Inner.Location);
if (columnDescriptor != null)
rightClickCol = columnDescriptor.Name;
}
}
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
if (!string.IsNullOrEmpty(rightClickCol))
{
hideColumnToolStripMenuItem.Text = "Hide " + rightClickCol;
hideColumnToolStripMenuItem.Enabled = true;
}
else
{
hideColumnToolStripMenuItem.Text = "Hide Column";
hideColumnToolStripMenuItem.Enabled = false;
}
}
private void hideColumnToolStripMenuItem_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(rightClickCol))
gridGroupingControl1.TableDescriptor.VisibleColumns.Remove(rightClickCol);
}
I am using an XtraGridView control in my winform. Now I added a RepositoryItemHyperLinkEdit to it. But I want to show/hide each link according to the row data.
How can I achieve this?
Thanks for any help..
I tried the next code but it did not work, the cell did not be empty.
("Show link" part is ok, but String.Empty does not work)
private void xgvGrid_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
{
if (e.Column == gcControlField)
{
if (xgvGrid.GetFocusedRowCellValue("ControlField") != null)
{
if (xgvGrid.GetFocusedRowCellValue("ControlField").ToString() == "LINK")
e.DisplayText = "Show link";
else
e.DisplayText = string.Empty;
}
}
}
You can add your checking in the event GridView.CustomColumnDisplayText.
e.g. Each row is bind to a Person instance
private void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
{
// gcLink is your column using repositoryitemhyperlinkedit
if (e.Column == gcLink)
{
var person = gridView1.GetRow(e.RowHandle) as Person;
if (person != null)
{
// Logic to show/hide the link based on other field
if (person.FirstName == "John")
e.DisplayText = string.Empty;
else
e.DisplayText = person.Link;
}
}
}
How to make column with row number? Solutions that works with default WPF dataGrid don't work with DevExpress...
You need to add a unboundcolumn to your gridview, you can do this from the designer or from code.
var col = gridView1.Columns.Add();
col.FieldName = "counter";
col.Visible = true;
col.UnboundType = DevExpress.Data.UnboundColumnType.Integer;
gridView1.CustomUnboundColumnData += gridView1_CustomUnboundColumnData;
void gridView1_CustomUnboundColumnData(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDataEventArgs e)
{
if (e.IsGetData)
e.Value = e.ListSourceRowIndex+1;
}
set the column caption to "#"
then add this event to the gridView1
private void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
{
if (e.Column.Caption == "#")
{
e.DisplayText = (e.RowHandle + 1).ToString();
}
}
I have setup a ComboBoxColumn for my DataGridView and set its selectable values from an enumeration. It mostly works as I would like with the following exception.
Whenever I click the dropdown arrow and then select one of the enum values, it remains in sort of a "intermediate" state where the CellValueChanged event isn't triggered. I need to focus on another cell or another control for the event to fire.
I also have an event handler for the DataGridView's Leaving event which "validates" the contents by making sure that no cell is empty.
So, if I create a row and fill all the cells and come to the (currently blank) ComboBox column, change it to a value, and then click a Run button; my error dialog pops up because the ComboBox selection wasn't "saved".
How can I get around this? Is there a way that after I select a value from the drop down it automatically "sets" the value?
Thanks!
You should use CurrentCellDirtyStateChanged event and force a commit edit on the grid:
private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
Hope it helps!
I would extend Moop's answer by checking the cell type instead of the column type.
dataGridView1.CurrentCellDirtyStateChanged += dataGridView1_CurrentCellDirtyStateChanged;
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (CurrentCell is DataGridViewComboBoxCell)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
dataGridView1.EndEdit();
}
}
I would extend ionden's answer by checking if the DataGridViewColumn is the type of DataGridViewComboBoxColumn before forcing the CommitEdit. This will prevent other DataGridViewColumn objects from committing too early.
dataGridView1.CurrentCellDirtyStateChanged += dataGridView1_CurrentCellDirtyStateChanged;
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
DataGridViewColumn col = dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex];
if (col is DataGridViewComboBoxColumn)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
The CurrentCellDirtyStateChanged event fixed mouse interaction for this issue, but it breaks keyboard interaction - using F4 then up/down arrow, every arrow click results in a dirty state change and commits the edit. The solution I found, was to grab the "DataGridViewComboBoxEditingControl" when it's created, and attach a DropDownClosed event to it. This works for keyboard and mouse interaction. In this example, we extended DataGridView so every instance would inherit this functionality:
protected override void OnEditingControlShowing(DataGridViewEditingControlShowingEventArgs e)
{
DataGridViewComboBoxEditingControl control = e.Control as DataGridViewComboBoxEditingControl;
if (control != null)
{
control.DropDownClosed -= ComboBoxDropDownClosedEvent;
control.DropDownClosed += ComboBoxDropDownClosedEvent;
}
base.OnEditingControlShowing(e);
}
void ComboBoxDropDownClosedEvent(object sender, EventArgs e)
{
DataGridViewComboBoxCell cell = CurrentCell as DataGridViewComboBoxCell;
if ((cell != null) && cell.IsInEditMode)
{
CommitEdit(DataGridViewDataErrorContexts.Commit);
EndEdit();
}
}
In some cases, the value won't stick until the focus has left the row entirely. In that case, the only way to force the current edit to end is to end it on the whole binding context:
mGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
mGridView.BindingContext[mGridView.DataSource].EndCurrentEdit(); // <<===
I found this tip here.
I spend like two hours searching for an error because I did not notice that the cell value does not get saved if it´s not defocused, or better to say I just noticed that the cell is not defocused because the combobox whited out while saving(btn event).
Not only that, the EditOnEnter-Mode prevails that most other methods shown above work. The reason to use EditOnEnter is that when you use a DataGridViewComboBoxColumn, you have to click two times to open the dropdown if you do not set EditMode to EditOnEnter.
this.dataGridView.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2;
this.dataGridView.EndEdit();
this.dataGridView.EditMode = DataGridViewEditMode.EditOnEnter;
I hope this helps. It cost me around two hours wondering why the value in the object is not the same then shown on the GUI.
I am adding my answer as a follow-up to the discussion that has already occurred. I was trying to build a DataGridView that had different comboboxes per row. They also had to be responsive to a single click. And, when the selection was made, another cell in the row needed to be changed according to the combobox selection. The change needed to happen as soon as the selection was made. My main problem, like the OP's, was the change wouldn't happen until the combobox lost focus.
So, here is a full working minimal example of such a DataGridView. I had to bring it down to a minimum because getting all my requirements to work at the same time was tricky. Several SO posts went into making this, and I will update my post with references later. But for now, here goes...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace TestDGV
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Panel panel2;
private DataGridView TestGrid;
private void InitializeComponent()
{
this.panel2 = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// panel2
//
this.panel2.Dock = DockStyle.Fill;
this.panel2.Name = "panel2";
this.panel2.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(661, 407);
this.Controls.Add(this.panel2);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
private void Form1_Load(object sender, EventArgs e)
{
//basic grid properties
TestGrid = new DataGridView();
TestGrid.Dock = DockStyle.Fill;
TestGrid.AutoGenerateColumns = false;
TestGrid.Name = "TestGrid";
TestGrid.ReadOnly = false;
TestGrid.EditMode = DataGridViewEditMode.EditOnEnter;
//Event handlers
TestGrid.DataBindingComplete += TestGrid_DataBindingComplete;
TestGrid.CurrentCellDirtyStateChanged += TestGrid_CurrentCellDirtyStateChanged;
TestGrid.CellValueChanged += TestGrid_CellValueChanged;
//columns
var textCol = new DataGridViewTextBoxColumn();
textCol.HeaderText = "Text";
textCol.Name = "Text";
textCol.DataPropertyName = "Text";
textCol.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
TestGrid.Columns.Add(textCol);
var comboCol = new DataGridViewComboBoxColumn();
comboCol.HeaderText = "ComboBox";
comboCol.Name = "ComboBox";
comboCol.AutoComplete = true;
comboCol.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
TestGrid.Columns.Add(comboCol);
var resultCol = new DataGridViewTextBoxColumn();
resultCol.HeaderText = "Result";
resultCol.Name = "Result";
resultCol.DataPropertyName = "Result";
resultCol.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
TestGrid.Columns.Add(resultCol);
//Bind the data
Datum.TestLoad();
TestGrid.DataSource = Datum.Data;
panel2.Controls.Add(TestGrid);
}
void TestGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0 || e.ColumnIndex < 0)
return;
var row = TestGrid.Rows[e.RowIndex];
var cell = row.Cells[e.ColumnIndex];
if (cell is DataGridViewComboBoxCell)
{
var val = cell.Value as string;
var datum = row.DataBoundItem as Datum;
datum.Current = val;
row.Cells["Result"].Value = datum.Result;
TestGrid.InvalidateRow(e.RowIndex);
}
}
void TestGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if(TestGrid.CurrentCell is DataGridViewComboBoxCell)
{
TestGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
TestGrid.EndEdit();
}
}
void TestGrid_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewRow row in TestGrid.Rows)
{
var datum = row.DataBoundItem as Datum;
if (datum == null)
return;
var cell = row.Cells["ComboBox"] as DataGridViewComboBoxCell;
if (cell.DataSource == null)
{
cell.DisplayMember = "KeyDisplayValue";
cell.ValueMember = "KeyValue";
cell.DataSource = (row.DataBoundItem as Datum).Combo;
cell.Value = (row.DataBoundItem as Datum).Current;
}
}
TestGrid.DataBindingComplete -= TestGrid_DataBindingComplete;
}
public class Datum
{
public static void TestLoad()
{
var t1 = new Triplet[] {
new Triplet("1", "World", "Everyone" ),
new Triplet("2", "Charlie", "Friend of Algernon" ),
new Triplet("3", "Lester", "Phenomenal programmer" ),
};
var t2 = new Triplet[] {
new Triplet("1", "World", "Everyone" ),
new Triplet("4", "Mary", "Wife of George Bailey" ),
new Triplet("3", "Lester", "Phenomenal programmer" ),
};
Data.Add(new Datum("hello, ", t1.ToList()));
Data.Add(new Datum("g'bye, ", t2.ToList()));
}
public static List<Datum> Data = new List<Datum>();
public Datum(string text, List<Triplet> combo)
{
this._text = text;
this._combo = combo.ToDictionary<Triplet,string>(o => o.KeyValue);
this.Current = combo[0].KeyValue;
}
private string _text;
public string Text
{
get
{
return _text;
}
}
private Dictionary<string, Triplet> _combo;
public List<Triplet> Combo
{
get
{
return _combo.Values.ToList();
}
}
private string _result;
public string Result
{
get
{
return _result;
}
}
private string _current;
public string Current
{
get
{
return _current;
}
set
{
if (value != null && _combo.ContainsKey(value))
{
_current = value;
_result = _combo[value].Description;
}
}
}
}
public class Triplet
{
public string KeyValue { get; set; }
public string KeyDisplayValue { get; set; }
public string Description { get; set; }
public Triplet(string keyValue, string keyDisplayValue, string description)
{
KeyValue = keyValue;
KeyDisplayValue = keyDisplayValue;
Description = description;
}
}
}
}
Thanks to Droj for the tip about EndCurrentEdit, which I needed to make it work for me.
This is what I ended up doing to instantly commit DataGridViewComboBoxColumns and DataGridViewCheckBoxColumns:
private void dataGridViewEnumerable_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
var dataGridView = sender as DataGridView;
if (dataGridView == null || dataGridView.CurrentCell == null)
return;
var isComboBox = dataGridView.CurrentCell is DataGridViewComboBoxCell;
if ((isComboBox || dataGridView.CurrentCell is DataGridViewCheckBoxCell)
&& dataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit)
&& isComboBox && dataGridView.EndEdit())
dataGridView.BindingContext[dataGridView.DataSource].EndCurrentEdit();
}
Here's how I solved the issue
Private Sub dgvEcheancier_CurrentCellDirtyStateChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dgvEcheancier.CurrentCellDirtyStateChanged
nbreClick += 1
With dgvEcheancier
Select Case .CurrentCell.ColumnIndex
Case 9
Dim col As DataGridViewComboBoxColumn = .Columns(9)
If TypeOf (col) Is DataGridViewComboBoxColumn Then
dgvEcheancier.CommitEdit(DataGridViewDataErrorContexts.Commit)
If nbreClick = 2 Then
MessageBox.Show("y" & "val=" & .CurrentCell.Value)
nbreClick = 0
End If
End If
End Select
End With
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
dataGridView1.BeginEdit(true);
ComboBox cmbMiCtrl=(ComboBox)dataGridView1.EditingControl;
string Valor= cmbMiCtrl.Text;
dataGridView1.EndEdit();
}
One problem that I saw : It won't work if you choose :
GridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;
You should use CellValueChanged which fires the change event on grid and inside the event you should commit changes and leave the control in order to save the item after it is selected.
private void FilterdataGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
FilterdataGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
FilterdataGrid.EndEdit(DataGridViewDataErrorContexts.LeaveControl);
}
Hope it helps!