Is there a way I enable users to switch tabs in a tab control using control-pageup/pagedown (as in Chrome), so I can free up control-tab for use in the body of the tab? Do I have to write a previewKeyDown or something, switch tabs programmatically and set event.Handled = true? In that case, how do I stop xamTabControl from interfering with the ctrl-tab keypress?
Thanks.
John.
Hello John,
Thank you for your post.
I have been looking into your requirements. What I can suggest is to handle the PreviewKeyDown event of XamTabControl and set the IsTabStop wpf property. To stop the Ctrl + Tab combination you can use Keyboard.Modifiers method in 'if' statement in the event handler and set e.handled to true. Also you can move the tabs with PageUp and PageDown buttons by checking in the event handler for it and change the selected item by changing the selected index. You can change it by using SelectedIndex property of XamTabControl. I created a short sample application to show you how you can achieve the functionality that you want. Please let me know if I missing something.
Please let me know if you need from any further assistance on this matter.
Thanks, Zhivko, but it doesn't help. As I said in my original post, I need to be able to use ctrl-TAB in my own program.
I'm attaching a modified version of what you sent me. As you can see, the TextBox inside the tab has AcceptsTab="True". Once I fall into that TextBox, I want to be able to use ctrl-Tab to get out of it. Setting e.Handled=True in the preview key handler prevents ctrl-tab from being seen by the TextBox.
Thank you for your reply.
I have been investigating your requirement. What I can suggest is to use the if statement, where checks for ctrl+Tab combination in the hadler of PreviewKeyDown event. In it you can use FocusNavigationDirection class and create object to perform the tab operation ( as Next, Previous, First, Last etc...). You can create a TraversalRequest with your FocusNavigationDirection choice. You can get the element with keyboard focus and change it by using MoveFocus(TraversalRequest) method of UIElement class.
Also after change the focus you should set the SelectedIndex property of XamTabControl to the current index, in order to be able to prevent the changing to the next tab item and set the handled property of PreviewKeyDown to True . I modified your sample application to show how you can impelemnt the functionality that you want.
Please let me know if you need any further assistance on the matter.
If the controls contained in the tab have KeyboardNavigation.ControlTabNavigation="Once", then I have to re-implement what WPF has already implemented, right? I have to determine object tree structure and find the next peer control to the control currently containing focus, and set focus to some control inside that control, right?
<igWPF:XamTabControl> <igWPF:TabItemEx> <StackPanel KeyboardNavigation.ControlTabNavigation="Once"> <TextBox TabIndex="1000" AcceptsTab="True"/> <CheckBox TabIndex="2000"/> </StackPanel> <StackPanel KeyboardNavigation.ControlTabNavigation="Once"> <TextBox TabIndex="3000" AcceptsTab="True"/> <CheckBox TabIndex="4000"/> </StackPanel> <StackPanel KeyboardNavigation.ControlTabNavigation="Once"> <TextBox TabIndex="5000" AcceptsTab="True"/> <CheckBox TabIndex="6000"/> </StackPanel> </igWPF:TabItemEx> </igWPF:XamTabControl>
I'm not making this up to be difficult. I have a requirement to include complex user controls (view model + data template) another team has written, those controls have text fields that accept tabs and I'd like control-tab to move from control to control, but not to controls within each user control. Setting ControlTabNavigation="Once" is perfect for this, but only if I get the Infragistics TabControl to let go of the control-tab key. Setting e.Handled to True in a preview key down handler will just suppress all following processing, right?
In the above example, if focus is on one of the text boxes and I call MoveFocus(Next), I'm going to wind up on a checkbox, right? I don't want that. I want to go to the first control in the next StackPanel, whatever that is.
The xamTabControl derives from TabControl and adds some additional functionality (e.g. close buttons, layout options, minimize, theming, etc). The MS TabControl processes the Ctrl+Tab specifically - via its OnKeyDown implementation - so this isn't anything the xamTabControl is doing. If you want to prevent the TabControl from processing those keys but still let the default WPF processing then you would probably need to derive from XamTabControl, override the OnKeyDown and not call the base when the e.Key is Keys.Tab and the ModifierKeys contain the Control bit. I've attached an example of that.
Andrew, thanks, that helped. However, now it looks like TabItemEx (or TabItem) is snagging ctrl-tab. If you run that app you posted most recently and hit ctrl-tab a few times, you'll see it switch to tab 2 and then back to tab 1 (but never tab 3).
More tomorrow, probably. :)
I don't think you'll be able to get this to work using just the wpf framework implementation if you expect it to cycle into the controls of each tab between going to each tab. I think the reason why it never gets to the 3rd tab is because of how they have it implemented. Basically they start with the focused element and then traverse the tree based on its tab index. The tabs all have the same tabindex so its more of a resolved tab index based on their zindex. Since the selected tab is the highest zindex it ends up going back to the 1st tab when the 2nd tab is selected and you press ctrl-tab. You can address that by setting the TabIndex of the TabItems. That being said they're traversing the sibling elements within the tab item pane before considering elements outside that tree so once you set the tabindex you'll find that it goes from tab 1 to tab 2 (which selects it and changes the tab content) to tab 3 which selects it and then since that tab has no children it navigates out to the button.
Maybe I looked at the wrong project but I thought the one you posted last was hooking the PreviewKeyDown to the XamTabControl_PreviewKeyDown method in the MainWindow.xaml. In any case when I blocked that I saw the behavior you described. I'm sorry I couldn't be of more help in terms of getting this to work without the Preview event but unfortunately the intrinsic controls seem to be making some assumptions here. The only other thing I could see doing is try to mark the event handled before the scrollviewer gets it and then marking it unhandled after it but that assumes that the ordering of the static events is consistent. I attached a modified version of the sample that does that.
Hi, Andrew,
There is a HandlePreviewKeyDown() in the code-behind, but it's not actually hooked up to anything, so commenting it out would do nothing (since it's already effectively commented out). Is that what you're referring to? (Sorry, the code's kind of grown as I played around with it, and there's some dead stuff in there.)
Sorry I blamed Infragistics for behavior it inherited from WPF. Bad reflex. :)
Using PreviewKeyDown works but makes me sad (means contained controls don't get a crack at it, which I know is the point, but, still...) but re-templating stuff just to switch some keys around is also sad. Tradeoffs.
Many thanks for your help. Hopefully I won't be back. :)
Just to be clear, you mean if I comment out your handling the PreviewKeyDown (which is reacting to the PageUp/Down)? I don't mean to redirect but xamPager is just a derived ScrollViewer that adds some logic to help it act as a "pager" type control. From looking at their code in ILSpy the ScrollViewer is processing the Next/PageDown and Prior/PageUp keys as long as the Alt key is not pressed. In theory you would think they would only do that if the control key is not pressed but they don't seem to use that info when processing those keys. This is the same reason why you're seeing it not work when the TextBox has focus - because it has a ScrollViewer within it that is processing those keys. While you might be able to do something similar by deriving from ScrollViewer (and retemplating the TextBox to use your derived control) and deriving from XamPager (and retemplating the xamTabControl to use that) it seems like you're probably better off handling the Control+PageDown|Up in a Preview event as you are in the sample you attached (except checking the modifier keys to ensure that Control is down and marking the event as handled so the focused control won't also process it).
Ok, using a subclass of XamTabControl as you suggested works. If I set KeyboardNavigation.ControlTabNavigation = "Contained" on the grid inside the TabItemEx, then ctrl-tab cycles through the controls contained in the tab, which is what I want.
Next problem, from the original post: making ctrl-PageUp/Down cycle through tabs. In the OnKeyDown() for XamTabControlEx (the custom subclass), I can select the next tab (when focus is on a control inside the tab, such as one of the checkboxes*), but after that one success, the next ctrl-PageDown event is consumed by XamPager (PART_TabItemScrollViewer), according to Snoop.
(*Ignoring for the time being that the text boxes also eat the ctrl-PageDown)
Am I just asking Infragistics/WPF to bend in a direction it wasn't designed to bend in? I'm on the verge of telling the user "sorry, you're stuck with control tab moving from tab to tab, but we can use it (once) to escape from a text field instead of switching tabs".
(Attaching latest "play" code.)