none
MVVM - View - KeyboardFocus auf Textbox innerhalb eines Popup´s RRS feed

  • Frage

  • Hallo Miteinander,

    im Netz finde ich hierfür keine funktionsfähige Demo.

    Ich blende über mein ViewModel ein Popup ein. Anschließend soll die Textbox den Keyboardfocus erhalten. Da dort Eingaben über einen Handscanner getätigt werden sollen. Kann man das direkt über die .xaml lösen ohne, dass ich im Codebehind arbeiten muss?

            <Popup Placement="Center" AllowsTransparency="True" IsOpen="{Binding IsPopupBarcodeScanVisible}">
                <Border BorderBrush="Black" BorderThickness="2">
                    <StackPanel>
                        <TextBlock Text="Barcode einlesen:" FontSize="50" FontWeight="ExtraBold" HorizontalAlignment="Center" Background="AntiqueWhite"/>
                        <StackPanel>
                            <TextBox x:Name="tbBarcode" Text="{Binding TextBarcodeScan}" MinHeight="50"></TextBox>
                        </StackPanel>
                    </StackPanel>
                </Border>
            </Popup>

    Ich danke Euch!
    Gruß Martin

    Donnerstag, 28. Februar 2019 11:11

Antworten

  • Hi Martin,
    hier mal eine kleine Demo:

    XAML:

    <Window x:Class="WpfApp1.Window02"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="Window02" Height="450" Width="800">
      <Window.Resources>
        <local:Window02VM x:Key="vm"/>
      </Window.Resources>
      <StackPanel DataContext="{StaticResource vm}">
        <Button Content="PopUp" Command="{Binding Cmd}"/>
        <Popup Placement="Center" AllowsTransparency="True" IsOpen="{Binding IsPopupBarcodeScanVisible}">
          <Border BorderBrush="Black" BorderThickness="2">
            <StackPanel>
              <TextBlock Text="Barcode einlesen:" FontSize="50" FontWeight="ExtraBold" HorizontalAlignment="Center" Background="AntiqueWhite"/>
              <StackPanel>
                <TextBox x:Name="tbBarcode" Text="{Binding TextBarcodeScan}" MinHeight="50">
                  <i:Interaction.Behaviors>
                    <local:Window02TextBoxBehavior SetFocus="{Binding IsPopupBarcodeScanVisible}"/>
                  </i:Interaction.Behaviors>
                </TextBox>
              </StackPanel>
            </StackPanel>
          </Border>
        </Popup>
      </StackPanel>
    </Window>

    Und dazu ViewModel und Behavior:

    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Interactivity;
    
    namespace WpfApp1
    {
    
      public class Window02VM : INotifyPropertyChanged
      {
    
        public ICommand Cmd { get { return new RelayCommand<object>((state) => IsPopupBarcodeScanVisible = !IsPopupBarcodeScanVisible); } }
    
        private bool _isPopupBarcodeScanVisible = false;
        public bool IsPopupBarcodeScanVisible
        {
          get { return _isPopupBarcodeScanVisible; }
          set
          {
            _isPopupBarcodeScanVisible = value;
            OnPropertyChanged(); // der Oberfläche melden, dass ggf. anderer Nachschlagewert 
          }
        }
    
        #region  OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion
    
      }
    
      public class Window02TextBoxBehavior : Behavior<TextBox>
      {
        public static readonly DependencyProperty SetFocusProperty =
           DependencyProperty.RegisterAttached("SetFocus",
           typeof(bool),
           typeof(Window02TextBoxBehavior),
           new UIPropertyMetadata(false, OnSetFocusPropertyChanged));
    
        //public static void SetGetFocus(DependencyObject obj, Window02TextBoxBehavior value) { obj.SetValue(SetFocusProperty, value); }
    
        public static bool GetSetFocus(DependencyObject obj) { return (bool)(obj.GetValue(SetFocusProperty)); }
        public static void SetSetFocus(DependencyObject obj, Window02TextBoxBehavior value) { obj.SetValue(SetFocusProperty, value); }
    
        private static void OnSetFocusPropertyChanged(object d, DependencyPropertyChangedEventArgs e)
        {
          Window02TextBoxBehavior beh = d as Window02TextBoxBehavior;
          if (beh == null) return;
          if (e.NewValue is bool && (bool)e.NewValue) beh.SetTextBoxFocus();
        }
    
        private void SetTextBoxFocus() => AssociatedObject.Focus();
      }
    
    }


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    • Als Antwort vorgeschlagen Peter Fleischer Donnerstag, 28. Februar 2019 12:31
    • Als Antwort markiert mApO18 Donnerstag, 28. Februar 2019 12:54
    Donnerstag, 28. Februar 2019 12:31

