XAML/WPF: Tabbing to textboxes that are inside a tab - wpf

I have a WPF/XAML form that has controls on the page and also controls inside a tab control.
I was hoping that by setting the tabindex values appropriately, the user could just tab from the controls outside of the tab control to the controls inside the first tab item, but it seems that the items inside tab control are skipped when tabbing around the form.
Is there a way to have the tabbing go into the tabitem/tab control?

WPF provides a number of ways to affect the tab order in an application. Probably the most important is also strangely the least known. I'm talking about the KeyboardNavigation class and in particular, the KeyboardNavigation.TabNavigation Attached Property. From the linked page on MSDN, this property Gets or sets the logical tab navigation behavior for the children of the element that this property is set on.
There are several possible values in the KeyboardNavigationMode Enumeration used that affect the tabbing order in different ways. Take a look at the last linked page to see which one suits your situation best, but as an example, the Local value has the effect that Tab Indexes are considered on local subtree only inside this container and ... [Navigation leaves the containing element when an edge is reached].
<Grid KeyboardNavigation.TabNavigation="Local">
...
</Grid>

This is a problem I've often faced and it's a tricky one. From my understanding, the reason that it doesn't work as you'd expect is because tab order (even specified via TabIndex) is contextual. TabIndex of higher level items will be prioritized over inner elements. So if you have two TabItems inside of a TabControl, and each one has UIElements inside of them, even if the TabIndex is specified, tabbing will first traverse the TabItems before it moves down to the contents of those controls. I "think", IIRC" this has to do with how the page is composed, but don't quote me on that. MS has weird reasons for some of these subtle nuances.
Onto the solution. What I've done in the past (so long as you're NOT working on WinRT, which makes this problem even worse) you can use UIElement.Focus. I store a list of UIElements in the order I wish them to be when tabbed in the code. Then, by binding the KeyDown event to a common handler for all of these controls, I do something like this:
int currentIndex = TabbableControls.IndexOf(sender);
UIElement next = TabbableControls[(currentIndex + 1) % TabbableControls.Length];
next.Focus();
Hope this helps!

Related

How to refresh a WPF subtree without knowing what is in the subtree (Especially all bindings that only depend on converter rather than source value)?

Background:
I use converters to acquire values for most of my binding statement because the bindings are so complicated that even multi-binding cannot satisfy. I have to calculate the value in the converters and return the value. Also I use OneWay or OneTime binding just to show the correct value. When user changes a value, I use Handlers to set the value. The Handlers are also complex program which cannot be simply replaced by TwoWay or OneWayToSource binding. Actually in this case the DataContext does not have any meaning. I use converters. Another reason of using converters is that all Controls are loaded dynamically using many DataTemplates and it's hard to create dynamic DataContext for each Controls in each DataTemplate.
With above background, my application works fine. I'm looking for solutions for our new problem below.
I have many group of Buttons each represent a warehouse containing different type of items.
When double-click a Button, a detail window pops up and user can modify the items. Those items can be represented by CheckBox, Combobox, TextBlocks, TextBox, etc.
For user's convenience, I duplicated some of the frequently-modified Controls from the popup window onto the Button itself (WPF allows Button to contain sub-controls), so that user can directly modify the items without double-click and popup the detail window.
Each Button could contain unknown number of sub-controls such as CheckBox, Combobox, TextBlocks, etc. Here "unknown" means that in the future developer can duplicate any controls onto the Button if the Controls for those items are deemed frequently-modified.
Everything works fine so far.
When user modifies an item in the popup window and closes the window, I used to reload the DataTemplate for the whole window so that everything is refreshed and the controls duplicated onto the Button can synch up with the value modified from inside the popup window.
Everything still works fine so far.
The problem happens when the application runs on machine with slow hardware, where performance is an issue. On a much slower machine, reloading the whole DataTemplate for the whole application that contains many Buttons is quite slow.
So I'm looking for ways to just refresh the Button that is double-clicked, not all Buttons. However, I searched a couple of days and could not find ideal solution of refreshing a WPF sub-tree.
I tried to travel the sub-tree of the Button to assign null to the DataContext property and then assign back the old DataContext, but the binding seems not triggered and the converters were not called.
I saw someone suggested to use something like below:
((ComboBox)sender).GetBindingExpression(ComboBox.ItemsSourceProperty)
.UpdateTarget();
That demands that I know the Control and its property that has bindings. I think I can do the same for all possible Controls and properties but it does not seem a future-proof solution.
Anybody knows an effective way of refreshing a WPF sub-tree without knowing what is in the sub-tree?

slow page trasitions due to databinding

