Moving Keyboard Focus Away from ListBox - wpf

I'm developing a program in WPF (VB) that relies on keyboard navigation only.
In my program, I have a listbox that displays up to 20000 items.
What I want is that when the listbox has keyboard focus, and I move to the bottom item that is visible (using ArrowDown), I want the focus to move to the next item outside the listbox. I'm using PgUp and PgDown to scroll the listbox contents, and text search to jump to items.
Is there a way to detect if the focused/selected item is the last/first visible item in the listbox?
If so, I could just use:
ListBox1.MoveFocus(New TraversalRequest(FocusNavigationDirection.Down))

I'd suggest that you don't do this, the user interface should behave consitesntly with other user interfaces in the operating system.
Your users would be better off if you come up with an alternate user interface that's consistent with how user interfaces behave on your target operating system.

It is a little clear from your explanation but either your looking for:
navigation to move outside of the listbox when the last item is selected.
when navigation is attempted beyond the last item in the list that the navigation pops out of the listbox.
If (1) is your objective there is probably a reasonable solution using triggers and or some custom code handling for events based on the selected item and selected item changed. I would have to agree with Tom if this is the case though and suggest that you do not implement it this way since the last item will never be selectable without focus being programatically removed.
If your instead looking to do (2) then it is my experience that the natural behavior of a ListBox is to move to the next control when the Tab key is pressed and I've tested this for the down arrow key as well and it works the same. When I get to the last item in the list focus pops out of the listbox and to the next control according to it's parent.
UPDATE: I have to withdraw my original comments as the behavior I described above do not describe the default behavior in WPF for a ListBox however it is the behavior you will see the behavior I described above (which I believe is the behavior your looking for) when implementing an ItemsControl and specifying an ItemTemplate. Take a look at the following example.
<ItemsControl ItemsSource="{Binding ElementName=TheWindow, Path=ListOStrings}">
<ItemsControl.Template>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Border BorderBrush="Magenta"
BorderThickness="1">
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
By chance, this just happens to have the behavior you described since each item in the list behaves almost like a control placed directly as a peer to all the other controls.

I use an easy trick to move the focus outside Listbox:
I disable the listbox so the focus moves automatically to the next control, then i enable the listbox again :)
Lst.IsEnabled = False
Lst.MoveFocus(New TraversalRequest(FocusNavigationDirection.Next))
Lst.IsEnabled = True

Related

ListBox inside a ListBoxItem template

I have a ListBox with the following ItemTemplate:
<DataTemplate>
<StackPanel>
<TextBlock .... />
<ListBox .... />
</StackPanel>
</DataTemplate>
I would like to forbid the user to Select an item in a child ListBox, and that when user clicks on the child ListBox, a parent ListBox SelectedItem should be set respectively.
What I have tried is to set IsHitTestVisible of the child ListBox to false, and that prevents the user to select an item on it, but the problem is that if I click on the child ListBox, the mouse click is not passed to parent ListBoxItem, so it never gets selected.
So to summarize, I need:
prevent the user to select item on the child listbox.
item on the parent listbox should be selected when we click anywhere in the ItemTemplate area (even when clicked on Child listbox).
You could replace the inner ListBox with an ItemsControl. Based on your question, it sounds like you just need to display a collection, and prevent the user from interacting with it. A simple ItemsControl is well suited for that.
The ItemsControl does not support selection, so the click will get propagated up to your main ListBox.
EDIT
Based on your comment, I'd recommend trying one of two options. First, you could set IsHitTestVisible to false on the list box items, as in the following example
<!-- XAML for the inner list box -->
<ListBox>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsHitTestVisible" Value="False" />
</Style>
</ListBox.Resources>
</ListBox>
This will cause the click event to propagate up to your main list box, while still being able to use a list box.
Second, maybe it would be easier to just create two separate list boxes? Again, you haven't fully explained why this is required, but trying to load up one control with different modes of functionality sometimes overcomplicates things. Having two controls, and showing only one at a time based on some condition, can be an easy way to simplify the XAML.

Bind border style to current user control

