How I can move focus from tabitem title to content in WPF? - wpf

How I can move focus from tabitem title to content of this tabitem by pressing downarrow?
I tried to use KeyboardNavigation but Keyboardfocus still doesn't move when I press down or up key.
Thanks in advance.

I created an attached property to address a similar problem. When you press a certain key on a ContentControl (TabItem), it focuses on the content. The XAML looks like this
<TabControl Focusable="False">
<TabItem Header="Main" local:Focus.ContentOn="Down">
<Stackpanel>
<TextBox />
</Stackpanel>
</TabItem>
And the Attached Property:
public static class Focus
{
public static Key GetContentOn(DependencyObject obj)
{
return (Key)obj.GetValue(ContentOnProperty);
}
public static void SetContentOn(DependencyObject obj, Key value)
{
obj.SetValue(ContentOnProperty, value);
}
// Using a DependencyProperty as the backing store for ContentOn. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ContentOnProperty =
DependencyProperty.RegisterAttached("ContentOn", typeof(Key), typeof(Navigate),
new FrameworkPropertyMetadata(Key.None, OnContentOnChanged));
private static void OnContentOnChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var control = o as ContentControl;
if (control != null)
control.KeyDown += FocusContent;
}
private static void FocusContent(object sender, KeyEventArgs e)
{
if (Keyboard.FocusedElement == sender)
{
var control = sender as ContentControl;
if (control != null && control.HasContent && GetContentOn(control) == e.Key)
{
((FrameworkElement)control.Content).MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
e.Handled = true;
}
}
}
}

Related

Mouseover button binding in WPF

What technique could be used in WPF to show TextBlock Text based on the Button that has mouse over on it?
The UI is organized as follows:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel>
<Button Content="Item1" Tag="This is the text for Item1"/>
<Button Content="Item2" Tag="This is the text for Item2"/>
<Button Content="Item3" Tag="This is the text for Item3"/>
</StackPanel>
<TextBlock Grid.Column="2" Margin="20,0,0,0" TextWrapping="Wrap" Text="This text should be shown based on the mouseovered button"/>
</Grid>
I was thinking to set the desired text to Tag of the Button but how to get that Tag to show on the mouse over event.
Notes:
I prefer to use individual Buttons here instead of ListBox or any other ItemsControl (the real application has more controls between these things etc.)
The application follows MVVM
I would prefer an approach other that setting the texts to UI directly (Tag of the Button)
For Mouse Move over,
Create an AttachedProperty for MouseMove and hook your list view with the property. The attached property can be used to any element in your application.
Attached Property
public class MouseBehaviour
{
public static readonly DependencyProperty MouseMoveCommandProperty =
DependencyProperty.RegisterAttached("MouseMoveCommand", typeof(ICommand), typeof(MouseBehaviour), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseMoveCommandChanged)));
private static void MouseMoveCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseMove += new MouseEventHandler(element_MouseMove);
}
static void element_MouseMove(object sender, MouseEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseMoveCommand(element);
command.Execute(e);
}
public static void SetMouseMoveCommand(UIElement element, ICommand value)
{
element.SetValue(MouseMoveCommandProperty, value);
}
public static ICommand GetMouseMoveCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseMoveCommandProperty);
}
}
XAML
xmlns:mousebehav="clr-namespace:your namespace"
<Button mousebehav:MouseBehaviour.MouseMoveCommand="{Binding MouseMoveCommand}">
VM
private RelayCommand _MouseMoveCommand;
public RelayCommand MouseMoveCommand
{
get
{
if (_MouseMoveCommand== null) return _MouseMoveCommand= new RelayCommand(param => Execute_MouseMoveCommand((MouseEventArgs)param));
return _MouseMoveCommand;
}
set { _MouseMoveCommand= value; }
}
private void Execute_MouseMoveCommand(MouseEventArgs param)
{
//your logic to expand or ??
}
Attached property for Mouse Leave,
public static readonly DependencyProperty MouseLeaveCommandProperty =
DependencyProperty.RegisterAttached("MouseLeaveCommand", typeof(ICommand), typeof(MouseBehaviour), new FrameworkPropertyMetadata(new PropertyChangedCallback(MouseLeaveCommandChanged)));
private static void MouseLeaveCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
element.MouseLeave += new MouseEventHandler(element_MouseLeave);
}
static void element_MouseLeave(object sender, MouseEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
ICommand command = GetMouseLeaveCommand(element);
command.Execute(e);
}
public static void SetMouseLeaveCommand(UIElement element, ICommand value)
{
element.SetValue(MouseLeaveCommandProperty, value);
}
public static ICommand GetMouseLeaveCommand(UIElement element)
{
return (ICommand)element.GetValue(MouseLeaveCommandProperty);
}
VM
private RelayCommand _MouseLeaveCommand;
public RelayCommand MouseLeaveCommand
{
get
{
if (_MouseLeaveCommand== null) return _MouseLeaveCommand= new RelayCommand(param => Execute_MouseLeaveCommand((MouseEventArgs)param));
return _MouseLeaveCommand;
}
set { _MouseMoveCommand= value; }
}
private void Execute_MouseLeaveCommand(MouseEventArgs param)
{
//your logic to expand or ??
}
XAML
<Button mousebehav:MouseBehaviour.MouseLeaveCommand="{Binding MouseLeaveCommand}">

