WPF 在运行时设置键盘焦点而不需要代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15200793/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 07:50:39  来源:igfitidea点击:

WPF setting keyboard-focus without code behind at runtime

wpfxamlmvvm

提问by Tobias Hoefer

I searched a lot on that topic but couldnt really find a solution for this using no code behind. I know some would say using code-behind for this view related things is totally ok, but nevertheless i would like to avoid it.

我在该主题上进行了大量搜索,但无法真正找到不使用任何代码的解决方案。我知道有些人会说对这个与视图相关的事情使用代码隐藏是完全可以的,但我还是想避免它。

I have a usercontrol which shows a "dialog" with a single textbox and an OK button. That dialog is a simple usercontrol that is placed on top of all others. By default the usercontrols visibility is set to collapsed. I would like to set the keyboardfocus to the textbox on the dialog usercontrol if the usercontrol gets visible. Is there any way to do this completely in xaml? Since my dialog-control is not visible at the time when the control is loaded, simply setting

我有一个用户控件,它显示一个带有单个文本框和一个确定按钮的“对话框”。该对话框是一个简单的用户控件,位于所有其他控件之上。默认情况下,用户控件可见性设置为折叠。如果用户控件可见,我想将键盘焦点设置为对话框用户控件上的文本框。有没有办法在 xaml 中完全做到这一点?由于我的对话框控件在加载控件时不可见,只需设置

FocusManager.FocusedElement="{Binding ElementName=tbID}"

FocusManager.FocusedElement="{Binding ElementName=tbID}"

will not work. I tried to use some kind of visibility trigger:

不管用。我尝试使用某种可见性触发器:

   <TextBox Grid.Column="3"
             Grid.Row="5"
             Name="tbID"
             VerticalAlignment="Center">
        <TextBox.Style>
            <Style TargetType="{x:Type TextBox}">
                <Style.Triggers>
                    <Trigger Property="Visibility" Value="Visible">
                        <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=tbID}" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>

but this doesnt work either. The trigger gets fired but the textbox doesnt get the focus. I would really appreciate any suggestions on that. Thanks in advance!

但这也不起作用。触发器被触发但文本框没有获得焦点。我真的很感激任何关于这方面的建议。提前致谢!

回答by Brandon Baker

You could try using an attached behavior to set the focus. Here's some sample code:

您可以尝试使用附加行为来设置焦点。这是一些示例代码:

public static class Focus
{
    public static readonly DependencyProperty ShouldFocusWhenVisibleProperty =
        DependencyProperty.RegisterAttached("ShouldFocusWhenVisible", typeof (bool), typeof (Focus), new PropertyMetadata(default(bool), ShouldFocusWhenVisibleChanged));

    private static void ShouldFocusWhenVisibleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var uiElement = sender as UIElement;
        if (uiElement == null) return;

        var shouldFocus = GetShouldFocusWhenVisible(uiElement);
        if (shouldFocus)
        {
            UpdateFocus(uiElement);
            uiElement.IsVisibleChanged += UiElementOnIsVisibleChanged;
        }
        else
            uiElement.IsVisibleChanged -= UiElementOnIsVisibleChanged;
    }

    private static void UiElementOnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var uiElement = sender as UIElement;
        if (uiElement == null) return;

        UpdateFocus(uiElement);
    }

    private static void UpdateFocus(UIElement uiElement)
    {
        if (!uiElement.IsVisible) return;

        Keyboard.PrimaryDevice.Focus(uiElement);
    }

    public static void SetShouldFocusWhenVisible(UIElement uiElement, bool value)
    {
        uiElement.SetValue(ShouldFocusWhenVisibleProperty, value);
    }

    public static bool GetShouldFocusWhenVisible(UIElement uiElement)
    {
        return (bool)uiElement.GetValue(ShouldFocusWhenVisibleProperty);
    }
}

Then, you apply the following code to the TextBox in your dialog: <TextBox local:Focus.ShouldFocusWhenVisible="True" />. Note that local:will need to be a reference to the namespace of the Focus class above.

然后,将以下代码应用于对话框中的 TextBox:<TextBox local:Focus.ShouldFocusWhenVisible="True" />. 请注意,local:需要引用上面的 Focus 类的命名空间。

回答by sa_ddam213

I think you want to bind to the UserControlVisibilityproperty not the TextBox

我认为你想绑定到UserControlVisibility属性而不是TextBox

Example

例子

<UserControl x:Class="WpfApplication7.IconButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="100" d:DesignWidth="200" Name="_this">
    <Grid>
        <TextBox Name="tbID" Margin="0,12,0,0" VerticalAlignment="Top">
            <TextBox.Style>
                <Style TargetType="{x:Type TextBox}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding ElementName=_this, Path=Visibility}" Value="Visible">
                            <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=tbID}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBox.Style>
        </TextBox>
    </Grid>
</UserControl>