I am making a search app in wp7. Every record's data is bound to a user control. I have introduced an infinite loading instead giving page numbers. So when the number of instances of the UserControl is increased in the screen the transition from one page to another page (like the preview or settings pages) or coming back from that page to the current page is getting slower. I cannot change the design (infinite loading concept).
What are the ways to handle this scenario? How about changing the visibility of the controls? And reference or suggestion will be highly appreciated.
Note I tagged WPF and Silverlight because the binding happens the same way in them, expected those to have dealt with scenarios like these.
EDIT Check this question, which is asked by me. Because of having UserControl's in the listbox the vertical offset is not being maintained. So I had no option other than using ItemsControl with scrollViewer around it. ItemsControl contains a list of 5 - 6 usercontrols which intern have itemsControls inside them, I thought virtualization may not happen in such cases. Am I right?
In WPF, this is done by Virtualization
Using Virtualization, only one copy (or a few copies) of the UserControl actually gets created, and switching to another user control actually just swaps out the DataContext that the control is bound to. It doesn't actually create a new UserControl.
For example, if you have an VirtualizingStackPanel with 100,000 items, and only 10 are visible at a time, it will only render about 14 items (extra items for a scroll buffer). When you scroll, the DataContext behind those 14 controls gets changed, but the actual controls themselves will never get replaced. In contrast, a regular StackPanel would actually render 100,000 items when it gets loaded, which would dramatically decrease the performance of your application.
This question about Virtualizing an ItemsControl can probably get you going in the right direction.
Take a look at this post, I believe the solution provided by Rico is what you are looking for. :)

Control.DrawToBitmap not working on UserControl

I have several composite UserControls, consisting of mostly labels and TextBoxes, and use the Control.DrawToBitmap to print the current UI. This works fine except for one composite UserControl. Its bitmap only contains a couple of controls within the UserControl. The Visible property of all controls is set to True. The documentation for DrawToBitmap states, "Controls inside containers are rendered in reverse order." I'm not entirely sure what this means but some controls are within panels, so I'm thinking this might have something to do with it. In any case, I've tried different orderings for the panels and the control within the panels, but nothing seems to help. Any ideas?
Figured it out. If e.g. two panels overlap but are not nested, then the controls in the panel that's behind the other panel will not be copied onto the bitmap. Changing the order (by bring to front) doesn't seem to have any effect.

WPF ListBox does not realise that its items have changed size

I have a ListBox that contains a number of User items that are DataTemplated to appear as UserControls in the ListBox. Each UserControl can be expanded in size. To start with, the ListBox is big enough to display them all in their unexpanded state. The problem that I have is that when a number of these UserControls are expanded together, they extend out of the ListBox's visible area. The ListBox does not recognise this fact and no ScrollBars appear, even when they are set to Visible.
I am using DoubleAnimations to alter the UserControl heights when the user clicks on a button in each one. Is there something that I have to do, or some setting on the ListBox that must be set to get it to register the size changes of the UserControls that represent its items and display ScrollBars when needed?
Edit>>>
I have tracked down the problem to a custom WrapPanel that I am using in the ListBox.ItemsPanel. When I remove it, or replace it with a standard WrapPanel, ScrollBars appear when required. I got the code for the Panel from a good article about creating custom WPF panels. Can anyone see what's missing from the code given in the article and why it might stop the ScrollBars from displaying?
I wonder whether ListBoxes normally do what you are expecting? You might try calling InvalidateMeasure/Layout on the ListBox if you know when the item sizes change, just to see?
I decided to write the custom WrapPanel code again completely and this time it worked correctly! When comparing the new version with the previous version, I could see that a + was missing from a += in a measuring calculation and so the Panel thought that the items were much smaller than they really were... hence no ScrollBars.
So, if you have this problem, check your measuring code carefully.

How does WPF build up the list of controls that can be tab-navigated?

I am curious to know how WPF figures out where the focus should be set when the user hits the TAB key. Thinking aloud, I feel:
It may be doing relative search on the UI and find the nearest control based on (x,y) location.
It could manually walk the logical sub-tree to look for the nearest control
Does it do it each time the TAB key is pressed ?
From WPFWiki:
Tab Navigation moves the focus through
controls in a logical sequence.
The default logical sequence is that
controls will be focused starting from
the first focusable child of the root
control (window, page, etc.). From
that point, the TabNavigation property
is considered, and the next control in
sequence is either the first focusable
descendent of the currently focused
control or the next focusable sibling.
The TabNavigation property of the
newly focused control is then
evaluated, and so on.
For the most part, the tab order (using the rule described above) will generally be from the top of your XAML file to the bottom.
Of course, this can be modified by setting KeyboardNavigation attached properties, such as IsTabStop, TabNavigation, TabIndex, etc.
Perhaps not the most technical answer (I don't know the actual guts of it), but that's the general idea...

Resources