Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top