WPF editable ComboBox SelectAll when clicked - c#

I have got how to SelectAll text when clicked on a TextBox; I want to do the same for an editable combobox - din find anything. My code for TextBox is
private void OnPreviewMouseDown(Object sender, MouseButtonEventArgs e)
{
txtBox.SelectAll();
txtBox.Focus();
e.Handled = true;
}
How can the same can be done for the Editable Combobox ?
Update
Code for Combox that gives me the output that I want:
private void cboMouseDown(object sender, MouseButtonEventArgs e)
{
var textBox = (cbo.Template.FindName("PART_EditableTextBox", cbo) as TextBox);
if (textBox != null)
{
textBox.SelectAll();
cbo.Focus();
e.Handled = true;
}
}
But now the dropdown of the combobox doesn't work, any suggestion ?
Update-2: Instead of PreviewMouseDown - I have tried PreviewMouseUp and now the dropdown does appear; but when once clicked on the box and then tried to open the dropdown - the window becomes frozen.
However, I have made a work around that I have put in my answer bellow. I would really appreciate your comments though if it is a right and safe solution I can go with.

Use GotFocus event and select text like this
var comboTextBoxChild = comboBox.FindChild(typeof(TextBox), "PART_EditableTextBox") as TextBox;
comboTextBoxChild .SelectAll();
Here combobox is your Editable Combobox name

A possible solution I have got and its working for me - need some suggestion though if it is ok or not; I am using PreviewMouseUp event of the ComboBox:
private void cboMouseUp(object sender, MouseButtonEventArgs e)
{
var textBox = (cbo.Template.FindName("PART_EditableTextBox", cbo) as TextBox);
if (textBox != null && !cbo.IsDropDownOpen)
{
Application.Current.Dispatcher.BeginInvoke(new Action(()=>{
textBox.SelectAll();
textBox.Focus();
//e.Handled = true;
}));
}

I am a little late to party, but I had same problem recently and after testing several solutions I came up with my own (I created custom control for this purpose):
public class ComboBoxAutoSelect : ComboBox
{
private TextBoxBase textBox;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
textBox = GetTemplateChild("PART_EditableTextBox") as TextBoxBase;
}
protected override void OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
// if event is called from ComboBox itself and not from any of underlying controls
// and if textBox is defined in control template
if (e.OriginalSource == e.Source && textBox != null)
{
textBox.Focus();
textBox.SelectAll();
e.Handled = true;
}
else
{
base.OnPreviewGotKeyboardFocus(e);
}
}
}
you can do the same with events but you will need to search for "PART_EditableTextBox" every time and here we do it only once per template change

Related

Generic MouseButtonEventHandler for TextBox and Label

Learning WPF with MacDonald's "Pro WPF 4.5 in C#," focusing on Ch5, Events.
How would I write a generic event handler that works with both Labels and TextBoxes to process the MouseDown event initializing a drag & drop procedure?
Here is my TextBox handler:
private void tBSource_MouseDown(object sender, EventArgs e) {
TextBox tBox = (TextBox)sender;
DragDrop.DoDragDrop(tBox, tBox.Text, DragDropEffects.Copy);
}
And my Label handler:
private void lblSource_MouseDown(object sender, EventArgs e) {
Label lbl = (Label)sender;
DragDrop.DoDragDrop(lbl, lbl.Content, DragDropEffects.Copy);
}
As you can see, I'm using the Content property and the Text property, depending on which object starts the event. If I try to use the same property for both senders, I get build errors (regardless of which I use). If I can avoid duplication, I would be very happy. Should I chunk a conditional out into another function and call that in the handler to determine what property should be used?
you could do something like this:
private void Generic_MouseDown(object sender, EventArgs e)
{
object contentDrop = string.Empty;
//Label inherits from ContentControl so it doesn't require more work to make work for all controls inheriting from ContentControl
if (sender is ContentControl contentControl)
{
//If you don't want to filter other content than string, you can remove this check you make contentDrop an object
if (contentControl.Content is string)
{
contentDrop = contentControl.Content.ToString();
}
else
{
//Content is not a string (there is probably another control inside)
}
}
else if (sender is TextBox textBox)
{
contentDrop = textBox.Text;
}
else
{
throw new NotImplementedException("The only supported controls for this event are ContentControl or TextBox");
}
DragDrop.DoDragDrop((DependencyObject)sender, contentDrop, DragDropEffects.Copy);
}
Let me know if you have any question

TextBox always focused