Alle Antworten

  • Hi Martin,
    mit System.Windows.Interactivity kannst Du das auch problemlos in MVVM realisieren. Die Idee dahinter ist, dass Du eine Klasse von Behavior erbst, darin eine DependencyProperty einbaust, die für eine Bindung genutzt wird, über die ein PropertyChanged signalisiert, dass der Focus zu setzen ist. Den Focus setzt Du in der Behavior-Klasse.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Donnerstag, 28. Februar 2019 11:16
  • Hi Peter,

    danke für die schnelle Antwort.

    Ich würde mich wie folgt nähern:

    public class PopupBehavior : Behavior<Popup> {

    // ?         DependencyProperty() }


            <Popup Placement="Center" AllowsTransparency="True" IsOpen="{Binding IsPopupBarcodeScanVisible}">
                <i:Interaction.Behaviors>
                    <local:PopupBehavior/>
                </i:Interaction.Behaviors>
                <Border BorderBrush="Black" BorderThickness="2">
                    <StackPanel>
                        <TextBlock Text="Barcode einlesen:" FontSize="50" FontWeight="ExtraBold" HorizontalAlignment="Center" Background="AntiqueWhite"/>
                        <StackPanel>
                            <TextBox x:Name="tbBarcode" Text="{Binding TextBarcodeScan}" MinHeight="50"></TextBox>
                        </StackPanel>
                    </StackPanel>
                </Border>
            </Popup>
    

    Leider fehlt mir der Rest für die Realisierung. Vielleicht kannst du mir eine kleine Demo geben?

    Danke dir.


    Donnerstag, 28. Februar 2019 11:31
  • Hi Martin,
    hier mal eine kleine Demo:

    XAML:

    <Window x:Class="WpfApp1.Window02"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="Window02" Height="450" Width="800">
      <Window.Resources>
        <local:Window02VM x:Key="vm"/>
      </Window.Resources>
      <StackPanel DataContext="{StaticResource vm}">
        <Button Content="PopUp" Command="{Binding Cmd}"/>
        <Popup Placement="Center" AllowsTransparency="True" IsOpen="{Binding IsPopupBarcodeScanVisible}">
          <Border BorderBrush="Black" BorderThickness="2">
            <StackPanel>
              <TextBlock Text="Barcode einlesen:" FontSize="50" FontWeight="ExtraBold" HorizontalAlignment="Center" Background="AntiqueWhite"/>
              <StackPanel>
                <TextBox x:Name="tbBarcode" Text="{Binding TextBarcodeScan}" MinHeight="50">
                  <i:Interaction.Behaviors>
                    <local:Window02TextBoxBehavior SetFocus="{Binding IsPopupBarcodeScanVisible}"/>
                  </i:Interaction.Behaviors>
                </TextBox>
              </StackPanel>
            </StackPanel>
          </Border>
        </Popup>
      </StackPanel>
    </Window>

    Und dazu ViewModel und Behavior:

    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Interactivity;
    
    namespace WpfApp1
    {
    
      public class Window02VM : INotifyPropertyChanged
      {
    
        public ICommand Cmd { get { return new RelayCommand<object>((state) => IsPopupBarcodeScanVisible = !IsPopupBarcodeScanVisible); } }
    
        private bool _isPopupBarcodeScanVisible = false;
        public bool IsPopupBarcodeScanVisible
        {
          get { return _isPopupBarcodeScanVisible; }
          set
          {
            _isPopupBarcodeScanVisible = value;
            OnPropertyChanged(); // der Oberfläche melden, dass ggf. anderer Nachschlagewert 
          }
        }
    
        #region  OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion
    
      }
    
      public class Window02TextBoxBehavior : Behavior<TextBox>
      {
        public static readonly DependencyProperty SetFocusProperty =
           DependencyProperty.RegisterAttached("SetFocus",
           typeof(bool),
           typeof(Window02TextBoxBehavior),
           new UIPropertyMetadata(false, OnSetFocusPropertyChanged));
    
        //public static void SetGetFocus(DependencyObject obj, Window02TextBoxBehavior value) { obj.SetValue(SetFocusProperty, value); }
    
        public static bool GetSetFocus(DependencyObject obj) { return (bool)(obj.GetValue(SetFocusProperty)); }
        public static void SetSetFocus(DependencyObject obj, Window02TextBoxBehavior value) { obj.SetValue(SetFocusProperty, value); }
    
        private static void OnSetFocusPropertyChanged(object d, DependencyPropertyChangedEventArgs e)
        {
          Window02TextBoxBehavior beh = d as Window02TextBoxBehavior;
          if (beh == null) return;
          if (e.NewValue is bool && (bool)e.NewValue) beh.SetTextBoxFocus();
        }
    
        private void SetTextBoxFocus() => AssociatedObject.Focus();
      }
    
    }


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    • Als Antwort vorgeschlagen Peter Fleischer Donnerstag, 28. Februar 2019 12:31
    • Als Antwort markiert mApO18 Donnerstag, 28. Februar 2019 12:54
    Donnerstag, 28. Februar 2019 12:31