Combobox User manual input and Selection change - wpf

I am trying to raise two different action which will expose additional field when ever there is a selection change on the Combobox and Manual Text input.
However, one triggers the other.
SelectionChanged="ComboBoxAccount_SelectionChanged"
TextBoxBase.TextChanged="ComboBoxAccount_textChanged"
How could I exactly determine there was a user manual input and not selection change which being population by different selections on the form and by doing that raise two different events?

I have used on the ComboBoxAccount_SelectionChanged() the comboxAccount.IsKeyboardFocusWithin check to determine if it is manual input or not.
private void ComboBoxAccount_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (this.comboxAccount.IsDropDownOpen && comboxAccount.comboxAccount.IsKeyboardFocusWithin)
{.....}
else if (comboxAccount.IsKeyboardFocusWithin)
{....}
}

Related

How to get the last click event on DataGridViewCheckBoxCell

I'm using a DataGridViewCheckBoxColumn inside a DataGridView in a WinForm panel.
When a checkbox is clicked, I need to compute things that might change a Control state outside the DataGridView.
To do so, I have to handle the CellContentClick event because I need to compute only when a checkbox value is actually changed.
Grid.CellContentClick += Grid_CellContentClick
private void Grid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
dgv.EndEdit();
// Compute stuff
}
However CellContentClick doesn't always fire, while the internal event that does change the DataGridViewCheckboxCell checked state is.
Most importantly, fast successive clicks on a checkbox do not fire CellContentClick, only the first is catched until the user stops clicking.
As a result I end up in an invalid state where the control outside the DataGridView doesn't display as intended because the computation doesn't use the checkboxes final values.
I've tried to debounce the event and creating a pseudo-lock using MouseDown and the grid ReadOnly property, with no success.
Is there a way to catch only the last event of a series of clicks? Is there a better way to do this?
Thank you #Jimi and #JohnG for your insights, it helped me solving this issue.
I could not make it work using CellValueChanged and CellContentClick, even with async and await Task.Delay(...) as it did not fire correctly and triggered inter-thread exceptions in my computation afterwards.
It might just have been me though, but I wasn't very fond of using Threading in this context anyway.
I hadn't considered using CellValueChanged and noticed that it wouldn't trigger for a DataGridViewCheckBoxCell when clicked, so I ended up reading this thread and the solution is actually quite simple.
Grid.CurrentCellDirtyStateChanged += Grid_CurrentCellDirtyStateChanged;
Grid.CellValueChanged += Grid_CellValueChanged;
private void Grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (Grid.IsCurrentCellDirty)
{
Grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
private void Grid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
DataGridViewCheckBoxCell cell = (DataGridViewCheckBoxCell)Grid[e.ColumnIndex, e.RowIndex];
// Compute stuff
}
This code is executed each time a grid checkbox is clicked on, and has a far better logic since it relies on a direct value change.
However it means the computation takes place each time the value is changed.
I believe one could debounce the computation in order to improve this solution, fortunately mine isn't too resource expensive so it runs smoothly and I don't need to take it that far.

Why my textbox TextChanged event gets fired after I enter "only" one character in my text box?

private void NameVal_TextChanged(object sender, EventArgs e)
{
String text = NameVal.Text;
}
As soon as I enter the first letter of my Name this program gets executed . How do I make the program wait until I finish entering the whole string for the field (such as Name ex: James) is entered.
If you want to determine when the user has finished typing, you can catch the leave event instead - this is fired when the focus is lost on that text box - ie the user clicks outside of the textbox:
private void NameVal_Leave(object sender, EventArgs e)
{
//Do your stuff
String text = NameVal.Text;
}
If you are working with VS2019 there is a correlation between the TextChanged event and the Focus Leave event. You must have a TextChanged Event then when you search the Events and find Focus select Leave then there will be a drop down box with the TextChanged event for the same object as the Focus Event, which you will select. That will add the Leave Event to the Form1 definition area but it will not generate the code in the code area of Form1 like when you normally double click the TextBox. That you must create yourself. This article helped me do that part.
Later that day.
I was mistaken. You don't have to pick the TextChanged event. It was the only one available in the drop down list at the time. I had to add both events again in the form1 definition area since I had deleted the TextChanged event and manuallu added the Focus_Leave event, then went back in to add the TextChanged Event. I'm experimenting here. But when I deleted them both and re-entered the events again in the form1.design file there was a possibility to pick the correct one. I had another bug, but now they are in sync again. It's all the code that is generated behind the scene with MS VS that makes it difficult to change this area. And of course they do tell you not to change it, but what do you do if you make a mistake like this, you don't start over, you dive right in and keep going and learn how they are doing what they do.

