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.
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.
public static void OnIsFocusedChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
if (s is TextBox)
{
TextBox t = s as TextBox;
if ((bool)e.NewValue)
{
t.Focus(FocusState.Pointer);
t.LostFocus += textbox_LostFocus;
}
else
{
t.LostFocus -= textbox_LostFocus;
}
}
}
Inside the LostFocus
event, the property is reset.
private static void textbox_LostFocus(object sender, RoutedEventArgs e)
{
TextBox t = sender as TextBox;
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)
{
TextBox t = d as TextBox;
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())
{
e.Handled = true;
ICommand command = GetCommand(t);
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