WPF and initial focus

后端 未结 12 2110
鱼传尺愫
鱼传尺愫 2020-11-29 15:59

It seems that when a WPF application starts, nothing has focus.

This is really weird. Every other framework I\'ve used does just what you\'d expect: puts initial foc

相关标签:
12条回答
  • 2020-11-29 16:27

    This works, too:

    <Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">
    
       <DataGrid x:Name="SomeElement">
         ...
       </DataGrid>
    </Window>
    
    0 讨论(0)
  • 2020-11-29 16:32

    I also faced the same problem. I had three text boxes inside canvas container and wanted the first text box to be focused when the user control opens. WPF code followed MVVM pattern. I created a separate behavior class for focusing the element and binded it to my view like this.

    Canvas behavior code

    public  class CanvasLoadedBehavior : Behavior<Canvas>
    {
        private Canvas _canvas;
        protected override void OnAttached()
        {
            base.OnAttached();
            _canvas = AssociatedObject as Canvas;
            if (_canvas.Name == "ReturnRefundCanvas")
            {
    
                _canvas.Loaded += _canvas_Loaded;
            }
    
    
        }
    
        void _canvas_Loaded(object sender, RoutedEventArgs e)
        {
            FocusNavigationDirection focusDirection = FocusNavigationDirection.Next;
    
            // MoveFocus takes a TraveralReqest as its argument.
            TraversalRequest request = new TraversalRequest(focusDirection);
            UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
            if (elementWithFocus != null)
            {
                elementWithFocus.MoveFocus(request);
            }
    
        }
    
    }
    

    Code for view

    <Canvas  Name="ReturnRefundCanvas" Height="200" Width="1466" DataContext="{Binding RefundSearchViewModel}">
                    <i:Interaction.Behaviors>
                        <b:CanvasLoadedBehavior />
                    </i:Interaction.Behaviors>
                    <uc:Keyboard Canvas.Left="973" Canvas.Top="111" ToolTip="Keyboard" RenderTransformOrigin="-2.795,9.787"></uc:Keyboard>
                    <Label  Style="{StaticResource Devlbl}" Canvas.Left="28" Content="Return and Refund Search" Canvas.Top="10" />
                    <Image Height="30" Width="28" Canvas.Top="6" Canvas.Left="5" Source="pack://application:,,,/HomaKiosk;component/images/searchF.png">
                        <Image.OpacityMask>
                            <ImageBrush ImageSource="pack://application:,,,/HomaKiosk;component/images/searchF.png"/>
                        </Image.OpacityMask>
                    </Image>
    
                    <Separator Height="4" Canvas.Left="6" Margin="0" Canvas.Top="35" Width="1007"/>
    
                    <ContentControl Canvas.Top="45" Canvas.Left="21"
                        ContentTemplate="{StaticResource ErrorMsg}"
                        Visibility="{Binding Error, Converter={c:StringNullOrEmptyToVisibilityConverter}}" 
                        Content="{Binding Error}" Width="992"></ContentControl>
    
                    <Label  Style="{StaticResource Devlbl}" Canvas.Left="29" Name="FirstName" Content="First Name" Canvas.Top="90" />
                    <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" Canvas.Left="33" ToolTip="First Name"  Canvas.Top="120" Width="205"                     Padding="10,5" TabIndex="1001"
                        VerticalAlignment="Top"
    
                        Watermark=""
                        IconPlacement="Left"
                        IconVisibility="Visible"
                        Delay="100"
    
                        Text="{Binding FirstName, Mode=TwoWay, TargetNullValue=''}" 
                        Provider="{Binding FirstNameSuggestions}">
                        <wpf:AutoCompleteTextBox.ItemTemplate>
                            <DataTemplate>
                                <Border Padding="5">
                                    <StackPanel Orientation="Vertical">
                                        <TextBlock Text="{Binding}"
                       FontWeight="Bold" />
                                    </StackPanel>
                                </Border>
                            </DataTemplate>
                        </wpf:AutoCompleteTextBox.ItemTemplate>
                    </wpf:AutoCompleteTextBox>
    
                    <Label Style="{StaticResource Devlbl}" Canvas.Left="250" Content="Last Name" Canvas.Top="90" />
                    <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" ToolTip="Last Name" Canvas.Left="250"  Canvas.Top="120" Width="205" Padding="10,5"  TabIndex="1002"
                        VerticalAlignment="Top"
                        Watermark=""
                        IconPlacement="Left"
                        IconVisibility="Visible"
                        Delay="100"
                       Text="{Binding LastName, Mode=TwoWay, TargetNullValue=''}" 
                        Provider="{Binding LastNameSuggestions}">
                        <wpf:AutoCompleteTextBox.ItemTemplate>
                            <DataTemplate>
                                <Border Padding="5">
                                    <StackPanel Orientation="Vertical">
                                        <TextBlock Text="{Binding}"
                       FontWeight="Bold" />
                                    </StackPanel>
                                </Border>
                            </DataTemplate>
                        </wpf:AutoCompleteTextBox.ItemTemplate>
                    </wpf:AutoCompleteTextBox>
    
                    <Label Style="{StaticResource Devlbl}" Canvas.Left="480" Content="Receipt No" Canvas.Top="90" />
                                 <wpf:AutoCompleteTextBox  Style="{StaticResource AutoComp}" Height="32" ToolTip="Receipt No" Canvas.Left="480"  Canvas.Top="120" Width="205" Padding="10,5"  TabIndex="1002"
                        VerticalAlignment="Top"
                        Watermark=""
                        IconPlacement="Left"
                        IconVisibility="Visible"
                        Delay="100"
                        Text="{Binding ReceiptNo, Mode=TwoWay, TargetNullValue=''}" 
                        Provider="{Binding ReceiptIdSuggestions}">
                        <wpf:AutoCompleteTextBox.ItemTemplate>
                            <DataTemplate>
                                <Border Padding="5">
                                    <StackPanel Orientation="Vertical" >
                                        <TextBlock Text="{Binding}"
                       FontWeight="Bold">
    
                                        </TextBlock>
                                    </StackPanel>
                                </Border>
                            </DataTemplate>
                        </wpf:AutoCompleteTextBox.ItemTemplate>
                        <i:Interaction.Behaviors>
                            <b:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]+$" MaxLength="15" />
                        </i:Interaction.Behaviors>
                    </wpf:AutoCompleteTextBox>
                    <!--<Label Style="{StaticResource Devlbl}" Canvas.Left="710" Content="Duration" Canvas.Top="79" />-->
                    <!--<ComboBox AllowDrop="True" Canvas.Left="710" ToolTip="Duration" Canvas.Top="107" Width="205" TabIndex="1004"
                        Style="{StaticResource CommonComboBox}"      
                        ItemsSource="{Binding Durations}" DisplayMemberPath="Description" SelectedValuePath="Id" SelectedValue="{Binding SelectedDate, Mode=TwoWay}">
    
                    </ComboBox>-->
    
                    <Button Content="Search" Style="{StaticResource MyButton}" ToolTip="Search" 
                        Canvas.Top="116" Canvas.Left="710" Cursor="Hand" 
                        Command="{Binding SearchCommand}" TabIndex="2001">
                    </Button>
                    <Button Content="Clear" Style="{StaticResource MyButton}"  ToolTip="Clear"
                        Canvas.Top="116" Canvas.Left="840" Cursor="Hand" 
                        Command="{Binding ClearCommand}" TabIndex="2002">
                    </Button>
                    <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="25" Source="pack://application:,,,/HomaKiosk;component/images/chkpending.png"/>
                    <Label  Style="{StaticResource LegendLbl}" Canvas.Left="50" Content="Check Returned and Payment Pending" Canvas.Top="178" />
                    <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="300" Source="pack://application:,,,/HomaKiosk;component/images/chkrepaid.png"/>
                    <Label  Style="{StaticResource LegendLbl}" Canvas.Left="325" Content="Repaid" Canvas.Top="178" />
                    <Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="395" Source="pack://application:,,,/HomaKiosk;component/images/refund.png"/>
                    <Label  Style="{StaticResource LegendLbl}" Canvas.Left="415" Content="Refunded" Canvas.Top="178" />
                     </Canvas>
    
    0 讨论(0)
  • 2020-11-29 16:34

    Above solution was not working as expected for me, I've changed slightly the behavior proposed by Mizipzor as following:

    From this part

    if ((bool)args.NewValue)
            {
                control.Loaded += (sender, e) =>
                       control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }
    

    To this

    if ((bool)args.NewValue)
            {
                control.Loaded += (sender, e) => control.Focus();
            }
    

    ANd I'm not attaching this behavior to Window or UserControl, but to control I want to focus initially, e.g.:

    <TextBox ui:FocusBehavior.InitialFocus="True" />
    

    Oh, sorry for different naming I'm using InitialFocus name for the attached property.

    And this is working for me, maybe it could help someone else.

    0 讨论(0)
  • 2020-11-29 16:38

    After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.

    First, add your App.xaml OnStartup() the followings:

    EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
              new RoutedEventHandler(WindowLoaded));
    

    Then add the 'WindowLoaded' event also in App.xaml :

    void WindowLoaded(object sender, RoutedEventArgs e)
        {
            var window = e.Source as Window;
            System.Threading.Thread.Sleep(100);
            window.Dispatcher.Invoke(
            new Action(() =>
            {
                window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
    
            }));
        }
    

    The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.

    I found the following solution best as it is used globally for the whole app.

    Hope it helps...

    Oran

    0 讨论(0)
  • A minimal version of Mizipzor's answer for C# 6+.

    public static class FocusBehavior
    {
        public static readonly DependencyProperty GiveInitialFocusProperty =
            DependencyProperty.RegisterAttached(
                "GiveInitialFocus",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, OnFocusFirstPropertyChanged));
    
        public static bool GetGiveInitialFocus(Control control) => (bool)control.GetValue(GiveInitialFocusProperty);
        public static void SetGiveInitialFocus(Control control, bool value) => control.SetValue(GiveInitialFocusProperty, value);
    
        private static void OnFocusFirstPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            var control = obj as Control;
    
            if (control == null || !(args.NewValue is bool))
                return;
    
            if ((bool)args.NewValue)
                control.Loaded += OnControlLoaded;
            else
                control.Loaded -= OnControlLoaded;
        }
    
        private static void OnControlLoaded(object sender, RoutedEventArgs e) => ((Control)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    }
    

    Use in your XAML:

    <Window local:FocusBehavior.GiveInitialFocus="True" />
    
    0 讨论(0)
  • 2020-11-29 16:44

    Had same problem solved it with simple solution: In the main window:

      <Window ....
            FocusManager.FocusedElement="{Binding ElementName=usercontrolelementname}"
             ... />
    

    In the user control:

    private void UserControl_GotFocus_1(object sender, RoutedEventArgs e)
            {
                targetcontrol.Focus();
                this.GotFocus -= UserControl_GotFocus_1;  // to set focus only once
            }
    
    0 讨论(0)
提交回复
热议问题