UWP TextBox Behaviour for Focus & Command Binding





5.00/5 (1 vote)
Adds MVVM focusing and command execution on keypress to universal Windows platorm textbox via attached properties.
Introduction
This is a behaviour class that you can plug into your universal Windows platform to provide a means of focusing a textbox in an MVVM fashion and also provides the ability to execute a command based on a key press.
Background
See the following article for an introduction to the concept of attached behaviours:
Using the Code
The behaviour
class provides two features.
Focus
The focusing capabilities have the following elements.
First, an attached property to indicate if the control has focus or not.
/// <summary>
/// Declare new attached property.
/// </summary>
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached("IsFocused", typeof(bool),
typeof(TextBoxBehaviour), new PropertyMetadata(default(bool), OnIsFocusedChanged));
When the IsFocused
property is changed, the OnIsFocusedChanged
method will be called. Within the method; if the IsFocused
property is true
, then the control is Focused
. Additionally, handling is attached for the LostFocus
event.
/// <summary>
/// This method will be called when the IsFocused
/// property is changed
/// </summary>
/// <param name="s">System.Object repersenting the source of the event.</param>
/// <param name="e">The arguments for the event.</param>
public static void OnIsFocusedChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
//If the host object is a frame.
if (s is TextBox)
{
//Unbox.
TextBox t = s as TextBox;
//If setting is true.
if ((bool)e.NewValue)
{
//Set the Focus
t.Focus(FocusState.Pointer);
//Attach handling for lost focus.
t.LostFocus += textbox_LostFocus;
}
else
{
//Remove handling.
t.LostFocus -= textbox_LostFocus;
}
}
}
Inside the LostFocus
event, the property is reset.
/// <summary>
/// Handling for when the texbox looses focus.
/// </summary>
/// <param name="sender">System.Object repersenting the source of the event.</param>
/// <param name="e">The arguments for the event.</param>
private static void textbox_LostFocus(object sender, RoutedEventArgs e)
{
//Unbox.
TextBox t = sender as TextBox;
//Set dependency property.
t.SetValue(IsFocusedProperty, false);
}
In your view, add the namespace for the behaviour.
xmlns:behave="using:UtilitiesUniversal.Behaviours"
You could then use the attached property as follows. Note that I have binded the property to the check state of a toggle button element placed elsewhere on the page. Now the focus of the control is toggled along with the toggle button checkstate. A potentially useful feature for one handed use on mobile.
<TextBox Name="filterText"
behave:TextBoxBehaviour.IsFocused="{Binding ElementName=filterBtn,
Path=IsChecked, Mode=TwoWay}" Height="48"
InputScope="AlphanumericFullWidth"
VerticalContentAlignment="Center" FontSize="25" >
...
<CommandBar ClosedDisplayMode="Compact" Name="commands">
<AppBarToggleButton Icon="Filter"
x:Uid="Filter" Name="filterBtn" IsChecked="False"/>
</CommandBar>
Command Binding
The other feature provided by the behaviour class is for executing a command on a keypress.
The command binding feature has the following elements.
First, there is the property to house the desired command.
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand),
typeof(TextBoxBehaviour), new PropertyMetadata(null));
The other property is of course the desired key that will trigger the command.
public static readonly DependencyProperty CommandKeyProperty =
DependencyProperty.RegisterAttached("CommandKey", typeof(string),
typeof(TextBoxBehaviour), new PropertyMetadata(default(string), OnCommandKeyChanged));
In the OnCommandKeyChanged
,
Callback handling is attached for the KeyDown
event.
private static void OnCommandKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextBox)
{
//Unbox.
TextBox t = d as TextBox;
//If the key is set.
if (e.NewValue != null && e.NewValue.ToString().Length > 0)
{
t.KeyDown += T_KeyDown;
}
else
{
t.KeyDown -= T_KeyDown;
}
}
}
In the KeyDown
event handler, the pressed key is compared to the CommandKey
property and if it matches, the command is executed.
private static void T_KeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
{
TextBox t = sender as TextBox;
if (e.Key.ToString() == t.GetValue(CommandKeyProperty).ToString())
{
//Handle.
e.Handled = true;
// Get command
ICommand command = GetCommand(t);
// Execute command
command.Execute(null);
}
}
In your view, add the namespace for the behaviour:
xmlns:behave="using:UtilitiesUniversal.Behaviours"
Now, you can use the property as follows; In the example, I will execute the ReadCommand
in the current datacontext
when the enter button is pressed in the textbox
.
<TextBox AcceptsReturn="False"
behave:TextBoxBehaviour.Command="{Binding ReadCommand}"
behave:TextBoxBehaviour.CommandKey="{Binding FakeBinding,FallbackValue=Enter}"
InputScope="AlphanumericFullWidth"
VerticalContentAlignment="Center" FontSize="25"/>
Points of Interest
It is my experience that the universal Windows platform will not allow setting an attached property directly, i.e., you must use a binding. Hence the binding notation above.
History
- 1.0