I have a window with a TextBox and a Button. I want to always focus my TextBox, but allow the user to click the button. How can I do it?
I tried it by using a LostFocusEvent, that whould check who has the focus, and if it wasn't the Button it would focus the TextBox back, but I always get a System.StackOverflowException...
This what I was using:
private void TextLostFocus(object sender, RoutedEventArgs e)
{
IInputElement focusedControl = FocusManager.GetFocusedElement(this);
if (focusedControl != btn && focusedControl != txt)
{
txt.Focus();
}
}
Is there a way to do this?
in the button click event you can give focus back to your text box like this.
textbox.focus();
Textbox.Select();
Focus is a lower level method used for custom controls. I would stick to select() or activate()
private void TextLostFocus(object sender, RoutedEventArgs e)
{
((TextBox) sender).Focus();
}
you could use ActiveControl Property to set focus to your text box.
this.ActiveControl = yourTextboxName;

WinForms DatagridViewComboboxColumn "enter key"

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.

Determine source of event

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.

TextBox Example Into Datagridview

I have simple textbox example as below:
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = "Apple";
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text.Length == 1)
{
if (textBox1.Text == "B" || textBox1.Text == "b")
{
textBox1.Text = "Ball";
}
}
}
By default textbox1 should return "Apple" on Form load but when I press "b" or "B" then it should return "Ball" on textbox1. I have a confusion on utilize it into datagridview. how can i do it in datagridview?.
Suppose I have One column on datagridview like below:
private void Form1_Load(object sender, EventArgs e)
{
DataGridViewColumn Particulars = new DataGridViewTextBoxColumn();
dataGridView1.Columns.Insert(0, Particulars );
}
If I have above column In datagridview1 than How to do I with datagridview1 which I have did with textbox?.
You might find it more straightforward to use the auto-complete functionality built-in to the textbox control, rather than trying to code for all possible scenarios yourself.
There are two important properties of the TextBox control that you must configure to enable its auto-completion functionality: AutoCompleteMode and AutoCompleteSource.
The AutoCompleteMode property allows you to choose how the textbox autocomplete function will look in action. You can choose between any of the AutoCompleteMode values
None Disables the automatic completion feature for the ComboBox and TextBox controls.
Suggest Displays the auxiliary drop-down list associated with the edit control. This drop-down is populated with one or more suggested completion strings.
Append Appends the remainder of the most likely candidate string to the existing characters, highlighting the appended characters.
SuggestAppend Applies both Suggest and Append options.
The AutoCompleteSource property allows you to specify the strings that you want the textbox to propose auto-completion with. In your case, you will probably want to specify a CustomSource, which requires you to set the AutoCompleteCustomSource property to a user-defined collection of strings—something like "Apple, Ball, ..." etc.
The DataGridViewTextBoxColumn simply hosts a standard TextBox control, so all of the auto-complete functionality it provides is already available to you for free. You can set the appropriate properties of this textbox by handling the EditingControlShowing event of your DataGridView, like so:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
//Create and fill a list to use as the custom data source
var source = new AutoCompleteStringCollection();
source.AddRange(new string[] {"Apple", "Ball"});
//Set the appropriate properties on the textbox control
TextBox dgvEditBox = e.Control as TextBox;
if (dgvEditBox != null)
{
dgvEditBox.AutoCompleteMode = AutoCompleteMode.Suggest;
dgvEditBox.AutoCompleteCustomSource = source;
dgvEditBox.AutoCompleteSource = AutoCompleteSource.CustomSource;
}
}
EDIT: If you'd prefer to keep the same behavior as you have in the original textbox example, you can just handle the TextChanged event for the DataGridViewTextBoxColumn. As I already explained above, the DataGridViewTextBoxColumn simply hosts a standard TextBox control, so it's fairly straightforward to add a handler for its TextChanged event and use the same code you had before:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
TextBox dgvEditBox = e.Control as TextBox;
if (dgvEditBox != null)
{
//Add a handler for the TextChanged event of the underlying TextBox control
dgvEditBox.TextChanged += new EventHandler(dgvEditBox_TextChanged);
}
}
private void dgvEditBox_TextChanged(object sender, EventArgs e)
{
//Extract the textbox control
TextBox dgvEditBox = (TextBox)sender;
//Insert the appropriate string
if (dgvEditBox.Text.Length == 1)
{
if (dgvEditBox.Text == "B" || dgvEditBox.Text == "b")
{
dgvEditBox.Text = "Ball";
}
}
}

Categories