Reputation: 50657
From post WPF: How to programmatically remove focus from a TextBox, I know how to set a TextBox
's focus back to its parent using the following code:
// Move to a parent that can take focus
FrameworkElement parent = (FrameworkElement)textBox.Parent;
while (parent != null && parent is IInputElement
&& !((IInputElement)parent).Focusable)
{
parent = (FrameworkElement)parent.Parent;
}
DependencyObject scope = FocusManager.GetFocusScope(textBox);
FocusManager.SetFocusedElement(scope, parent as IInputElement);
Is there any way to generalize this code (like template functions) to make it also work for other items like ComboBox
, Canvas
, Image
etc.
Upvotes: 3
Views: 7243
Reputation: 22702
Yes, there is such a possibility, in such cases, implement attached
behavior. Logic at work with a focus must fit into DependencyPropertyChangedEvent
handler.
Here is an example for your case:
XAML
<Window x:Class="RemoveFocusHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:this="clr-namespace:RemoveFocusHelp"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Name="TestTextBox"
this:RemoveFocusBehavior.IsRemoveFocus="False"
Width="100"
Height="25"
Text="TestText" />
<Button Name="CreateFocus"
Width="100"
Height="30"
Content="Create Focus"
HorizontalAlignment="Left"
Click="CreateFocus_Click" />
<Button Name="RemoveFocus"
Focusable="False"
Width="100"
Height="30"
Content="Remove Focus"
HorizontalAlignment="Right"
Click="RemoveFocus_Click" />
</Grid>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void CreateFocus_Click(object sender, RoutedEventArgs e)
{
TestTextBox.Focus();
}
private void RemoveFocus_Click(object sender, RoutedEventArgs e)
{
RemoveFocusBehavior.SetIsRemoveFocus(TestTextBox, true);
}
}
public class RemoveFocusBehavior
{
#region IsRemoveFocus Dependency Property
public static readonly DependencyProperty IsRemoveFocusProperty;
public static void SetIsRemoveFocus(DependencyObject DepObject, bool value)
{
DepObject.SetValue(IsRemoveFocusProperty, value);
}
public static bool GetIsRemoveFocus(DependencyObject DepObject)
{
return (bool)DepObject.GetValue(IsRemoveFocusProperty);
}
static RemoveFocusBehavior()
{
IsRemoveFocusProperty = DependencyProperty.RegisterAttached("IsRemoveFocus",
typeof(bool),
typeof(RemoveFocusBehavior),
new UIPropertyMetadata(false, IsRemoveFocusTurn));
}
#endregion
#region IsRemoveFocus Property Metadata
private static void IsRemoveFocusTurn(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
Control control = sender as Control;
if (control == null)
{
return;
}
if (e.NewValue is bool && ((bool)e.NewValue) == true)
{
FrameworkElement parent = (FrameworkElement)control.Parent;
while (parent != null && parent is IInputElement
&& !((IInputElement)parent).Focusable)
{
parent = (FrameworkElement)parent.Parent;
}
DependencyObject scope = FocusManager.GetFocusScope(control);
FocusManager.SetFocusedElement(scope, parent as IInputElement);
}
}
#endregion
}
Project is available at this
link
.
Upvotes: 2
Reputation: 446
It should be relatively straightforward:
FrameworkElement ctrl = control; //or whatever you're passing in, since all controls are FrameworkElements.
// Move to a parent that can take focus
FrameworkElement parent = (FrameworkElement)ctrl.Parent;
while (parent != null && parent is IInputElement
&& !((IInputElement)parent).Focusable)
{
parent = (FrameworkElement)parent.Parent;
}
DependencyObject scope = FocusManager.GetFocusScope(ctrl); //can pass in ctrl here because FrameworkElement inherits from DependencyObject
FocusManager.SetFocusedElement(scope, parent as IInputElement);
This works because all controls inherit from FrameworkElement which inherits from DependencyObject. So you can set ctrl
to any type of control you want: ComboBox
, TextBox
, Button
, Canvas
, etc.
Upvotes: 3