I`m developing a wizard application which has a side menu with 5 borders and a content control that contain application screens (user controls).
The borders styles are suppose to give to user an indication where he is at the wizard steps.
I wrote 2 border styles - the first one is the defult style which applied on all borders by default.
The second one (isFoucusedStyle) need to be applied by the border that suitable to the current screen.
For example when the wizard is showing the first screen: first border need to use the isFoucusedStyle and the others need to use defult style. When the user continues to next screen, the first border need get back to default style and the second border now will apply isFoucusedStyle.
I create the pages instances via xaml at the mainWindow under resources at the next way:
xmlns:view="clr-namespace:App.View"
xmlns:ViewModel="clr-namespace:App.ViewModel"
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModel:OpeningViewModel}">
<view:OpeningView/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:PersonalDataViewModel}">
<view:PersonalDataView/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:BusinessDataViewModel}">
<view:BusinessDataView/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:BusinessDataViewModel}">
<view:BusinessDataView/>
</DataTemplate>
I also have a property - CurrentPage which binded to ContentControl - when the user clicks "next page button" CurrentPage updates and the ContentControl switch UserControl.
There is no any binding between the borders to User Controls, in my current state the borders are just visual graphics without any features.
How can i implement it?
Thanks
I took the "isFoucusedStyle" and config it to baseOn defultstyle.
I added triger to isFoucusedStyle which turns on when Border.Focusable is true.
I Created a converter which has access to current page number.
At every border I bounded focusable property to the converter and sent it "converter parameter" with the suitible page number (page number which represented by current border)
The converter is checking for equility between currentPageNumber to converterParameter and returns boolean result.
The result is turning on (or not) the trigger and set the needed border style.
Thanks anyway.
Firstly I would strongly suggest you base your wizard on the NavigationWindow (or containing a NavigationFrame), this will give you all your back and forwards navigation for free, and if you want you can always re-style your NavigationWindow to match a more wizard like interface (see WPF Wizards). NavigationWindow/Frame also supply you with Navigate() methods that handle the transition between pages.
In order to handle the navigation links (your five side menu items) I bind each link to a View level ICommand which tests to see if we need are already on the correct page in CanExecute. Setting ths borders is then just a case of {Binding CanExecute, Converter={BoolToColorConverter}}.
In your case, you can simply do the same thing. Setup your command to check if we have the right CurrentPage, and Bind as above using a Converter.

What standard WPF control should I use?

I am trying the master-detail presentation in my app: when an item in a listbox is selected, its details are displayed in an adjacent control.
This control will have a list of measurements such as height, width, weight, etc. It will also have some small graphics such as a green or red dot or a medium sized image. It will also have some rich text.
Which STANDARD WPF control should I use to contain all these elements. I am thinking of using a listbox but wonder if there are better controls to use.
My main consideration is ease of coding, then possibly efficiency of the code.
Thanks.
A listbox indicates a list of items that can be tailored using a DataTemplate for appearence. In this case you are showing the details of a selected item. I would actually use a container such as a Grid nested in your current UI and have a set of stackpanel including the details of the selected item.
<Grid>
<StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>Detail1</TextBlock>
<TextBox></TextBox>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>Detail2</TextBlock>
<TextBox></TextBox>
</StackPanel>
</StackPanel>
</Grid>
This is only one suggestion but the point is to use a container and use a set of controls in the containers - textblock,textbox,checkboxes(boolean details), etc... this will allow you to use any control type necessary to represent the specific data field of the selected item.
You don't want to use a listbox unless you have a collection of similar items, and you want one or more items to be 'selected' at some point. It sounds like that is not what you want for the details part.
You do have a collection, which is shown in your master list. You should bind the SelectedItem in your master list to a property in your viewmodel. Then you can bind that same property to the details section of your UI. When the selection in the master list changes, your details UI will automatically update to reflect the changes.
<ListBox x:Name="masterList" ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem, Mode=TwoWay}"></ListBox>
<UserControl x:Name="detailsControl" DataContext="{Binding MySelectedItem}"> </UserControl >

Silverlight ListBox: How to find out if user is currently dragging the scrollbar slider?

Scenario: I have a ListBox, containing a WrapPanel from the Silverlight Toolkit as ItemsPanel:
<ListBox x:Name="listBoxFaelle">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Template>
<ControlTemplate>
<Grid>
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</Grid>
</ControlTemplate>
</ListBox.Template>
</ListBox>
This ListBox gets populated automatically with the results of a RIA service call every 60 seconds. While the application is waiting for the LoadOperation to complete, it displays the standard BusyIndicator that is part of the Silverlight Business Application template.
This works fine as long as the user is not dragging the scrollbar slider of the ListBox when the Timer Event fires.
Problem: If the user is dragging the scrollbar slider when the BusyIndicator is being displayed, the scrollbar doesn’t work anymore, afterwards. It looks like the mouse pointer remains captured to the slider even if the left mouse button is released. I assume this happens because the BusyIndicator temporarily takes away the focus from the slider while it is being dragged.
Question: Is there a way to find out if the scrollbar slider of the ListBox is currently being pushed?
As far as I know there is no status/property to find out if the slider is being pushed.
That said you could try to keep track of it yourself by handling MouseLeftButtonDown and Up events but you might have to consider other events as well depending on your scenario (mouse wheel?)
MouseLeftButtonUp Occurs when the left mouse button is released (or the tip of the stylus is removed from the tablet) while the mouse (or the stylus) is over a UIElement (or while a UIElement holds mouse capture). (Inherited from UIElement.)
It might also be possible to solve this the other way around by releasing the MouseCapture (if that is causing the problem) by using ReleaseMouseCapture
Again, it depends on what you want to happen from the user's point of view: skip the loading of the data (this is what I would prefer because I do not like the content to be changing when I am scrolling) or reset the listbox and scroll to the top (ugly in my opinion)

How do you navigate a complex Visual Tree in order to re-bind an existing element?

In the above image, child is a ContentPresenter. Its Content is a ViewModel. However, its ContentTemplate is null.
In my XAML, I have a TabControl with the following structure:
<local:SuperTabControlEx DataContext="{Binding WorkSpaceListViewModel}"
x:Name="superTabControl1" CloseButtonVisibility="Visible" TabStyle="OneNote2007" ClipToBounds="False" ContentInnerBorderBrush="Red" FontSize="24" >
<local:SuperTabControlEx.ItemsSource>
<Binding Path="WorkSpaceViewModels" />
</local:SuperTabControlEx.ItemsSource>
<TabControl.Template>
<ControlTemplate
TargetType="TabControl">
<DockPanel>
<TabPanel
DockPanel.Dock="Top"
IsItemsHost="True" />
<Grid
DockPanel.Dock="Bottom"
x:Name="PART_ItemsHolder" />
</DockPanel>
<!-- no content presenter -->
</ControlTemplate>
</TabControl.Template>
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:WorkSpaceViewModel}">
....
WorkSpaceViewModels is an ObservableCollection of WorkSpaceViewModel. This code uses the code and technique from Keeping the WPF Tab Control from destroying its children.
The correct DataTemplate - shown above in the TabControl.Resource - appears to be rendering my ViewModel for two Tabs.
However, my basic question is, how is my view getting hooked up to my WorkSpaceViewModel, yet, the ContentTemplate on the ContentPresenter is null? My requirement is to access a visual component from the ViewModel because a setting for the view is becoming unbound from its property in the ViewModel upon certain user actions, and I need to rebind it.
The DataTemplate is "implicitly" defined. The ContentPresenter will first use it's ContentTemplate/Selector, if any is defined. If not, then it will search for a DataTemplate resource without an explicit x:Key and whose DataType matches the type of it's Content.
This is discussed here and here.
The View Model shouldn't really know about it's associated View. It sounds like there is something wrong with your Bindings, as in general you should not have to "rebind" them. Either way, an attached behavior would be a good way to accomplish that.
I think the full answer to this question entails DrWPF's full series ItemsControl: A to Z. However, I believe the gist lies in where the visual elements get stored when a DataTemplate is "inflated" to display the data item it has been linked to by the framework.
In the section Introduction to Control Templates of "ItemsControl: 'L' is for Lookless", DrWPF explains that "We’ve already learned that a DataTemplate is used to declare the visual representation of a data item that appears within an application’s logical tree. In ‘P’ is for Panel, we learned that an ItemsPanelTemplate is used to declare the items host used within an ItemsControl."
For my issue, I still have not successfully navigated the visual tree in order to get a reference to my splitter item. This is my best attempt so far:
// w1 is a Window
SuperTabControlEx stc = w1.FindName("superTabControl1") as SuperTabControlEx;
//SuperTabItem sti = (SuperTabItem)(stc.ItemContainerGenerator.ContainerFromItem(stc.Items.CurrentItem));
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(stc);
//ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(sti);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
The above code is an attempt to implement the techniques shown on the msdn web site. However, when I apply it to my code, everything looks good, except myDataTemplate comes back null. As you can see, I attempted the same technique on SuperTabControlEx and SuperTabItem, derived from TabControl and TabItem, respectively. As described in my original post, and evident in the XAML snippet, the SuperTabControlEx also implements code from Keeping the WPF Tab Control from destroying its children.
At this point, perhaps more than anything else, I think this is an exercise in navigating the Visual Tree. I am going to modify the title of the question to reflect my new conceptions of the issue.

Resources