WPF: Disable arrow-keys on tabcontrol

I'm using the WPF TabControl in my application in order to switch between different areas/functions of the program.
One thing annoys me though. I have hidden the tabs so I can control the selectedtab, instead of the user. The user however, can still switch between tabs using the arrow-keys.
I have tried using the KeyboardNavigation-attribute, but I can't get this working.
Can this be disabled?
You can hook on to the TabControl.PreviewKeyDown event for this one. Check to see if it's the left or right arrow and say that you've handled it.
private void TabControl_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Left || e.Key == Key.Right)
e.Handled = true;
}
if you're using a pure view model application you could apply the above as an attached property.
XAMl to use the below attached property.
<TabControl local:TabControlAttached.IsLeftRightDisabled="True">
<TabItem Header="test"/>
<TabItem Header="test"/>
</TabControl>
TabControlAttached.cs
public class TabControlAttached : DependencyObject
{
public static bool GetIsLeftRightDisabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsLeftRightDisabledProperty);
}
public static void SetIsLeftRightDisabled(DependencyObject obj, bool value)
{
obj.SetValue(IsLeftRightDisabledProperty, value);
}
// Using a DependencyProperty as the backing store for IsLeftRightDisabled. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsLeftRightDisabledProperty =
DependencyProperty.RegisterAttached("IsLeftRightDisabled", typeof(bool), typeof(MainWindow), new UIPropertyMetadata(false, new PropertyChangedCallback((s, e) =>
{
// get a reference to the tab control.
TabControl targetTabControl = s as TabControl;
if (targetTabControl != null)
{
if ((bool)e.NewValue)
{
// Need some events from it.
targetTabControl.PreviewKeyDown += new KeyEventHandler(targetTabControl_PreviewKeyDown);
targetTabControl.Unloaded += new RoutedEventHandler(targetTabControl_Unloaded);
}
else if ((bool)e.OldValue)
{
targetTabControl.PreviewKeyDown -= new KeyEventHandler(targetTabControl_PreviewKeyDown);
targetTabControl.Unloaded -= new RoutedEventHandler(targetTabControl_Unloaded);
}
}
})));
static void targetTabControl_Unloaded(object sender, RoutedEventArgs e)
{
TabControl targetTabControl = sender as TabControl;
targetTabControl.PreviewKeyDown -= new KeyEventHandler(targetTabControl_PreviewKeyDown);
targetTabControl.Unloaded -= new RoutedEventHandler(targetTabControl_Unloaded);
}
static void targetTabControl_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Left || e.Key == Key.Right)
e.Handled = true;
}
}

MVVM- How can I bind to a property, which is not a DependancyProperty?

