I have the following code:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
DataGridView dgv = sender as DataGridView;
if (dgv.Columns[e.ColumnIndex].Name.Equals("edit"))
{
string status = dataGridView1.Rows[e.RowIndex].Cells["status"].Value.ToString();
if (status == "1")
{
dgv.Rows[e.RowIndex].Cells["edit"].Value = Properties.Resources.edit_disable;
}
}
}
When I try to replace image here:
dgv.Rows[e.RowIndex].Cells["edit"].Value = Properties.Resources.edit_disable;
Program hangs and image and is rendered infinity
You selected the wrong event for changing an Image. The event dataGridView1_CellFormatting is fired when an image changes, so if you use this event to change an image, you are getting into an infinite loop.
Since your code is querying the cell's Value, you might want to switch to a different event, which is fired when the row / cell data changes or binds, such as DataGridView.DataBindingComplete or dataGridView1.RowsAdded:
private void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
string status = dataGridView1.Rows[e.RowIndex].Cells["status"].Value.ToString();
if (status == "1")
{
dgv.Rows[e.RowIndex].Cells["edit"].Value = Properties.Resources.edit_disable;
}
}
Related
I have a DataGridView which I bind to a DataTable, through a BindingSource. Simple example code.
DataTable records;
BindingSource bindRecords;
private void InitGrid() {
records = new DataTable();
records.Columns.Add(new DataColumn("text", typeof(string)));
bindRecords = new BindingSource();
bindRecords.DataSource = records;
dgvRecords.DataSource = bindRecords;
}
Then I use the CellValidating event like this:
private void dgvRecords_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
if(e.ColumnIndex == dgvRecords.Columns["text"].Index) {
if(e.FormattedValue.ToString() == "error") {
dgvRecords[e.ColumnIndex, e.RowIndex].ErrorText = "Oops!";
}
}
}
Now when user inputs as text the literal "error", an error icon is shown in the cell. So far so good.
But if I sort the column the validation is lost. I understand that in order for the cell validating event to fire the cell must be entered and then leaved.
I also have the same problem when inserting data programmatically like this:
private void btnAddRecord_Click(object sender, EventArgs e) {
records.Rows.Add(new object[] { "error" });
}
How would I force validation to occur? I don't want hacks like traversing the grid and setting the CurrentCell.
Your problem is that the CellValidating event only seems to happen when you exit the cell (i.e. finish editing). Therefore, I tested and found that putting the code you specified into another event that fires after a sort, like CellPainting, accomplishes what you wish. For example:
private void dgvRecords_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == dgvRecords.Columns["text"].Index)
{
if (e.FormattedValue.ToString() == "error")
{
dgvRecords[e.ColumnIndex, e.RowIndex].ErrorText = "Oops!";
}
}
}
I have a datagridview with an editable combobox column, but everytime I press "Enter" on the current combobox, the text I'm writing disappears.
private void dgView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (dgView1.CurrentCell.IsInEditMode)
{
if (dgView1.CurrentCell.GetType() == typeof(DataGridViewComboBoxCell))
{
if (!((DataGridViewComboBoxColumn)dgView1.Columns[e.ColumnIndex]).Items.Contains(e.FormattedValue))
{
((DataGridViewComboBoxColumn)dgView1.Columns[e.ColumnIndex]).Items.Add(e.FormattedValue);
}
}
}
}
private void dgView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (e.Control.GetType() == typeof(DataGridViewComboBoxEditingControl))
{
ComboBox cbo = (ComboBox)e.Control;
cbo.DropDownStyle = ComboBoxStyle.DropDown;
}
}
I also tried adding the event handlers: "on key press", "on key down" and "on key up" but same problem happens.
How can I keep the current text when I press "Enter" key?
The DataGridViewComboBoxColumn does not accept any value which is not contained in the Items collection. So when user types in a new value, the current cell does simply not store the value after editing. You have to find another way to get the last value right after cell being edited. We can get the actual DataGridViewComboBoxEditingControl in the EditingControlShowing event handler, that control is actually a ComboBox, we can handle the TextChanged event. The best DataGridView event to handle to submit the new value (add to Items and show in the current cell) is the CellEndEdit event. So here is the code you should do, I've tested it and looks like it works as what you expected:
//use some variable to store the last edited value
string editingValue;
//EditingControlShowing event handler
private void dataGridView1_EidtingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e) {
var combo = e.Control as ComboBox;
if(combo != null){
combo.DropDownStyle = ComboBoxStyle.DropDown;
combo.TextChanged += (s,ev) => {
editingValue = combo.Text;
};
}
}
//CellEndEdit event handler for your dataGridView1
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e){
var comboColumn = dataGridView1.Columns[e.ColumnIndex] as DataGridViewComboBoxColumn;
if(comboColumn != null && editingValue != "" &&
!comboColumn.Items.Contains(editingValue)){
comboColumn.Items.Add(editingValue);
dataGridView1[e.ColumnIndex, e.RowIndex].Value = editingValue;
}
}
Note that the cell value is supposed to be string which is why the editingValue is declared as string, otherwise, you may have to convert the Text of the editing comboBox to the correct type of editingValue.
Working in VS 2012, WinForms, C#...
I have a ListBox I would like to populate depending upon the value selected in a ComboBox. I've tested my SQL Query and it works, but I'm getting a weird problem where, when I run my routines, my ComboBox comes up empty, as well as my ListBox. When I comment out the code in my cb_Session_SelectedValueChanged routine, my CB and LB load just fine, but when it's not commented out is when my LB and CB end up blank.
This is what I have:
private void cb_Session_SelectedValueChanged(object sender, EventArgs e)
{
listbox_Sessions.Visible = true;
LoadSessionListbox();
}
private void LoadSessionListbox()
{
int tempID = Convert.ToInt32(cb_Session.SelectedValue);
// Code here to load listbox, which works without above routine.
}
Am I missing something? Why are my CB and LB blank with that first routine added?
[EDIT]:
I put the routines which were in SelectedValueChanged in a MouseClick event and it works, but not when I want it to... You have to click a couple times to get it to re-load with the correct ID. I feel like I'm getting closer, but still not the right event.
Try this:
private void cb_Session_SelectedValueChanged(object sender, EventArgs e)
{
if(cb_Session.SelectedValue>-1)
{
listbox_Sessions.Visible = true;
LoadSessionListbox();
}
}
Figured it out!!
I ended up adding a simple if statement to my SelectedValueChanged routine, and it fixed everything!
private void cb_Sessions_SelectedValueChanged(object sender, EventArgs e)
{
listBox_Sessions.Visible = true;
if (cb_Sessions.SelectedValue != null)
LoadSessionListbox();
}
Works perfectly now.
Try in SelectedIndexChanged Event and follow
private void cb_Session_SelectedIndexChanged(object sender, EventArgs e)
{
if (cb_Session.SelectedValue == null) return;
if (cb_Session.SelectedIndex == -1) return;
listbox_Sessions.Visible = true;
LoadSessionListbox((int)cb_Session.SelectedValue);
}
private void LoadSessionListbox(int selectedValue)
{
//TODO: Do stuff
}
I have a gridview with 2 column, one is a DataGridViewCheckBoxColumn named "choose" , the other is an ordinary DataGridViewTextBoxColumn named "ID"... I want to change the text of a textbox immediately when the checked of chechkbox column changed .... but i don't know which event should i use ....
void SetTextBox()
{
TextBox1.Text="";
for (int i = 0; i < MyGrid.Rows.Count; i++)
if (Convert.ToBoolean(MyGrid.Rows[i].Cells["choose"].Value) == true)
{
TextBox1.Text += MyGrid.Rows[i].Cells["ID"].Value.ToString()+",";
}
}
private void !!!!which Event?!!!!(object sender, EventArgs e)
{
SetTextBox();
}
There's actually two events you need to deal with. Here's an example adapted from the code I'm working on right now.
private void dgvRMADetail_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dgvRMADetail.CurrentCell is DataGridViewCheckBoxCell))
{
dgvRMADetail.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
private void dgvRMADetail_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == useRowCheckboxColumn.Index)
{
// Logic for doing whatever when the checkbox is checked.
}
}
The first event tells it "Automatically commit this when it changes", the second event is "When the value is committed, do something".
I have a dropdown list and radio button. If something is selected from the dropdown by the user, I want the radio button cleared. If the radio button is selected I want the selection of the dropdown cleared. Unfortunately, this creates events that cancel each other out. I tried using the sender as shown below to determine if the value was being changed by code or by the user, but that doesn't work. How do I make these events only work if the user is the source of the action?
private void rbBlank_Checked(object sender, RoutedEventArgs e)
{
// Verify source of event
if (sender is RadioButton)
{
// Display
comboBoxTitles.SelectedIndex = -1;
}
}
private void comboBoxTitles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
// Verify source of event
if (sender is ComboBox)
{
// Display
rbBlank.IsChecked = false;
}
}
You won't be able to tell the difference between the two since the source will be the same instance for both occasions.
This doesn't answer the question directly but if you compare the SelectedIndex of comboBoxTitles in the SelectionChanged event handler, your problem should be solved
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (comboBoxTitles.SelectedIndex != -1)
{
rbBlank.IsChecked = false;
}
}
Try to compare if sender == instance of a control instead of is type of.
private void rbBlank_Checked(object sender, RoutedEventArgs e)
{
// Verify source of event
if (sender == rbBlank)
{
// Display
comboBoxTitles.SelectedIndex = -1;
}
}
private void comboBoxTitles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
// Verify source of event
if (sender == comboBoxTitles)
{
// Display
rbBlank.IsChecked = false;
}
}
If you know the IDs of those controls, you can try something like this:
System.Web.UI.WebControls.WebControl webControl = (System.Web.UI.WebControls.WebControl) sender;
if( webControl.ID == <comboboxId>)
{
//Do something
}
I havent tried this, but I guess it might work.