Capturing line feed characters in a textbox OnKeyUp event in winforms

I have a Windows Forms application containing a textbox used to provide input to the application from a handheld barcode scanner. The barcodes we are using may contain special control characters like ESC whose default behavior is to clear out the input line. In order to be able to read such barcode string into the application I use the following method which is hooked into the textbox on key up event:
private void OnKeyUp(object sender, KeyEventArgs e){barcodestr += (char)e.KeyValue;}
The problem is that the line feed characters are being ignored by OnKeyUp method and I am not sure how I could capture those.
Please note that setting the Multiline/AcceptsReturn textbox attributes in any combination of true and false does not seem to make any difference.
In the end it worked after switching to using the KeyPress event instead of the KeyUp.

DataGridViewCheckboxColumn not setting underlying data

I have a DGV bound to an IEnumerable. T has a boolean property which can be get/set. When loading the table, the get property is accessed to populate the DataGridViewCheckboxColumn. I can see it being hit in the debugger. When I click a cell in the checkbox column, the checkbox is checked as you'd expect, but the underlying data source isnt' updated, and the property setter isn't called. The checkbox column has the ReadOnly property set to false.
How can I get this to update the underlying bound data?
polygonListBindingSource.DataSource = m_displayPolygons.OrderBy(p => p.Name);
I've seen related questions, but they're not consistant in their answers. Some suggest calling EndEdit on the DGV, other suggest calling it on the binding source. Do I really have to subscribe to an event for when the cell value is changed to actually commit the change to the underlying data type? This seems unnatural.
This is down to the fact that the DataGridView only commits its edits when the current cell loses focus. Clicking on the checkbox isn't enough to commit the edit.
The standard was to do this is to use events, usually the CurrentCellDirtyStateChanged event:
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
It is a bit unnatural but is by design - this way your data source doesn't get flooded by edits that may not be final. Not necessarily such a big deal for a checkbox but a worthwhile design decision for the text box cell.

MVVM WPF datagrid data entry problem

I have a datagrid in my MVVM application which, because of the way the client wants the data displayed, needs use template columns. They want some typical data-entry functionality though (pressing enter performs data checking, commits the row if valid, focuses on the first textbox of the next row; pressing tab focuses the next textbox...). Also, data is often imported from an external source into the grid, usually thousands of records at a time.
Right now, I have a Loaded event hooked up to each textbox which I am using to set focus after new rows are added. My problem is that the grid goes haywire when I import a lot of rows. As the user scrolls, the Loaded events are fired, and the grid becomes basically unusable. I disabled virtualization to prevent this, and find my grid taking up a gig of RAM in certain configurations, which is unacceptable. I can't figure out a way to get this grid to work the way they require without using a huge amount of memory. It seems as if I just need to be able to focus a textbox within a newly added row, but since the data validation is performed in the viewmodel, I don't have access to the new row in codebehind, so I can't just call "newtextbox.focus()" or whatever. I'm getting pretty desperate here, any suggestions would be massively appreciated.
Put an event listener in the code behind that can call your newtextbox.focus() (and whatever else you want to do). In the validation in the view model, fire the event with args that indicate what you want your grid to do.
Edit: OK, new approach. Try trapping the keystrokes, and on enter or tab do the things you want it to do.
This would be in your xaml
<Grid KeyUp="myDataGrid_KeyUp" >
This would go in your code-behind
private void myDataGrid_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
// do your enter stuff here, manipulate the view model for validation, etc.
}
else if (e.Key == Key.Tab)
{
// do your tab stuff here (get selected row, determine cell focus, focus on next cell)
}
}

Resources