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.

有帮助吗?

解决方案

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.

其他提示

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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top