Override tab navigation for XAML ListBox - wpf

I want a list of items that are selectable, so naturally I chose ListBox. However the tab/arrowing behavior is not what I want. I need the tab behavior of ItemsControl without the arrow key functionality. So if I have three UIElements like:
ButtonA
ListBox
ButtonB
then the tab order will be:
ButtonA, ListBoxItem1, ... ListBoxItemN, ButtonB, ButtonA, ....
Unfortunately the default ListBox tab navigation makes the tab order:
ButtonA, ListBoxSelectedItem, ButtonB, ButtonA, ....
All is well if I use an ItemsControl, but ItemsControl has no selected item logic.

setting the KeyboardNavigation.TabNavigation in the ListBox to "Continue" should do it :
<StackPanel>
<Button Content="ButtonA"/>
<ListBox KeyboardNavigation.TabNavigation="Continue">
<ListBoxItem Content="One"/>
<ListBoxItem Content="Two"/>
<ListBoxItem Content="Three"/>
<ListBoxItem Content="Four"/>
</ListBox>
<Button Content="ButtonB"/>
</StackPanel>

Related

How does the Content property work

Both syntaxes below works. My question is how does WPF know Content is what I specified?
<Button>
<Button.Content>
my button
</Button.Content>
</Button>
<Button>
my button <!--how does wpf know this is the content-->
</Button>
similarly, how does wpf know I'm now adding ListBoxItems
<ListBox>
<!--ListBox.Items-->
<ListBoxItem Content="item 1" /> <!--XAML automatically knows I'm specifying items-->
item 2
<ListBoxItem Content="item 3" />
<!--/ListBox.Items-->
</ListBox>
So in ContentControl, the default property is Content, and with ItemsControl, the default is Items, and with TextBox, the default is TextBox.
How does this 'default' work?
How do I create this 'default property' when I creat a Custom Control?
ContentPropertyAttribute tells xaml parser which property to use for direct content.
ContentControl, from which Button inherits, is marked with attibute [ContentProperty("Content")]. Similarly, ItemsControl (ancestor of ListBox) is marked with [ContentProperty("Items")].

ScrollViewer Focus doesn't change to outer control

I have used ListBox inside TreeView
<TreeView Height="300">
<TreeViewItem Header="Item1"/>
<TreeViewItem Header="Item2">
<ListBox Height="100">
<ListBoxItem Content="Item1"/>
<ListBoxItem Content="Item2"/>
<ListBoxItem Content="Item3"/>
<ListBoxItem Content="Item4"/>
<ListBoxItem Content="Item5"/>
<ListBoxItem Content="Item6"/>
<ListBoxItem Content="Item7"/>
<ListBoxItem Content="Item8"/>
</ListBox>
</TreeViewItem>
<TreeViewItem Header="Item3">
<ListBox Height="100">
<ListBoxItem Content="Item1"/>
<ListBoxItem Content="Item2"/>
<ListBoxItem Content="Item3"/>
<ListBoxItem Content="Item4"/>
<ListBoxItem Content="Item5"/>
<ListBoxItem Content="Item6"/>
<ListBoxItem Content="Item7"/>
<ListBoxItem Content="Item8"/>
</ListBox>
</TreeViewItem>
<TreeViewItem Header="Item4">
<ListBox />
</TreeViewItem>
<TreeViewItem Header="Item5">
<ListBox />
</TreeViewItem>
<TreeViewItem Header="Item6"/>
</TreeView>
When I point the mouse point in ListBox and start scrolling the ListBox get scrolled. When the Scrolling gets end I need to change the focus to TreeView scroll viewer so, that TreeView get scroll. In this code the scrolling doesn't work for TreeView when mouse is inside ListBox.
I need to change the focus to outer control scroll viewer when after ListBox get scrolled
This is not a good description of your problem, but if you are saying that you want to be able to move focus from inside the ListBox to outside the ListBox, then it seems that all you need is to learn how to navigate a ListBox from a keyboard using the arrow keys.
If focus is on a TreeViewItem that has a ListBox in it, then you can press the right arrow key to expand the item and iterate through the ListBoxItems. You can then press the up and down arrow keys to select the previous or next items in the ListBox.
Once you have finished looking through the ListBoxItems, you can then press the left arrow key to navigate back to the TreeViewItem from the ListBox. You will then be able to press the up and down arrow keys to navigate through the TreeViewItems once again.
If that has not helped you with your problem, then please edit your question and add a clear description of your problem.
UPDATE >>>
You can detect when a ListBox has been scrolled to the bottom by handling the ScrollViewer.ScrollChanged event:
<ListBox ItemsSource="{Binding Days}" ScrollViewer.CanContentScroll="False"
ScrollViewer.ScrollChanged="ListBox_ScrollChanged" />
...
private void ListBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ScrollViewer scrollViewer = (ScrollViewer)e.OriginalSource;
if (scrollViewer.VerticalOffset + scrollViewer.ViewportHeight ==
scrollViewer.ExtentHeight)
{
// The ListBox was scrolled to the bottom
}
}
Then, you can focus the next UI element using the TraversalRequest class and the UIElement.MoveFocus method:
TraversalRequest request = new TraversalRequest(FocusNavigationDirection.Next);
UIElement focusedElement = Keyboard.FocusedElement as UIElement;
if (focusedElement != null) focusedElement.MoveFocus(request);

