I'm using WPF
I want to auto-tab to the next texbox when 'MaxLength' is reached.
I found this code : XAML Trigger Auto-tab when MaxLength is Reached
And it's working. But the problem is, I can't delete text when the MaxLength is reached !
I can't change the actual text too.
Do you have an idea to allow me to modify, or delete text from a MaxLength reached textbox ?
My XAML :
<TextBox Grid.Column="0" Name="txtC1" Margin="5" MaxLength="7" PreviewKeyDown="txt1_PreviewKeyDown"></TextBox>
<TextBox Grid.Column="1" Name="txt2" Margin="5" MaxLength="12" PreviewKeyDown="txt2_PreviewKeyDown"></TextBox>
<TextBox Grid.Column="2" Name="txt3" Margin="5" MaxLength="12" PreviewKeyDown="txt3_PreviewKeyDown"></TextBox>
Code Behind
private void txt1_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
// Auto-tab when maxlength is reached
if (((TextBox)sender).MaxLength == ((TextBox)sender).Text.Length)
{
// move focus
var ue = e.OriginalSource as FrameworkElement;
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
The problem is that you are using the event on a keyDown and that means that when backspace or delete is pressed, the event is triggered but the text hasn't changed until the keyDown event is done, so the code will always validate with the same number of characters in the textBox and it will take one more character to type in the box to trigger the change of focus in your case.
You can do something like this instead
XAML
<TextBox Grid.Column="0" Name="txtC1" Margin="5" MaxLength="7" TextChanged="txt1_TextChanged"></TextBox>
<TextBox Grid.Column="1" Name="txt2" Margin="5" MaxLength="12" TextChanged="txt2_TextChanged"></TextBox>
<TextBox Grid.Column="2" Name="txt3" Margin="5" MaxLength="12" TextChanged="txt3_TextChanged"></TextBox>
Code
private void txt1_TextChanged(object sender, TextChangedEventArgs e)
{
if (((TextBox)sender).MaxLength == ((TextBox)sender).Text.Length)
{
// move focus
var ue = e.OriginalSource as FrameworkElement;
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
You can still do some keyDown event for something else e.g.: Allowing some key only like numbers or special numbers, but it is better to validate the text lenght with a textChanged event.
I resolved my own problem. Thanks to differents answers I got, I used them a little.
This is my new code behind :
private void txt1_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
// Auto-tab when maxlength is reached
if (((TextBox)sender).MaxLength == ((TextBox)sender).Text.Length)
{
if(e.Key != Key.Delete && e.Key != Key.Clear && e.Key != Key.Back && ((TextBox)sender).SelectionLength == 0)
{
// move focus
var ue = e.OriginalSource as FrameworkElement;
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
}
And it's working.
Related
I have a DataGrid with CheckBox-type column which should be editable with single click. This is easily achieved by using template column with CheckBox inside:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<CheckBox BackGround="Red" IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
the problem, however, is that single clicking will change the value without ever entering Edit mode. How can I ensure the edit mode is entered before changing the CheckBox value (all will single click)?
My best attempt on the problem was setting PreviewMouseLeftButtonDown on DataGridCell through style and forcing BeginEdit(). While this does begin edit, it is back to needing double click to interact.
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender is DataGridCell cell && !cell.IsEditing && e.OriginalSource is DependencyObject source)
{
var checkBoxParent = VisualExtensions.GetVisualParent<CheckBox>(source);
if (checkBoxParent != null) // ensure CheckBox was clicked
{
cell.Focus();
ItemListDG.BeginEdit();
}
}
}
I have also tried handling Selected or GotFocus without any luck (breaks other types of interaction), CheckBox.Checked events cannot be used neither because they trigger on re/load.
In case of Selected event, the problem is that it enables single click edit on all columns even though it is handled on just one column (again, set through style):
private void DataGridCell_Selected(object sender, RoutedEventArgs e)
{
// second part of condition is always true, no matter what cell is clicked
if (sender is DataGridCell cell && cell.Column == ItemListDG.Columns[0])
{
// try to detect if the CheckBox column was clicked, if not return
if (sender != e.OriginalSource) // always false
return;
ItemListDG.BeginEdit(e); // always executes no matter the source
}
}
The event which should be handled is PreviewMouseLeftButtonUp, same like the case with Down event, after BeginEdit() is called the original CheckBox does not exist anymore and cannot handle the un/checking. The solution to doubleclick problem is to find the new representation of the CheckBox and either re-raise the event threre or toggle it manually:
private void DataGridCell_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (sender is DataGridCell cell && !cell.IsEditing && e.OriginalSource is UIElement source)
{
var actualSource = source is CheckBox ?
(CheckBox)source : VisualExtensions.GetVisualParent<CheckBox>(source);
if (actualSource != null)
{
ItemListDG.BeginEdit();
var newSource = cell.GetVisualChild<CheckBox>();
if (newSource != null)
{
newSource.IsChecked = !newSource.IsChecked;
}
}
}
}
I need to edit some hierarchical structure and I use TreeView with TextBoxes
Short example
<TreeView>
<TreeView.Items>
<TreeViewItem Header="Level 0">
<!-- Level 1-->
<TextBox Margin="5"
BorderThickness="1" BorderBrush="Black" />
</TreeViewItem>
</TreeView.Items>
</TreeView>
When I type in TextBox, +, -, letters and digits work fine, arrows work but when I press -, Level 0 item collapses and when I type *, nothing happens
How should I handle - and * to see them in TextBox as expected?
Edit:
- works if typed as Key.OemMinus but not from numeric keyboard as Key.Subtract
* works if typed as Shift+Key.D8 but not from numeric keyboard as Key.Multiply
finally solved the problem with Key.Subtract
I added handler to PreviewKeyDown on TextBox
<TextBox Margin="5" BorderThickness="1" BorderBrush="Black"
PreviewKeyDown="TextBoxPreviewKeyDown"
/>
on receiving Key.Subtract, KeyDown is marked as handled and then i manually raise TextInput event as explained in this answer (How can I programmatically generate keypress events in C#? )
private void TextBoxPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Subtract)
{
e.Handled = true;
var text = "-";
var target = Keyboard.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;
target.RaiseEvent(
new TextCompositionEventArgs
(
InputManager.Current.PrimaryKeyboardDevice,
new TextComposition(InputManager.Current, target, text)
)
{
RoutedEvent = routedEvent
});
}
}
I can suggest a keydown event for the textboxes that you have.
<TextBox Margin="5" KeyDown="TextBox_KeyDown"
BorderThickness="1" BorderBrush="Black" />
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
TextBox txt = sender as TextBox;
if(e.Key == Key.Subtract)
{
txt.Text += "-";
txt.SelectionStart = txt.Text.Length;
txt.SelectionLength = 0;
e.Handled = true;
}
else if (e.Key == Key.Multiply)
{
txt.Text += "*";
txt.SelectionStart = txt.Text.Length;
txt.SelectionLength = 0;
e.Handled = true;
}
}
It's not a good solution but it works. If you have any other "problem" keys, you can add an if to the event.
SelectionStart and SelectionLength are for positioning cursor at the end of textbox. And e.Handled = true; does prevent the default behaviour.
Evening all, I've run into an issue with the SelectionChanged (TabControl) event being call before the LostFocus (TextBox) event.
This is a problem since the SelectionChanged is triggered during a tab change, that intern resets the ListView.SelectedIndex (TabControl>TabItem>ListView) to -1.
The textbox uses LostFocus to update/validate it's textbox.text which depend upon the SelectedIndex. The text in the textbox is stored/retrieved from a List<string> and because the index changed, the List happens to go out of bounds.
I've looked around, tired a few things also a "hack-y" approach which didn't really help.
<TabControl SelectionChanged="SelectionChanged_Tab"
<TabItem .../>
<TabItem .../>
</TabControl>
<Grid>
<Label .../>
<TextBox Name="Name" LostFocus="Lost_Focus" .../>
</Grid>
Code:
private void SelectionChanged_Tab(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
ListView1.SelectedIndex = -1;
ListView2.SelectedIndex = -1;
}
}
private void Lost_Focus(object sender, RoutedEventArgs e)
{
TextBox textbox = sender as TextBox;
int Index = ListView.SelectedIndex;
if (string.IsNullOrEmpty(textbox.Text) || textbox.Text == "0")
{
textbox.Text = "0";
}
switch (textbox.Name)
{
case "Name":
SomeList[Index].AProperty = textbox.Text;
break;
}
}
OK, so after think about the problem from a different perspective, I decided to simple make the TabControl, an Focus-able event and simple make it focus when selection changes:
<TabControl SelectionChanged="SelectionChanged_Tab" Focusable="True"
<TabItem .../>
<TabItem .../>
</TabControl>
Code:
private void SelectionChanged_Tab(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
ListView2.Focus();
ListView1.SelectedIndex = -1;
ListView2.SelectedIndex = -1;
}
if (ListView2.SelectedIndex == -1)
{
ListView1.Focus();
}
}
I know it's not the most elegant solution (In the process or re-factoring) but this seems to get the job done.
Okay. I am trying on and off mouse events on the click of the toggle button in wpf. so far this is what i have..
the xaml is as follows
<telerik:RadToggleButton Name="Percentage" Height="25" Width="25" Style="{StaticResource SelectionGridStyle}" Checked="Percentage_Click"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
<telerik:RadToggleButton.ToolTip>
<ToolTip Content="{localization:Translate Percentage}"></ToolTip>
</telerik:RadToggleButton.ToolTip>
</telerik:RadToggleButton>
the this is the code behind.
private void Percentage_Click(object sender, RoutedEventArgs e)
{
RadToggleButton btn = sender as RadToggleButton;
btn.IsChecked = true;
//if (e.Handled == true)
// e.Handled = false;
//else if(e.Handled == false)
// e.Handled = true;
}
i want to handle the drag of a mouse for selection purpose when on else off. is there i way to achieve this?? Thank you.
WPF- Selection Brush is not working, I am selecting 'H' in my case but it is not working.
Here is my code :
XAML :
<TextBox Text="Hello" Height="49" Name="textBox2" Width="547" />
C#
textBox2.SelectionStart = 0;
textBox2.SelectionLength = 1;
textBox2.SelectionBrush = Brushes.Red;
Try this
textBox2.Focus();
textBox2.SelectionStart = 0;
textBox2.SelectionLength = 1;
textBox2.SelectionBrush = Brushes.Red;
An alternative solution is to trick the TextBox into thinking it has not lost focus. This way, you're not actually moving focus back to the TextBox.
For this to work, you'd have to set focus on the TextBox at least once, like when the user enters the initial text, or by calling textBox2.Focus() from the constructor.
Markup:
<TextBox Height="49" x:Name="textBox2" LostFocus="TextBox2_OnLostFocus" />
Code-behind:
private void TextBox2_OnLostFocus(object sender, RoutedEventArgs e)
{
e.Handled = true;
}