0

I would like to show/activate a hidden window and set the (keyboard-)focus to a textbox programmatically (without violating mvvm if possible).

So if the the user presses a hotkey (already implemented) following should happen:

  • Window gets shown + activated
  • Textbox gets focused + keyboard focus (so the user can type some text)

Pressing the hotkey again should hide the window.

I tried binding Activated and Visibility to a boolean value, but I ran into some problems with TwoWay-Binding. Thank you for any ideas on how to solve this problem.

Edit:

MainWindow.xml:

    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
    </Window.Resources>

    <i:Interaction.Behaviors>
        <bh:ActivateBehavior Activated="{Binding Visible, Mode=TwoWay}"/>
    </i:Interaction.Behaviors>

    <Window.Visibility>
        <Binding Path="Visible" Mode="TwoWay" Converter="{StaticResource BoolToVisConverter}"/>
    </Window.Visibility>
    
    <TextBox Grid.Column="1" x:Name="SearchBar" bh:FocusExtension.IsFocused="{Binding Visible, Mode=TwoWay}"/>

ActivateBehavior.cs: used from this https://stackoverflow.com/a/12254217/13215602

public class ActivateBehavior : Behavior<Window> {

  Boolean isActivated;

  public static readonly DependencyProperty ActivatedProperty =
    DependencyProperty.Register(
      "Activated",
      typeof(Boolean),
      typeof(ActivateBehavior),
      new PropertyMetadata(OnActivatedChanged)
    );

  public Boolean Activated {
    get { return (Boolean) GetValue(ActivatedProperty); }
    set { SetValue(ActivatedProperty, value); }
  }

  static void OnActivatedChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) {
    var behavior = (ActivateBehavior) dependencyObject;
    if (!behavior.Activated || behavior.isActivated)
      return;
    // The Activated property is set to true but the Activated event (tracked by the
    // isActivated field) hasn't been fired. Go ahead and activate the window.
    if (behavior.AssociatedObject.WindowState == WindowState.Minimized)
      behavior.AssociatedObject.WindowState = WindowState.Normal;
    behavior.AssociatedObject.Activate();
  }

  protected override void OnAttached() {
    AssociatedObject.Activated += OnActivated;
    AssociatedObject.Deactivated += OnDeactivated;
  }

  protected override void OnDetaching() {
    AssociatedObject.Activated -= OnActivated;
    AssociatedObject.Deactivated -= OnDeactivated;
  }

  void OnActivated(Object sender, EventArgs eventArgs) {
    this.isActivated = true;
    Activated = true;
  }

  void OnDeactivated(Object sender, EventArgs eventArgs) {
    this.isActivated = false;
    Activated = false;
  }

}

FocusExtension.cs: used from this https://stackoverflow.com/a/1356781/13215602

    public static class FocusExtension
    {
        public static bool GetIsFocuses(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsFocusedProperty);
        }

        public static void SetIsFocused(DependencyObject obj, bool value)
        {
            obj.SetValue(IsFocusedProperty, value);
        }

        public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.RegisterAttached("IsFocused", typeof(bool), typeof(FocusExtension),
                new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));

        private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var uie = (UIElement) d;
            if ((bool) e.NewValue)
            {
                Keyboard.Focus(uie);
                uie.Focus();
            }
        }
    }

MainViewModel.cs:

        private bool mVisible;

        //Binding to this variable
        public bool Visible
        {
            get { return mVisible; }
            set
            {
                if (mVisible == value)
                    return;

                mVisible = value;
                RaisePropertyChanged(nameof(Visible));
            }
        }
TheGoobsy
  • 75
  • 1
  • 6
  • private void OnLoaded(object sender, RoutedEventArgs e) { // Sets keyboard focus on the first Button in the sample. Keyboard.Focus(firstButton); } – RoXTar Aug 16 '20 at 12:35
  • Provide from your Code, so we can improve. – RoXTar Aug 16 '20 at 12:37
  • Thank you for your quick response, I've now edited my question so you can have a look at my code. – TheGoobsy Aug 16 '20 at 17:04
  • This looks good. What is with setting visiblity property in your keycommand, is it visible? I don't see your key handling? My fault? Normaly you set your propertys (visible and focus) there. Do you have defined propertys for your textbox in mainmodel? – RoXTar Aug 16 '20 at 17:25
  • I do key handling like this https://stackoverflow.com/a/9330358/13215602, because the user should be able to use the hotkey also outside of the application) Then I just toggle the Visible property. I am not sure but I think that you can't really "deactivate" a window, so if I set the property to false it kinda conflicts with the the other TwoWay-bindings. I've tested with different properties for each Activated and Window.Visible so they don't conflict, which works for now. I am still trying to find a better solution and I am going to update you with the final methods I used. Thank you! – TheGoobsy Aug 16 '20 at 18:47
  • Visible property is the right way, it is no deactivate – RoXTar Aug 16 '20 at 19:02
  • Ok with this keyhandling you can set the relevant properties in your mainviewmodel, (visible and focusses) what wrong with that? Your propertys rise the relevant propertychanged and good. – RoXTar Aug 16 '20 at 19:07
  • 1
    I think you overloaded all a bit. You need to have properties for focus and visiblity (as in your code) and set the propertys in your keyhandler. This should so the Magic. – RoXTar Aug 16 '20 at 19:29
  • 1
    Yes you were right. Focus and visibility is enough. Thank you! – TheGoobsy Aug 20 '20 at 15:14
  • Glad i could help. – RoXTar Aug 20 '20 at 16:10

0 Answers0