dataGridView ComboBox Event Handler Problem - c#

I am having a problem with the handling of an index changed event for a comboBox that resides inside a dataGridView. I write an method to handle the comboBox selection change using either a delegate:
ComboBox.SelectedIndexChanged -= delegate { ComboBoxIndexChanged(); };
ComboBox.SelectedIndexChanged += delegate { ComboBoxIndexChanged(); };
or an EventHandler:
comboBox.SelectedIndexChanged += new EventHandler(ComboBoxIndexChanged);
but both methods do not work as expected. That is, when you click on your selection within the comboBox (contained within the dataGridView) it takes multiple clicks to cause my ComboBoxIndexChanged(); method to function proper, that if it decides to function at all. What is the best way to overcome/go-about specifying an event on an indexedChange of a comboBox within a dataGridView?
The code I am currently using in context is as follows:
private void dataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
try
{
if (this.dataGridView.CurrentCell.ColumnIndex == (int)Column.Col)
{
ComboBox comboBox = e.Control as ComboBox;
if (comboBox != null)
{
comboBox.SelectedIndexChanged += new EventHandler(ComboBoxIndexChanged);
}
}
return;
}
catch (Exception Ex)
{
Utils.ErrMsg(Ex.Message);
return;
}
}
and the event ComboBoxIndexChanged is:
private void ComboBoxIndexChanged(object sender, EventArgs e)
{
// Do some amazing stuff...
}
I have read a similar thread on StackOverFlow which states that there is a problem with dealing with the comboBox change event this way, but I cannot get the solution to work. The post can be found here: "SelectedIndexChanged" event in ComboBoxColumn on Datagridview. It says:
"Things get complicated since they optimized the DataGridView by only having one editing control for all the rows. Here's how I handled a similar situation:
First hook up a delegate to the EditControlShowing event:
myGrid.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(
Grid_EditingControlShowing);
...
Then in the handler, hook up to the EditControl's SelectedValueChanged event:
void Grid_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
ComboBox combo = e.Control as ComboBox;
if (combo != null)
{
// the event to handle combo changes
EventHandler comboDelegate = new EventHandler(
(cbSender, args) =>
{
DoSomeStuff();
});
// register the event with the editing control
combo.SelectedValueChanged += comboDelegate;
// since we don't want to add this event multiple times, when the
// editing control is hidden, we must remove the handler we added.
EventHandler visibilityDelegate = null;
visibilityDelegate = new EventHandler(
(visSender, args) =>
{
// remove the handlers when the editing control is
// no longer visible.
if ((visSender as Control).Visible == false)
{
combo.SelectedValueChanged -= comboDelegate;
visSender.VisibleChanged -= visibilityDelegate;
}
});
(sender as DataGridView).EditingControl.VisibleChanged +=
visibilityDelegate;
}
}"
This issue I have with this is that "VisSender" is not defined hence the event "VisibleChanged" cannot be used.
Any help from you lads, is as always, most appreciated.

Sounds like you want the changes to be committed as soon as the user changes the drop down box, without them having to click off of the cell. In order to do this you will need to force the commit when the change happens (using CommitEdit, there is also an example on the MSDN page). Add this to your DataGridView:
// This event handler manually raises the CellValueChanged event
// by calling the CommitEdit method.
void dataGridView1_CurrentCellDirtyStateChanged(object sender,
EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
Then you could just listen for the CellValueChanged and avoid having to try and register for the ComboBoxValueChanged event on the underlying editing control.

Related

Fire event programmatically C#

I have several radio buttons inside a container. For each one I have the CheckedChangedevent so I have a code like this
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
if ((sender as RadioButton).Checked)
// do stuff...
}
private void radioButton2_CheckedChanged(object sender, EventArgs e)
{
if ((sender as RadioButton).Checked)
// do stuff...
}
private void radioButton3_CheckedChanged(object sender, EventArgs e)
{
if ((sender as RadioButton).Checked)
// do stuff...
}
// ... and so on...
Then I must fire the CheckedChanged event for the currently checked radioButton. To get the radioButton I used this code:
RadioButton checkedButton = container.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked);
Now how can I fire the CheckedChanged event for checkedButton?
EDIT: I'm using WinForms. My radio buttons are in a tabPage. When I open the tabPage I need to know what is the currently checked radioButton and fire the corresponding checkedChanged event. This is because when I select another tabPage I perform other actions and, going back to the tabPage containing the radio buttons, I need to restore the previous state.
Changing the value of the Checked property should fire the event:
checkedButton .Checked = !checkedButton .Checked;
You may also call the event handler explicitly, e.g.:
RadioButton checkedButton = container.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Checked);
switch (checkedButton.Name)
{
case "radioButton1":
radioButton1_CheckedChanged(this, EventArgs.Empty);
break;
case "radioButton2":
radioButton2_CheckedChanged(this, EventArgs.Empty);
break;
case "radioButton3":
radioButton3_CheckedChanged(this, EventArgs.Empty);
break;
}
Depending on your requirements, you may of course want to consider using the same event handler for all RadioButtons.

