I've got a WPF window where I have a column of buttons on the left side. On the right side I am show/hiding UserControls as the left hand buttons are clicked.
I have created the UserControls once and then just switch between them with the buttons. As I switch I would like to retain the keyboard focus where it was when that UserControl was last visible.
In other words, I click on button A and show UserControl A. If I move keyboard focus to a textbox in that UserControl then click button B, do some work, then click button A again I would like focus to be on the same textbox that I last used in UserControl A.
Any ideas on how I accomplish this?
Declare a dictionary with the key being one the left-side buttons and the value the currently focused control. When a button is clicked, get the currently focused element and set it in the dictionary (with the key being the previously clicked button). Change the displayed UserControl and read the dictionary with the key being the just-clicked button. If there is a control for this entry, set the focus to it.
Use FocusManager.FocusedElement to know which control has the focus (actually an IInputElement, which should be the type of the dictionary value) and FocusManager.SetFocusedElement to put the focus back (or call Focus() on the control).
Related
I have a pretty simple use case but I cannot make it work right. I've got a ListView whose item template is a Note custom UserControl:
Each Note has a few simple controls as shown.
I want this to work so that if a row is selected programmatically or by clicking somewhere in it, it sets focus to the first textbox in that row. But if you click on a control in the row, it activates that control (i.e. lets you edit the Exhibit contents or click the Delete button).
If I don't do anything to set focus, clicking on the row highlights the row but doesn't set focus to any child control.
Within the Note control I have tried this:
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
text.Focus();
}
text is the name of that first TextBox, and it does set focus, but it also does this if I click directly on the Exhibit textbox or Delete button, making them unusable.
So, how can I enable the focusing that I want when the container control gets focus, UNLESS it got that focus via a click on a specific child control (which should then keep the focus)?
After a bit more searching, I found the correct way to implement this: at the root of the container control (the Note UserControl in my case), you can specify the name of the control to be the default focus control:
FocusManager.FocusedElement="{Binding ElementName=text}
Not sure how I missed that one.
Weird WPF ComboBox behavior:
I just noticed that in a WPF ComboBox, when the Keyboard Focus is set via the tab key (tabbing focus from the previous control), and TextBox inside the ComboBox ("PART_EditableTextBox") is the source of the tunneling event OnPreviewGotKeyboardFocus.
But for some strange reason, if the focus is received by clicking the mouse inside the control, then OnPreviewGotKeyboardFocus gets called twice: first time, the Source is the ComboBox itself; and the second time, the Source is, again, PART_EditableTextBox.
I also noticed that when settings Focusable to False on the ComboBox, you can still focus to it using the Tab key, but not using the mouse.
Does anyone know why this strange behavior?
From Microsoft doc.
The KeyboardNavigation class is responsible for implementing default keyboard focus navigation when one of the navigation keys is pressed. The navigation keys are: TAB, SHIFT+TAB, CTRL+TAB, CTRL+SHIFT+TAB, UPARROW, DOWNARROW, LEFTARROW, and RIGHTARROW keys.
The navigation behavior of a navigation container can be changed by
setting the attached KeyboardNavigation properties TabNavigation,
ControlTabNavigation, and DirectionalNavigation. These properties are
of type KeyboardNavigationMode and the possible values are Continue,
Local, Contained, Cycle, Once, and None. The default value is
Continue, which means the element is not a navigation container.
The combobox itself is a navigation container. This means that when you press tab, the container for the PART_EditableTextBox has KeyBoardNavigationMode set to Continue by default (this means that the focus go directly to the first non container element). The click event instead work differenctly, since you are not pressing a keyboard key, this behaviour is overrided, and the event is launched in order by any element that WPF will find in the visual tree. This is done to ensure that you can handle this event to do operation on your control, before the focus reach the Textbox. Also, you have to consider that this is necessary, cause WPF can't know exactly what you are going to click. That's why he must raise the same event from each layer of the combobox in order (if you click on the expander the focus won't stop inside PART_EditableTextBox).
So in short, if you are going to press TAB, WPF by default know that the final element that will be focused is the Textbox inside the combobox, that's why it's not needed by the combobox itself to raise the event. On the other hand, if you click on the combobox, WPF need to check which element will be focused at last and if there are some operation that must be done before switching focus.
Regarding the Focusable property finally, this one for a control indicates whether the control can receive focus, which means that the control can receive keyboard input after the user clicks on the control. Focusable is normally set to true for controls that are designed to accept user input. The part that can receive the keyboard focus, is the Textbox. So if you set Focusable = false inside the combobox, the KeyboardNavigation class will place the focus on the Combobox, instead of Textbox, cause it can't apply it's default behaviour
I need to set focus to UserControl itself, not its child.
Otherwise I cannot implement insertion from the buffer. :(
Setting Focusable=True doesn't help.
Google and SO tells only how to set focus to UserControl child.
My control contains:
- Toolbar with several buttons bound to commands of the corresponding
VM
- TextBox which is the input for the filter
- DataGrid - list of items.
I need to bind Ctrl+V command to VM. But to handle this gesture UserControl must have focus within. When there are no items in the grid (VM's collection is empty) buttons are disabled and the only element which can get focus is TextBox. But it handles Ctrl+V in its own way and I don't want to change this behavior.
Thus, I need something to set focus to when I click the area of UserControl.
I believe UserControl is the best candidate for it.
But I don't know how to make it selectable.
The whole problem was in my misunderstanding of controls' behavior.
This SO question clearly shows it I believe.
Thus, setting UserControl.Focusable = true is not sufficient. To make it navigatable via keyboard IsTabStop must be true also. And to make UC selectable by mouse click we should call Focus() in mouse eventhandler. That's it.
I want to add the menubar to TextBox control in Silverlight 4. (I will create a new reusable control.) The menubar will consists of a few image buttons. The idea is that it will normally stay hidden and will show up only when the user puts his/her mouse cursor to the TextBox area. If used in a multiline textbox, whole menubar can fit inside it, this should be easy. (I hope. :-))
But how to solve situation when TextBox is in single line mode? I'd like to put the menubar above the TextBox. But I don't have a clue how to do it. Can somebody help? I need to let all other controls in a form to stay in their positions, and only add my menubar above my textbox. (So the menubar will NOT hide the textbox. Instead, it will hide other controls residing right above the textbox.) It should work in all arrangements of form, like Grid, StackPanel, Canvas etc. In the fact it would be similar to a classic right-click context menu, but not modal. (Right-click context menu is modal, i.e. while it is shown you cannot use other controls, and it automatically hides when you click anywhere else. I want my menubar to stay visible as long as user heeps mouse cursor over the textbox or the menubar.)
Example: Coordinates of textbox are top=100,left=20,bottom=115,right=120. So my menubar's coordinates should be bottom=100,left=20, right & top are based on size of menubar.
If many textboxes will be used on a single page, each single one should have its own menubar. (Of course.)
You can create your own control (custom control or UserControl, whichever you like should work) which has the TextBox, and the visual for the menu bar.
If the TextBox is single-line, you could display the menu bar in a Popup which you position just above the TextBox whenever the mouse is over it.
If the TextBox is multi-line, you'd simply use a StackPanel or Grid or whatever to do layout like normal, if I am understanding what you want.
No coding required if you use this menu:
http://sl4popupmenu.codeplex.com
To achieve this behavior you will need to set its IsPinned property to true.
I have a grid, and in the grid I am setting my first element to be focused:
<Grid FocusManager.FocusedElement="{Binding ElementName=companyNameField}">
When the window opens, the correct control is focused.
But if I tab through the whole form, when the above focused field, should have the focus, there is no cursor evident anywhere on the window.
If I hit tab once more, it selects the control after the control that should be selected.
If I completely remove the focumanager attributes from my grid, I am correctly tabbing trough all my controls in the correct order.
Even stranger, if i leave in the focusmanager attributes and first click on the first text box and then focus through the entire form, then it selects my text box like any other control.
If you have any Ideas, I would love some help.
Thanks
I have had this happen to me, when I had some focus code in the code-behind fighting with the FocusManager. Mine was hidden in the Load of a nested UserControl, so I didn't notice it.