WPF - Why is the last char not visible in keydown event method - wpf

I have a WPF app where I'm updating output on key press.
My code works fine. Only it feels a little bit behind as I'm using KeyUp event.
When I try to use KeyDown, it is always a character behind. I have already tried adding UpdateSourceTrigger as shown in the TextBox XAML below
<TextBox
Text="{Binding TheLine, UpdateSourceTrigger=PropertyChanged}"
Behaviors:WatermarkTextBoxBehavior.EnableWatermark="True"
Behaviors:WatermarkTextBoxBehavior.Label="Please enter a numeric value"
Behaviors:WatermarkTextBoxBehavior.LabelStyle="{StaticResource watermarkLabelStyle}"
Grid.Column="0" x:Name="txtLengthFrom" GotFocus="txtLengthFrom_GotFocus" FontSize="15" FontWeight="SemiBold"></TextBox>
All characters are available as expected in the KeyUp event. What can I do to make sure all characters are available in the KeyDown event?
The code behind looks like this
public MainWindow()
{
InitializeComponent();
this.KeyDown += new KeyEventHandler(MainWindow_KeyDown);
}
void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
UpdateOutput();
}

Based on #Jon's comment, I changed my code to use TextBox.TextChanged event and it works as I want. So now when I keep a key pressed, the output is changing as characters gets added to text box. The way I had it, it would not update the output while I had a key pressed. I just didn't like it so was trying to fix that.