Manage CheckedListBox ItemCheck event to run after an item checked not before

I am using CheckedListBox in C# Window Forms Application.
I want to do something after one item checked or unchecked but ItemCheck event runs before the item checked/unchecked .
How can I do that?
CheckedListBox.ItemCheck Event
The check state is not updated until after the ItemCheck event occurs.
To run some codes after the item checked, you should use a workaround.
Best Option
You can use this option (Thanks to Hans Passant for this post):
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
this.BeginInvoke(new Action(() =>
{
//Do the after check tasks here
}));
}
Another option
If in middle of ItemCheck Event, you need to know state of item, you should use e.NewValue instead of using checkedListBox1.GetItemChecked(i)
If you need to pass a list of checked indices to a method do this:
Using the code:
var checkedIndices = this.checkedListBox1.CheckedIndices.Cast<int>().ToList();
if (e.NewValue == CheckState.Checked)
checkedIndices.Add(e.Index);
else
if(checkedIndices.Contains(e.Index))
checkedIndices.Remove(e.Index);
//now you can do what you need to checkedIndices
//Here if after check but you should use the local variable checkedIndices
//to find checked indices
Another Option
In middle of ItemCheck event, remove handler of ItemCheck, SetItemCheckState and then add handler egain.
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
var control = (CheckedListBox)sender;
// Remove handler
control.ItemCheck -= checkedListBox_ItemCheck;
control.SetItemCheckState(e.Index, e.NewValue);
// Add handler again
control.ItemCheck += checkedListBox_ItemCheck;
//Here is After Check, do additional stuff here
}
Try searching more for answers, cause here it is
private void clbOrg_ItemCheck(object sender, ItemCheckEventArgs e)
{
CheckedListBox clb = (CheckedListBox)sender;
// Switch off event handler
clb.ItemCheck -= clbOrg_ItemCheck;
clb.SetItemCheckState(e.Index, e.NewValue);
// Switch on event handler
clb.ItemCheck += clbOrg_ItemCheck;
// Now you can go further
CallExternalRoutine();
}
And the link:
Which CheckedListBox event triggers after a item is checked?
You can hook up an event on ItemCheck. You can do it by right clicking your checkboxlist and select properties. And at the right side you will see the property tab, click the event tab button and locate ItemCheck event and double click it. It will generate a event method for you depend on your checkboxlist name like below.
Then, you can verify selected/checked checkbox using code below.
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
var checkBoxName = checkedListBox1.Items[e.Index];
Console.WriteLine("Current {0}, New {1} , value {2}", e.CurrentValue, e.NewValue, checkBoxName);
}

flow panel with listview

I'm creating listviews in a flowpanel at run time which later will accept drag and dropped files. the reason being is i want these to act as folders so a user double clicks and gets a window displaying the contents.
i'm having difficulty setting up the events for my listviews as they are added.
how do i create some events (like MouseDoubleClick and DragDrop) dynamically for each added listview? can i create a single function for both of these events and have listview1, listview2, listviewX use it?
i have a button that is adding the listviews, which works fine. please advise, i apologize if this is too conceptual and not exact enough.
private void addNewWOButton_Click(object sender, EventArgs e)
{
ListView newListView = new ListView();
newListView.AllowDrop = true;
flowPanel.Controls.Add(newListView);
}
You would have to have the routine already created in your code:
private void listView_DragDrop(object sender, DragEventArgs e) {
// do stuff
}
private void listView_DragEnter(object sender, DragEventArgs e) {
// do stuff
}
and then in your routine, your wire it up:
private void addNewWOButton_Click(object sender, EventArgs e)
{
ListView newListView = new ListView();
newListView.AllowDrop = true;
newListView.DragDrop += listView_DragDrop;
newListView.DragEnter += listView_DragEnter;
flowPanel.Controls.Add(newListView);
}
You would have to check who the "sender" is if you need to know which ListView control is firing the event.
You can also just use a lambda function for simple things:
newListView.DragEnter += (s, de) => de.Effect = DragDropEffects.Copy;
Just make sure to unwire the events with -= if you also remove the ListViews dynamically.
To answer the other half of your question, you can use a single handler for any event, from any source, that has the handler's signature. In the body of the handler, you just have to check the sender argument to determine which control raised the event.
You need a way to tell one control from a different one of the same class, however. One way to do this is to make sure to set the Name property on each control when you create it; e.g., newListView.Name = "FilesListView".
Then, before you do anything else in your event handler, check the sender.
private void listView_DragDrop(object sender, DragEventArgs e) {
ListView sendingListView = sender as ListView;
if(sendingListView == null) {
// Sender wasn't a ListView. (But bear in mind it could be any class of
// control that you've wired to this handler, so check those classes if
// need be.)
return;
}
switch(sendingListView.Name) {
case "FilesListView":
// do stuff for a dropped file
break;
case "TextListView":
// do stuff for dropped text
break;
.....
}
}

