在样式触发器中为TextBox设置焦点

时间:2014-04-04 02:44:51

标签: wpf xaml textbox popup focus

我有以下但触发器无效。它应该将光标放在准备输入的TextBox中。

请有人指出我正确的方向。

<Popup Name="PopupGoto" Placement="Mouse" StaysOpen="False" 
       IsOpen="{Binding Path=GotoPopupIsOpen, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">

    <Popup.Style>
        <Style TargetType="Popup">
            <Style.Triggers>
                <Trigger Property="IsOpen" Value="True">
                    <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=GotoTextbox}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Popup.Style>

    <Border>
        <Grid>
            <TextBox x:Name="GotoTextbox" Text="{Binding GotoLineNumber}" />
            <Button Content="Goto" Command="{Binding GotoCommand}" />
        </Grid>
    </Border>
</Popup>

2 个答案:

答案 0 :(得分:6)

FocusManager.FocusedElement为元素建立了逻辑焦点:

  

确定附加此属性的元素是否具有逻辑焦点。

这是什么意思?这意味着,在WPF中有两个与焦点相关的主要概念:键盘焦点和逻辑焦点[MSDN]。以下是一个例子:

<TextBox Name="GotoTextbox" 
         Text="TestText"
         Keyboard.GotKeyboardFocus="GotoTextbox_GotKeyboardFocus" 
         FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Mode=Self}}" />

在这种情况下,我们设置逻辑焦点,但是当你打开Popup时,光标会被渲染,我们无法打印文本(我建议你自己检查)。这也可以使用事件处理程序Keyboard.GotKeyboardFocus检查:

private void GotoTextbox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    MessageBox.Show("Give focus!");
}

当您Popup打开时,MessageBox不会出现,当您按下键盘上的按键时会出现窗口。

对于所有正常工作,需要设置键盘焦点,它还调用物理焦点。我在Style.Triggers中看到过很多关于设置Focus to TextBox的例子,但对我来说,由于可以理解的原因,它们并不起作用。

我可以建议的唯一解决方案是使用附加行为,它非常适合MVVM的风格。

<强> FocusBehavior

public static class FocusBehavior
{
    public static readonly DependencyProperty IsFocusProperty;

    public static void SetIsFocus(DependencyObject DepObject, bool value)
    {
        DepObject.SetValue(IsFocusProperty, value);
    }

    public static bool GetIsFocus(DependencyObject DepObject)
    {
        return (bool)DepObject.GetValue(IsFocusProperty);
    }

    static FocusBehavior()
    {
        IsFocusProperty = DependencyProperty.RegisterAttached("IsFocus",
                                                              typeof(bool),
                                                              typeof(FocusBehavior),
                                                              new UIPropertyMetadata(false, IsFocusTurn));
    }

    private static void IsFocusTurn(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var element = sender as Control;

        if (element != null)
        {
            if (e.NewValue is bool && (bool)e.NewValue == true)
            {
                element.Loaded += ElementLoaded;
            }
        }
    }

    private static void ElementLoaded(object sender, RoutedEventArgs e)
    {
        var control = sender as Control;

        if (control != null) 
        {
            if (control is TextBox)
            {
                Keyboard.Focus(control);
            }
            else
            {
                control.Focus();
            }
        }            
    }
}

这里我们为Control设置Loaded事件处理程序,并将焦点设置为元素。使用此行为的示例:

<Grid>
    <ToggleButton Name="OpenButton"                      
                  Content="Open" 
                  Width="100"
                  Height="30" />

    <Popup Name="PopupGoto"
           StaysOpen="False" 
           PlacementTarget="{Binding ElementName=OpenButton}"
           IsOpen="{Binding Path=IsChecked, ElementName=OpenButton}">           

        <Border>
            <StackPanel>
                <TextBox x:Name="GotoTextbox" 
                         this:FocusBehavior.IsFocus="True"
                         Text="TestText" />

                <Button Content="Goto" />
            </StackPanel>
        </Border>
    </Popup>
</Grid>

答案 1 :(得分:1)

您的代码几乎正确无误。只需将Setter.TargetName设置为与Value绑定相同,一切都会正常工作。

<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=GotoTextbox}" ElementName="GotoTextbox" />