WPF check if UIElement takes text input - wpf

Is there a way to check if a given UIElement takes text input? I see there's a UIElement.TextInput event handler so I could add/remove handlers, but of course I can't check if it is null (if at least one handler has been added to it).
I'm guessing it's not possible but maybe there's a workaround I don't know about.

Related

DataGridView navigate cell on KeyUp with wrapped text

I would expect to navigate to the other cell only when reaching the very top.
What actually happens is that it navigates on hitting the 'up' key at the fourth line (which would the first line, if not for the text wrap).
Do you know if it is 'by design' or can be avoided?
Handling of the keyboard input is a responsability shared by the editing controls (classes implementing IDataGridViewEditingControl) inside the DataGridView and the DataGridView itself.
If you look at the source code inside DataGridView, you will see that the decision of where to handle a key press is demanded to the editing controls. Basically, the DataGridView asks to the IDataGridViewEditingControl (in your case, a DataGridViewTextBoxEditingControl) "Do you want to handle it?" by calling the
EditingControlWantsInputKey method.
This method contains a bug, or better an over-semplifications. The intent of the code seems to be "if I am already on the first line, a KeyUp means that the user wants to move to the cell above me". Unfortunately, "first line" is, in the code, anything before the first \r\n, disregarding word wrap. Which is what you are observing.
Fortunately EditingControlWantsInputKey is public virtual, so you can derive from DataGridViewTextBoxEditingControl and adjust the behaviour corresponding to your needs.
For example:
public class MyDataGridViewTextBoxEditingControl : DataGridViewTextBoxEditingControl {
public override bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) {
switch (keyData & Keys.KeyCode)
{
case Keys.Up:
return false; // never pass KeyUp to the DataGrid
...
// call base.EditingControlWantsInputKey when
// you want to retain the standard behaviour
This is oversimplified (it just disables the "move to the cell above" behaviour; you might want to act differently, maybe measuring the text lenght fitting in the "real" first line inside the cell by using Graphics.MeasureString. This is up to you and what you want to obtain.
Then, it is relatively easy to replace the standard controls for DataGridView cells with your own.

How to optimize TreeNode name change?

I have a TreeView which holds approximately 100,000 TreeNodes or even more, I have optimized everything related to loading or unloading them on deserialization process but now I'm stuck with an issue I can't overcome.
Its important to mention I decided not to use the LabelEdit default event given by the control since its pretty tricky to make it work as I wanted to, Its widely known that there are a lot of "problems" with this particular event which have pushed many devs to implement their own custom TreeViews.
In my case I am using a ContextMenu which has a Rename option, this brings a textbox right in front of the TreeNode and then I just simply change the TreeNode.Text property to whatever the user input was in the TextBox keydown event, once we trigger this event, the whole GUI freezes for a couple of seconds (4-5), I'm not doing any Depth search over the TreeNodeCollection or anything, I am directly accessing the TreeNode and modifying the property...
So, any thoughts on what could be wrong here? I already tried BeginUpdate / SuspendLayout / or even a custom solution found here How do I suspend painting for a control and its children? and nothing seems to help.
The first thing that comes to mind is that when the text is changed on the node, it must be redrawing the entire treeview.
In this situation, suspendlayout will not help, as the control isn't laying its contents.
I think beginupdate stops the drawing when nodes are being added to the list, but the text changed might bypass this.
Have you considered not using the keydown, and just updating the text once the user has dismissed the textbox? (i.e. done editing). Not ideal, but will limit the performance hit to once, instead of every key stroke?

How can I intercept the text to be inserted into a RichTextBox?

There is a TextChanged event for the RichTextBox, what I require is a TextChanging event so I have chance to perform an action before the text is changed. The KeyDown event is not enough as my application uses a speech recognition engine which means it is possible to enter text without using the keyboard.
I was hoping I could intercept something in the WndProc method but nothing stands out.
Any ideas or help would be much appreciated. Thanks.
Try using the TextChanged Event from the RichTextBox class. Based on the description from MSDN
This event is raised if the Text property is changed by either a programmatic modification or user interaction.
It should be able to handle what you are trying to do.
Edit: You could have some sort of intermediary storage of the text so that when the text changes it is stored somewhere else first and after the text changed event is done, you can put the text back into the RichTextBox. But without knowing specifically what you are trying to accomplish, this would be my recommendation.

Make WPF TextBox or other focusable controls transparent to certain key presses (i.e. pass-through, not swallow)

I have a ListBox with a custom data template which contains a CheckBox, a TextBlock and a TextBox. Normally when you select an item in a ListBox, the underlying ListBoxItem is actually what has the focus and as such, it responds to the up and down keys. Additionally, if the CheckBox has focus, since it doesn't do anything with the up and down keys itself, it just happily ignores them and they're handled by the underlying ListBoxItem as well. All's good so far.
However, a TextBox has its own processing rules for the up and down keys, namingly moving the caret up or down a line in text, which doesn't apply here because in this case it's a single line (it's a number actually.) As such, if the TextBox has focus, the up and down keys break the navigation of the ListBox's selection, nor do they really help with editing.
Now while I could handle the PreviewKeyDownEvent (which I do below, but for different reasons) and manually process the behaviors depending on the pressed keys, that's a very specific solution and requires the control to have knowledge of its container's behavior.
In a perfect world (and in pseudocode), I'd like to just say MyTextBox.KeysToIgnore(Up, Down) or something similar and have it do just that... ignore those keys as if it wasn't even there. (Again, not swallow, but ignore so they pass through.)
But until then, here's what I've come up with, which seems to work, but just looks so 'hacky' to me...
private void PreviewKeyDownHandler(object sender, KeyEventArgs e) {
switch (e.Key){
case Key.Up:
case Key.Down:
case Key.OtherKeyToIgnore
case Key.AndAnother
e.Handled = true;
FrameworkElement target = VisualTreeHelper.GetParent(
e.Source as DependencyObject) as FrameworkElement;
target.RaiseEvent(
new KeyEventArgs(
e.KeyboardDevice,
PresentationSource.FromVisual(target),
0,
e.Key
){
RoutedEvent=Keyboard.KeyDownEvent
}
);
break;
}
}
This also has the added negative of not sending the PreviewKeyDown event to the target. Now I could work around that and fake it by sending that event first, then looking at the e.Handled before sending the actual KeyDown message, which makes sense, but then I hit another wall with the PreviewKeyUp and KeyUp events since thanks to setting e.Handled above, I never get the real 'key up' events to know when to send the fake ones. Plus I'm pretty sure I'd also be breaking the direction of the PreviewKeyxxx messages since they bubble the opposite direction from the regular non non-preview versions. (Maybe that's handled internally but I don't think so.)
Like I said... hacky, hacky, hacky!
But it does work so there's that. And I can implement this via Attached Behaviors which is why I even went this route. (In the attached behaviors implementation, it's not a case statement but rather a check against a collection of keys that I specify in XAML.) I just don't like the idea of losing all the other behaviors that I want.
Again, I just want to say 'Hey TextBox... when you see the Up or Down keys being pressed, STFU ya b*stard!!' and otherwise make it key-transparent.
Thoughts anyone?
Man... not even one comment, let alone an answer in almost a month! Oh well... guess my 'hacky' solution above is the way to do this so I'm marking this as the answer.
Yeh, TextBox key event handling sure can give you a headache.
The trouble is that it is impossible to determine call order of callbacks, registered via EventManager.RegisterClassEventHandler. I.e. your callback gets called on unhandled event, then event is handled, and thats it...
I found a way to "unhandle" key events by subclassing TextBox and by calling "AddEventHandler(KeyDownEvent, callback, true)" in constructor. Then set e.Handled = false by circumstances. Seems like callback gets called after event is processed by TextBox.
It is very not nice to have instance of delegate per instance of TextBox, rather than to have one delegate instance per class, but i can't see any other way to workaround.

WPF - Why isn't Keyboard.Focus() working?

have a TextBox item (MyTextBox) on a TabItem control. I have code that looks as follows:
MyTextBox.Focus();
Keyboard.Focus(MyTextBox);
When I run this code through the debugger I see the following after the lines are executed:
MyTextBox.IsFocused = true
MyTextBox.IsKeyboardFocused = false
Can anyone tell me why the textbox isn't receiving keyboard focus? It's just a standard TextBox control that is enabled.
When you try to set Focus to an element besides the things enumerated above by our coleague, you must also know that WPF does not allow cross threaded operations.
In some cases this exception is not raised like in the Focus method call case. What I've done to fix this issue is to call all the code that involves Keyboards focus in an action.
This action is ran inside the control dispatcher to make sure that my code is not being executed from another thread than the UI thread (e.g. timer event or an event raised from another thread):
[UIElement].Dispatcher.BeginInvoke(
new Action(
delegate{
/// put your Focus code here
}
)
);
MyTextBox.IsKeyboardFocused is false because you are looking at it under debugger and the keyboard focus is probably in your Visual Studio... Try debugging focus without breakpoints (e.g. Debug.Write or trace brakepoints) to see actual values of MyTextBox.IsKeyboardFocused in runtime.
Also notice that Focus() method returns boolean value that indicates whether focus was successfully set. Does it return False in your case? If yes, I would suggest stepping into Focus() method in order to find out what is wrong.
3 important properties must be true: IsVisible="True", Focusable="True". IsEnabled="True".
To be focusable, Focusable and IsEnabled must both be true.
http://msdn.microsoft.com/en-us/library/system.windows.uielement.focus.aspx
The accepted answer here does not solve the problem of textboxes who dont gain focus, no matter what the debugger tells you. If you have and can write to your textbox, then you have it keyboard-focused.
I found this here solving the problem (and actually gaining focus, not just settings the values so it looks like focus in the debugger), it comes very close to Pavlov's answer but with the "Focus code" : Keyboard.Focus does not work on text box in WPF
This worked for me (had to do UpdateLayout, otherwise Focus() didn't work immediately after changing tab from script)
tabControl.SelectedIndex = 2;
this.UpdateLayout();
txtMyTextBox.Focus();
It's important where your first two lines of code are executed.
If they are in an event handler that relates to the user pressing a key, using the mouse, altering the visibility of a control, or otherwise taking an action that might have an impact on focus, I find manually calling Focus() often doesn't work.
My theory is that internally, WPF operates as follows:
User or code takes action which could have an impact on focus, e.g. a TextBox control becomes enabled inside a focus scope which previously had no focusable control.
WPF notifies various event handlers, including yours which calls Focus().
WPF updates focus based on the state changes in step 1. This overrides whatever you did in step 2.
That is why this answer suggests to call your Focus() in a queued callback which will be executed after step 3.
Side note: you don't need to call both UIElement.Focus and Keyboard.Focus since the first includes the second (at least if you trust the Microsoft docs).
In conclusion, replace your first two lines of code with this:
// using System.Windows.Threading;
Dispatcher.BeginInvoke(DispatcherPriority.Input, MyTextBox.Focus);

Resources