About datagridview control's event

I'm developed an application for the datagridview filtering . And i used the datagridview's dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
event for filtering.
But i want to handle it on the key press event for the datagridview cell. But i'm not getting that type of event.
the datagridview event should occure
on the each keypress..
So can anybody tell me that which event should i use for the datagridview?
please help me...
thanx
The DataGridView.KeyPress event will not be raised when the user types in a particular cell. If you want to be notified each time they press a key while editing content in a cell, you have two options:
Handle the KeyPress event that is raised directly by the editing control itself (which you can access using the EditingControlShowing event).
For example, you might use the following code:
public class Form1 : Form
{
public Form1()
{
// Add a handler for the EditingControlShowing event
myDGV.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(myDGV_EditingControlShowing);
}
private void myDGV_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
// Ensure that the editing control is a TextBox
TextBox txt = e.Control as TextBox;
if (txt != null)
{
// Remove an existing event handler, if present, to avoid adding
// multiple handler when the editing control is reused
txt.KeyPress -= new KeyPressEventHandler(txt_KeyPress);
// Add a handler for the TextBox's KeyPress event
txt.KeyPress += new KeyPressEventHandler(txt_KeyPress);
}
}
private void txt_KeyPress(object sender, KeyPressEventArgs e)
{
// Write your validation code here
// ...
MessageBox.Show(e.KeyChar.ToString());
}
}
Create a custom class that inherits from the standard DataGridView control and override its ProcessDialogKey method. This method is designed to process each key event, even those
that occur on the editing control. You can either handle the key presses inside of that overridden method, or raise an event of your own to which you can attach a separate handler method.

C# ComboBox GotFocus

I have a C# ComboBox using WPF. I have code that executes when the ComboBox's GotFocus is activated. The issue is that the GotFocus event is executed every time a selection is made from the ComboBox. For example, the GotFocus is executed when you first click on the ComboBox and then when you make a selection even though you have not click on any other control.
Is it possible to prevent this event from firing if a selection is being made in the list or is there a flag or something else in the event handler that can be used to determine if the GotFocus event handler was fired as a result of the user selecting an item in the list?
You can solve this problem with next verification:
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() == typeof(ComboBoxItem))
return;
//Your code here
}
This code will filter all focus events from items (because they use bubble routing event). But there is another problem - specific behaviour of WPF ComboBox focus: when you open drop-down list with items your ComboBox losing focus and items get. When you select some item - item losing focus and ComboBox get back. Drop-down list is like another control. You can see this by simple code:
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
Trace.WriteLine("Got " + DateTime.Now);
}
}
private void myComboBox_LostFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
Trace.WriteLine("Lost " + DateTime.Now);
}
}
So you will get anyway atleast two focus events: when you select ComboBox and when you selecting something in it (focus will return to ComboBox).
To filter returned focus after selecting item, you can try to use DropDownOpened/DropDownClosed events with some field-flag.
So the final code with only 1 event of getting focus:
private bool returnedFocus = false;
private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem) && !returnedFocus)
{
//Your code.
}
}
private void myComboBox_LostFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
{
ComboBox cb = (ComboBox)sender;
returnedFocus = cb.IsDropDownOpen;
}
}
Choose from this examples what you actually need more for your application.
I'm not too hot on WPF; but if you're trying to detect changes to the list (click on new value etc) you can use SelectedIndexChanged events..
On the other hand, if you really do want to know simply when the control is focussed, can you filter it by saying something like;
if (combo1.Focused && combo1.SelectedIndex == -1)
{
...
}
.. ? It really depends on what youre trying to detect, exactly.
Another solution is used is to determine whether the new focused element is an existing item in the combobox. If true then the LostFocus event should not be performed, because the combobox still has focus. Otherwise an element outside the combobox received focus.
In the code snipplet below I added the functionality in a custom combobox class
public class MyComboBox : System.Windows.Controls.Combobox
{
protected override void OnLostFocus(RoutedEventArgs e)
{
//Get the new focused element and in case this is not an existing item of the current combobox then perform a lost focus command.
//Otherwise the drop down items have been opened and is still focused on the current combobox
var focusedElement = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));
if (!(focusedElement is ComboBoxItem && ItemsControl.ItemsControlFromItemContainer(focusedElement as ComboBoxItem) == this))
{
base.OnLostFocus(e);
/* Your code here... */
}
}
}

Categories