Question

I have the following but the Trigger is not working. It is supposed to place cursor in the TextBox ready to type.

Can someone point me in the right direction please.

<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>
Was it helpful?

Solution

The FocusManager.FocusedElement establishes a logical focus for the element:

Determines whether the element this property is attached to has logical focus.

And what does it mean? This means, that in WPF there are two main concepts that pertain to focus: keyboard focus and logical focus [MSDN]. Below is an example:

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

In this case, we set logical focus, but when you open Popup the cursor rendered and we can not print text (I advise to check yourself). This can also be checked using an event handler Keyboard.GotKeyboardFocus:

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

When your Popup open, the MessageBox does not appear, the Window appears when you press keys on the keyboard.

To all the worked as as it should, need to set the keyboard focus, it also calls the the physical focus. I have seen many examples of set Focus to TextBox in Style.Triggers, but for me they did not work for understandable reasons.

The only solution that I can suggest - is to use an attached behavior, it is perfectly suited to the style of 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();
            }
        }            
    }
}

Here we set the Loaded event handler for Control, and it sets the focus to the element. Example of using this Behavior:

<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>

OTHER TIPS

Your code almost correct. Just set Setter.TargetName the same as in Value binding and everything will work fine.

<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=GotoTextbox}" ElementName="GotoTextbox" />
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top