I have found this question MVVM and the TextBox's SelectedText property. However, I am having trouble getting the solution given to work. This is my non-working code, in which I am trying to display the first textbox's selected text in the second textbox.
View:
SelectedText and Text are just string properties from my ViewModel.
<TextBox Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" Height="155" HorizontalAlignment="Left" Margin="68,31,0,0" Name="textBox1" VerticalAlignment="Top" Width="264" AcceptsReturn="True" AcceptsTab="True" local:TextBoxHelper.SelectedText="{Binding SelectedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" />
<TextBox Text="{Binding SelectedText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Height="154" HorizontalAlignment="Left" Margin="82,287,0,0" Name="textBox2" VerticalAlignment="Top" Width="239" />
TextBoxHelper
public static class TextBoxHelper
{
#region "Selected Text"
public static string GetSelectedText(DependencyObject obj)
{
return (string)obj.GetValue(SelectedTextProperty);
}
public static void SetSelectedText(DependencyObject obj, string value)
{
obj.SetValue(SelectedTextProperty, value);
}
// Using a DependencyProperty as the backing store for SelectedText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.RegisterAttached(
"SelectedText",
typeof(string),
typeof(TextBoxHelper),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedTextChanged));
private static void SelectedTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TextBox tb = obj as TextBox;
if (tb != null)
{
if (e.OldValue == null && e.NewValue != null)
{
tb.SelectionChanged += tb_SelectionChanged;
}
else if (e.OldValue != null && e.NewValue == null)
{
tb.SelectionChanged -= tb_SelectionChanged;
}
string newValue = e.NewValue as string;
if (newValue != null && newValue != tb.SelectedText)
{
tb.SelectedText = newValue as string;
}
}
}
static void tb_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox tb = sender as TextBox;
if (tb != null)
{
SetSelectedText(tb, tb.SelectedText);
}
}
#endregion
}
What am I doing wrong?
The reason this is not working is that the property change callback isn't being raised (as the bound value from your VM is the same as the default value specified in the metadata for the property). More fundamentally though, your behavior will detach when the selected text is set to null. In cases like this, I tend to have another attached property that is simply used to enable the monitoring of the selected text, and then the SelectedText property can be bound. So, something like so:
#region IsSelectionMonitored
public static readonly DependencyProperty IsSelectionMonitoredProperty = DependencyProperty.RegisterAttached(
"IsSelectionMonitored",
typeof(bool),
typeof(PinnedInstrumentsViewModel),
new FrameworkPropertyMetadata(OnIsSelectionMonitoredChanged));
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static bool GetIsSelectionMonitored(TextBox d)
{
return (bool)d.GetValue(IsSelectionMonitoredProperty);
}
public static void SetIsSelectionMonitored(TextBox d, bool value)
{
d.SetValue(IsSelectionMonitoredProperty, value);
}
private static void OnIsSelectionMonitoredChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TextBox tb = obj as TextBox;
if (tb != null)
{
if ((bool)e.NewValue)
{
tb.SelectionChanged += tb_SelectionChanged;
}
else
{
tb.SelectionChanged -= tb_SelectionChanged;
}
SetSelectedText(tb, tb.SelectedText);
}
}
#endregion
#region "Selected Text"
public static string GetSelectedText(DependencyObject obj)
{
return (string)obj.GetValue(SelectedTextProperty);
}
public static void SetSelectedText(DependencyObject obj, string value)
{
obj.SetValue(SelectedTextProperty, value);
}
// Using a DependencyProperty as the backing store for SelectedText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.RegisterAttached(
"SelectedText",
typeof(string),
typeof(TextBoxHelper),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedTextChanged));
private static void SelectedTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TextBox tb = obj as TextBox;
if (tb != null)
{
tb.SelectedText = e.NewValue as string;
}
}
static void tb_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox tb = sender as TextBox;
if (tb != null)
{
SetSelectedText(tb, tb.SelectedText);
}
}
#endregion
And then in your XAML, you'd have to add that property to your first TextBox:
<TextBox ... local:TextBoxHelper.IsSelectionMonitored="True" local:TextBoxHelper.SelectedText="{Binding SelectedText, Mode=OneWayToSource}" />
In order for the SelectedTextChanged handler to fire the SelectedText property must have an initial value. If you don't initialize this to some value (string.Empty as a bare minimum) then this handler will never fire and in turn you'll never register the tb_SelectionChanged handler.
This works for me using the class TextBoxHelper. As other mentioned, you need to initialize the SelectedText property of TextBoxHelper with a non null value. Instead of data binding to a string property (SelText) on the view you should bind to a string property of your VM which should implement INotifyPropertyChanged.
XAML:
<Window x:Class="TextSelectDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TextSelectDemo"
Height="300" Width="300">
<StackPanel>
<TextBox local:TextBoxHelper.SelectedText="{Binding Path=SelText, Mode=TwoWay}" />
<TextBox Text="{Binding Path=SelText}" />
</StackPanel>
</Window>
Code behind:
using System.ComponentModel;
using System.Windows;
namespace TextSelectDemo
{
public partial class Window1 : Window, INotifyPropertyChanged
{
public Window1()
{
InitializeComponent();
SelText = string.Empty;
DataContext = this;
}
private string _selText;
public string SelText
{
get { return _selText; }
set
{
_selText = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("SelText"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
Your binding attempts to bind the Text property of your TextBox to a SelectedText property of the TextBox's current data context. Since you're working with an attached property, not with a property hanging off of your data context, you will need to give more information in your binding:
<TextBox Text="{Binding local:TextBoxHelper.SelectedText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" ... />
Where local has been associated with the CLR namespace containing the TextBoxHelper class.
You need a normal .net property wrapper for the dependencyproperty, some like:
public string SelectedText
{
set {SetSelectedText(this, value);}
...
It is not required by runtime (runtime use set/get) but it is required by designer and compiler.

Keeping keyboard focus on a single control while still beeing able to use a ListBox

Working on a TouchScreen application which also has a keyboard attached, I have the following problem:
The WPF window has a TextBox, which should receive ALL keyboard input. There are also Buttons and a ListBox, which are solely used by the TouchScreen(=Mouse).
A very simple example looks like this:
<Window x:Class="KeyboardFocusTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1">
<StackPanel>
<TextBox Text="{Binding Input, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PreviewLostKeyboardFocus="TextBox_PreviewLostKeyboardFocus"/>
<Button Click="Button_Click">Add</Button>
<ListBox ItemsSource="{Binding Strings}" />
</StackPanel>
</Window>
To keep the TextBox always focused, I just do:
private void TextBox_PreviewLostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
{
e.Handled = true;
}
So far so good - the problem now is, that I can't select items from the ListBox anymore. This only seems to work, if the ListBox has the keyboard focus. But if I loose the keyboard focus on the TextBox, I can't enter text anymore without clicking it first.
Any ideas, comments suggestions are welcome!
There might be a more elegant solution for this, but you could always handle the PreviewKeyDown event at the Window level, and pass focus to the TextBox if it doesn't already have it, instead of preventing it from losing focus in the first place. That way, the ListBox can use focus as is normal, but as soon as a key is pressed focus jumps right to the TextBox. In addition, you can filter out keys that you don't want to switch focus - the arrow keys come to mind, which could then be used to move up and down in the ListBox.
Adding an event handler like the following should do the trick:
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (!textBox.IsFocused)
{
textBox.Focus();
}
}
Based on Nicholas' suggestion (thx!), here's a markup extension, which is used like:
<TextBox Helpers:KeyboardFocusAttractor.IsAttracted="true" />
It seems to work, and ANTS didn't show any memory leaks. But when it comes to WPF and especially events and bindings, you never know, so use with care!
public static class KeyboardFocusAttractor
{
public static readonly DependencyProperty IsAttracted = DependencyProperty.RegisterAttached("IsAttracted",
typeof (bool), typeof (KeyboardFocusAttractor), new PropertyMetadata(false, OnIsAttracted));
private static void OnIsAttracted(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var isAttracted = (bool) e.NewValue;
var controlWithInputFocus = d as Control;
if (controlWithInputFocus != null)
{
if (isAttracted)
{
new KeyboardInputFocusEventManager(controlWithInputFocus);
}
}
}
public static void SetIsAttracted(DependencyObject dp, bool value)
{
dp.SetValue(IsAttracted, value);
}
public static bool GetIsAttracted(DependencyObject dp)
{
return (bool) dp.GetValue(IsAttracted);
}
private class KeyboardInputFocusEventManager
{
private readonly Control _control;
private Window _window;
public KeyboardInputFocusEventManager(Control control)
{
_control = control;
_control.Loaded += ControlLoaded;
_control.IsVisibleChanged += ControlIsVisibleChanged;
_control.Unloaded += ControlUnloaded;
}
private void ControlLoaded(object sender, RoutedEventArgs e)
{
_window = Window.GetWindow(_control);
if (_window != null)
{
_control.Unloaded += ControlUnloaded;
_control.IsVisibleChanged += ControlIsVisibleChanged;
if (_control.IsVisible)
{
_window.PreviewKeyDown += ParentWindowPreviewKeyDown;
}
}
}
private void ControlUnloaded(object sender, RoutedEventArgs e)
{
_control.Unloaded -= ControlUnloaded;
_control.IsVisibleChanged -= ControlIsVisibleChanged;
}
private void ControlIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (_window != null)
{
_window.PreviewKeyDown -= ParentWindowPreviewKeyDown;
}
if (_control.IsVisible)
{
_window = Window.GetWindow(_control);
if (_window != null)
{
_window.PreviewKeyDown += ParentWindowPreviewKeyDown;
}
}
}
private void ParentWindowPreviewKeyDown(object sender, KeyEventArgs e)
{
Keyboard.Focus(_control);
}
}
}

Interpret enter as tab WPF

I want to interpret Enter key as Tab key in whole my WPF application, that is, everywhere in my application when user press Enter I want to focus the next focusable control,except when button is focused. Is there any way to do that in application life circle? Can anyone give me an example?
Thanks a lot!
You can use my EnterKeyTraversal attached property code if you like. Add it to the top-level container on a WPF window and everything inside will treat enter as tab:
<StackPanel my:EnterKeyTraversal.IsEnabled="True">
...
</StackPanel>
Based on Richard Aguirre's answer, which is better than the selected answer for ease of use, imho, you can make this more generic by simply changing the Grid to a UIElement.
To change it in whole project you need to do this
In App.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
EventManager.RegisterClassHandler(typeof(UIElement), UIElement.PreviewKeyDownEvent, new KeyEventHandler(Grid_PreviewKeyDown));
base.OnStartup(e);
}
private void Grid_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
var uie = e.OriginalSource as UIElement;
if (e.Key == Key.Enter)
{
e.Handled = true;
uie.MoveFocus(
new TraversalRequest(
FocusNavigationDirection.Next));
}
}
Compile.
And done it. Now you can use enter like tab.
Note: This work for elements in the grid
I got around woodyiii's issue by adding a FrameworkElement.Tag (whose value is IgnoreEnterKeyTraversal) to certain elements (buttons, comboboxes, or anything I want to ignore the enter key traversal) in my XAML. I then looked for this tag & value in the attached property. Like so:
if (e.Key == Key.Enter)
{
if (ue.Tag != null && ue.Tag.ToString() == "IgnoreEnterKeyTraversal")
{
//ignore
}
else
{
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
woodyiii, There is a function in the UIElement called PredictFocus() which by its name know its function, then you can check if that element is enabled or not so as to move the focus to it or not...
Here is Matt Hamilton's code, if anyone is wondering since his site is down apparently:
public class EnterKeyTraversal
{
public static bool GetIsEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}
static void ue_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
var ue = e.OriginalSource as FrameworkElement;
if (e.Key == Key.Enter)
{
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
private static void ue_Unloaded(object sender, RoutedEventArgs e)
{
var ue = sender as FrameworkElement;
if (ue == null) return;
ue.Unloaded -= ue_Unloaded;
ue.PreviewKeyDown -= ue_PreviewKeyDown;
}
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool),
typeof(EnterKeyTraversal), new UIPropertyMetadata(false, IsEnabledChanged));
static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ue = d as FrameworkElement;
if (ue == null) return;
if ((bool)e.NewValue)
{
ue.Unloaded += ue_Unloaded;
ue.PreviewKeyDown += ue_PreviewKeyDown;
}
else
{
ue.PreviewKeyDown -= ue_PreviewKeyDown;
}
}
}
Another, a more on/off implementation approach would be to use behaviors:
public class TextBoxEnterFocusesNextBehavior :
Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewKeyDown += AssociatedObjectOnPreviewKeyDown;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewKeyDown -= AssociatedObjectOnPreviewKeyDown;
base.OnDetaching();
}
private void AssociatedObjectOnPreviewKeyDown(object sender, KeyEventArgs args)
{
if (args.Key != Key.Enter) { return; }
args.Handled = true;
AssociatedObject.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
Usage example:
<UserControl xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:behaviors="clr-namespace:Your.Namespace.To.Behaviors"
...>
<DockPanel>
<TextBox x:Name="TextBoxWithBehavior"
DockPanel.Dock="Top">
<b:Interaction.Behaviors>
<behaviors:TextBoxEnterFocusesNextBehavior />
</b:Interaction.Behaviors>
</TextBox>
<TextBox x:Name="TextBoxWithoutBehavior"
DockPanel.Dock="Top" />
<TextBox x:Name="AnotherTextBoxWithBehavior"
DockPanel.Dock="Top">
<b:Interaction.Behaviors>
<behaviors:TextBoxEnterFocusesNextBehavior />
</b:Interaction.Behaviors>
</TextBox>
</DockPanel>
</UserControl>
My solution:
public class MoveToNext : TriggerAction<DependencyObject>
{
protected override void Invoke(object parameter)
{
if (parameter is RoutedEventArgs routedEventArgs && routedEventArgs.OriginalSource is FrameworkElement element)
{
routedEventArgs.Handled = true;
element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
}
Usage:
<StackPanel>
<i:Interaction.Triggers>
<i:KeyTrigger Key="Return">
<util:MoveToNext/>
</i:KeyTrigger>
</i:Interaction.Triggers>
<!-- put your controls here -->
</StackPanel>
If you want the behavior to be attached to only one control instead of all controls within a layouter, simply add the <i:Interaction.Triggers block to that specific control.

Resources