KeyDown event happens before the key takes effect on your property. Not sure why you want to do this, but you'll need to check the KeyEventArgs for which key is being pressed if you HAVE to have them all in keydown. If you end up modifying your property based on what is in the KeyEventArgs, you'll need to set e.Handled = true to prevent it from happening twice (Since it will be handled later if you don't).

Related

WPF Default Button command not triggering binding in textbox

I have a search screen with some textboxes and a Search button as the default. If I type in a textbox and I CLICK the button, everything's great. But if I press enter within a text box, the button command fires but the binding on whatever text box I was in does NOT fire and so my criteria doesn't make it to the view model to get filtered on.
I know one fix is to set the bindings on the text boxes to PropertyChanged, but this seems like way overkill. I might have logic in the viewmodel doing stuff and I don't want that to trigger on every single keystroke.
What I really want is a way for the button itself to either trigger a focus change or somehow trigger binding. Or to have the textbox trigger binding if focus is lost OR I press enter OR a command is executed from anywhere
One way to do this is with a BindingGroup.
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.bindinggroup.aspx
If your TextBox(es) and Button are both contained within a Grid (for example), you would add a BindingGroup like this:
<Grid>
<Grid.BindingGroup>
<BindingGroup Name="bindingGroup1"/>
</Grid.BindingGroup>
Then you could add a Click event handler to your button and call CommitEdit() on the BindingGroup (which the Button and TextBox inherit from the Grid):
private void button1_Click(object sender, RoutedEventArgs e)
{
(sender as FrameworkElement).BindingGroup.CommitEdit();
}
The Button.Click event fires before the CommandBinding, so any databound TextBox or any other databound controls within that BindingGroup should be updated before your view model command gets executed.
I've had the exact scenario you just mentioned. The trick I use is an attached behavior that sits on a control and listens for the PreviewKeyDown event. It checks if enter is being pressed. If so it forces the control to lose focus, thus causing the binding to fire before the command executes.
A simpler approach (rather than using a binding group) is to use the default button's click event to set the focus to itself. As this happens before the command is executed it means the ViewModel is updated in time.
private void button1_Click(object sender, RoutedEventArgs e)
{
(sender as Button).Focus()
}
And if you really hate code behind, you could always write an attached property...

WPF TextBox lostfocus as attached property

I have a Grid with many TextBoxes and I want to call NotifyPropertyChanged() method to update some other controls everytime one of these TextBox-es changed the value = lost the focus (I don't want to use PropertyChanged as UpdateSourceTrigger)
This is what I can do:
<Grid TextBoxBase.TextChanged="My_TextChanged" >
...
</Grid>
I need something like:
TextBoxBase.OnLostFocus
Use the lost focus event
TextBox.LostFocus="OnTextBoxLostFocus"
Filter on textboxes ;)
private void OnTextBoxLostFocus(object sender, RoutedEventArgs e)
{
if(!(e.OriginalSource is TextBox))
return;
//Do stuff
}
If your properties are not changed, your Textboxes will not be updated however. You should consider mutating the data those other TextBoxes are bound to, instead of using LostFocus to update your model.
Good luck!
TextBoxBase.LostFocus is, I suspect, the event you're looking for.
It's listed here: http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.textboxbase_events.aspx - but it's defined on UIElement - so you possibly want to try UIElement.LostFocus if the above doesn't work in markup.

How to register to/listen to richtextbox command's?

I'm creating a simple editor within our application using the WPF RichTextBox. Above it I've added the reguslar buttons like Bold, Italic, etc. These buttons use the RichTextBox's commands to set these properties, but next to these buttons, the commands also get send with CTRL+B, CTRL+I, etc. I want these buttons to represent the current state of the RichTextBox at the cursor. I already found out how to get this state and it works when I update this state on the SelectionChanged event. This event ofcourse isn't fired when Bold is toggled so there is no direct feedback.
I would like to know if there is a way to listen to the commands being called, without affecting its original behaviour or some other ideas to solve my problems.
I tried listening to the command the following way:
CommandBinding boldBinding = new CommandBinding(EditingCommands.ToggleBold, CommandExecuted);
_richTextBox.CommandBindings.Add(boldBinding);
and
private void CommandExecuted(object sender, ExecutedRoutedEventArgs e) {
UpdateProperties();
e.Handled = false;
}
This did update the properties, but the RichTextBox didn't seem to receive the command anymore.
I also tried to make my own commands on the control containing the RichTextBox, but when CTRL+B is pressed when the RichTextBox has focus, the original RichTextBox commands are called instead of the new one.
Many thanks in advance!
Liewe
In order to listen to the commands being called, you can use the events raised by CommandManager: Executed or PreviewExecuted.
If you change your XAML to:
<RichTextBox x:Name="_richTextBox" ...
CommandManager:PreviewExecuted="OnRichTextBoxCommand" ... />
you get the OnRichTextBoxCommand method called right before the command is executed. Unfortunately, using the Executed attached event does not work.
This method is called for each event, so you have to filter them:
private void OnRichTextBoxCommand(object sender, ExecutedRoutedEventArgs e) {
if (e.Command == EditingCommands.ToggleBold) {
UpdateProperties();
}
}
It may be even a bit more complex, as the current selection may not have changed when this method is called, so you have to post yourself a message, e.g. like this:
Dispatcher.BeginInvoke(new Action(UpdateProperties));
(if you reference already System.Core, you have the Action type, otherwise define a delegate taking no parameter and returning void, and use in instead.)

Silverlight TextBox, moving caret position

I am trying to make a TextBox behavior for an on-screen keyboard, it can update the text in the textbox but I can't get it to focus the textbox and move the caret to the end of the text once it's done updating.
I have tried using TextBox.Focus() and TextBox.Select() in both orders with no luck.
Thanks for your time
Changing the focus from within an input event handler (i.e. mouse click on a virtual key) will fail, since the mouse-up event (or key-up) will return the focus to the original element. In order to make it work, you have to dispatch the focus command to a later time using the Dispatcher object.
Example:
Dispatcher.Invoke(new Action(() =>
{
textBox1.Focus();
textBox1.SelectionStart = textBox1.Text.Length;
// or textBox1.Select(textBox1.Text.Length,0);
}), System.Windows.Threading.DispatcherPriority.Background);
Here is a simple example of moving the cursor to the end of a TextBox once you have updated it.
TextBox.Focus();
TextBox.Text = "sometext ";
TextBox.SelectionStart = TextBox.Text.Length;
I had a similar situation and I attached a "TextChanged" Handler to my textbox as shown here.
<TextBox Name="tbTextEntry" Width="200" HorizontalAlignment="Center" Background="Plum" Text="{Binding Entered_text,Mode=TwoWay}" TextChanged="OnTextChanged_Handler"></TextBox>
And handled the event like this(thanks Jeff Beck from comment above):
protected void OnTextChanged_Handler(object sender, RoutedEventArgs e)
{
TextBox my_text_box = (TextBox)sender;
my_text_box.SelectionStart = my_text_box.Text.Length;
Debug.WriteLine("OnTextChanged_Handler called !");
return;
}
This is inefficient for the cases when a person leaves the onscreen keyboard and start
to use the real keyboard because each new character will then cause this handler to be
invoked needlessly as the cursor works just fine with real keyboard. Any more efficient solution welcome !
Hope that helps.
Thanks.

WPF: Textbox not firing onTextInput event

So basically, I have a bunch of TextBoxes that the user gets to fill out. I've got a button that I want to keep disabled until all the TextBoxes have had text entered in them. Here is a sample XAML TextBox that I'm using:
<TextBox Name="DelayedRecallScore" TextInput="CheckTextBoxFilled" Width="24" />
And here is the function that I'm trying to trigger:
//Disables the OK button until all score textboxes have content
private void CheckTextBoxFilled(object sender, RoutedEventArgs e)
{
/*
foreach (TextBox scorebox in TextBoxList)
{
if (string.IsNullOrEmpty(scorebox.Text))
{
Ok_Button.IsEnabled = false;
return;
}
}
Ok_Button.IsEnabled = true;
*/
MessageBox.Show("THIS MAKES NO SENSE");
}
The MessageBox is not showing up when TextInput should be getting triggered. As an experiment I tried triggering CheckTextBoxFilled() on PreviewTextInput, and it worked fine then, meaning that for whatever reason, the function just isn't getting called. I also have a validation function that is triggered by PreviewTextInput, which works as it should. At first I thought PreviewTextInput might somehow be interfering with TextInput, so I took PreviewTextInput off the TextBox, but that hasn't managed to fix anything. I'm completely befuddled by why this might happen, so any help would be appreciated.
Your handler for the TextInput event is not fired because the TextBox is handling the event. You could try using the TextChanged event instead, since really you just want to know when characters were added or removed from the TextBox.
InitializeComponent();
textbox.AddHandler(TextBox.TextInputEvent,
new TextCompositionEventHandler(TextBox_TextInput_1),
true);
Use "PreviewTextInput" instead, it will work.
Create a new class derived from TextBox. In the new class override the OnTextInput method. Your OnTextInput method will get called before the TextBox gets it.

Resources