WPF Listbox Selection change not firing on Item click

In my wpf application when I select listboxItem, SelectionChanged event of listbox is not firing. However event fires when I click on outer margin.
have a look at below snap.
so basically, when I click on section inside Red border(Right Image), Selection change event is not firing, but when I click on outer border (White color part), selection change fires.
While searching about issue, I am not sure but I found it may be issue due to event tunneling. However I have only a bit of knowledge about tunneling yet.
So can any one please help me how this can get working so that selection change fire when I click on listboxitem (Red section)
let me if I need to further clear question.
I am also putting listbox code here
<ListBox x:Name="Listbox1" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem Margin="10" Content="{Binding Name}" Height="25"
BorderBrush="#FF404040" BorderThickness="0,0.25" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thanks in anticipation
I can't think of a reason why you would want to have a ListBoxItem inside the DataTemplate of a ItemTemplate. The ListBoxItems are genarated automatically for each element of the ListBox and whatever you have in your DataTemplate will be used as the content of that ListBoxItem So in your case you end up having a ListBoxItem inside a ListBoxItem. This might be the cause.
Try it this way:
<ListBox x:Name="Listbox1" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Margin="10"
Content="{Binding Name}"
Height="25"
BorderBrush="#FF404040"
BorderThickness="0,0.25" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

ListBox is selecting more than one item when it is being dragged

I have a ListBox with RadioButton inside it of the same GroupName.
Like so:
<ListBox x:Name="AnswerListBox" DataContext="{Binding .}" ItemsSource="{Binding Answers}" Width="auto" HorizontalAlignment="Center" >
<ListBox.ItemTemplate>
<DataTemplate>
<local:spriteToggleButton DataContext="{Binding .}" HorizontalAlignment="Center" Text="{Binding text}" Selected="{Binding selected}" Sprites="{Binding Path=DataContext.UISprites, ElementName=questionField}" IsChecked="{Binding selected, Mode=TwoWay}" GroupName="{Binding Path=DataContext.QuestionTitle, ElementName=questionField}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When I click on a RadioButton it will unselect another in that group, this is fine.
But when I do a swipe down on the ListBox it will select more than one RadioButton which is an unwanted behavior.
There might be more than one way of changing that behavior.
I don't need it to scroll up and down the list as I will only show as many items as will fit on screen. so maybe that behavior can be disabled.
Maybe a callback could incur when the ListBox is scrolled and something could disable selection when dragging in being done.
the DataContext to the listbox is of List<> so is there a way to change the setter of my Selected variable in my List<> so that it unsets the other values in that list.
Set ScrollViewer.VerticalScrollBarVisibility to "Disabled" on the ListBox element.
In the SelectionChanged event, set the SelectedIndex to -1
You could clear all the other values in the ItemsSource in the SelectionChanged event.

EditingCommands of the WPF RichTextBox loose its binding when they are not put within a ToolBar

Using the below code in a DataGridTemplateColumn of the DataGrid, my formatting buttons are disabled(grayed out). The formatting buttons are only enabled when they are put in a ToolBar.
When the buttons are put in a ToolBar I do not need the CommandTarget. So when I put them outside a ToolBar some could think it must work with CommandTarget, but it does not, WHY ?
<Button Content="K" CommandTarget="{Binding ElementName=RTFBox}" Command="EditingCommands.ToggleItalic"/>
<Button Content="U" CommandTarget="{Binding ElementName=RTFBox}" Command="EditingCommands.ToggleUnderline" />
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Helper:RichTextBox VerticalScrollBarVisibility="Auto" x:Name="RTFBox" LostFocus="RTFBox_LostFocus" Text="{Binding Notes, UpdateSourceTrigger=PropertyChanged}" >
<Helper:RichTextBox.TextFormatter>
<Helper:RtfFormatter />
</Helper:RichTextBox.TextFormatter>
<RichTextBox.CommandBindings>
<CommandBinding Command="EditingCommands.ToggleUnderline"/>
<CommandBinding Command="EditingCommands.ToggleItalic"/>
</RichTextBox.CommandBindings>
</Helper:RichTextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
ToolBar has FocusManager.IsFocusScope="True" which is by default false.
Just put FocusManager.IsFocusScope="True" inside the panel that holds the buttons.
CommandTarget is to limit the buttons if they are in a IsFocusScope="True" panel - e.g. if you have two RichTextBoxes and you only want the buttons to work on one of them.

Resources