首页 文章

WPF和最初的焦点

提问于
浏览
167

似乎当WPF应用程序启动时,没有任何焦点 .

这真的很奇怪 . 我使用过的每个其他框架都符合您的期望:将初始重点放在Tab键顺序中的第一个控件上 . 但我已经确认它是WPF,而不仅仅是我的应用程序 - 如果我创建一个新窗口,只是在其中放置一个TextBox,并运行应用程序,TextBox没有焦点,直到我点击它或按Tab键 . 呸 .

我的实际应用程序比TextBox更复杂 . 我在UserControls中有几层UserControl . 其中一个UserControls有Focusable =“True”和KeyDown / KeyUp处理程序,我希望它在我的窗口打开后立即获得焦点 . 不过,我仍然有点像WPF新手,而且我没有太多运气搞清楚如何做到这一点 .

如果我启动我的应用程序并按Tab键,则焦点转到我的可聚焦控件,它开始以我想要的方式工作 . 但是我不希望我的用户在开始使用窗口之前必须点击Tab .

我玩过FocusManager.FocusedElement,但是我不确定将它设置为哪个控件(顶级窗口?包含可聚焦控件的父级?可聚焦控件本身?)或者设置它的内容 .

一旦窗口打开,我需要做什么才能使我的深层嵌套控件具有初始焦点?或者更好的是,将第一个可聚焦控件聚焦在Tab键顺序中?

12 回答

  • 14

    您可以轻松地将控件设置为XAML中的焦点元素 .

    <Window>
       <DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
         ...
       </DataGrid>
    </Window>
    

    我从来没有尝试在用户控件中设置它,看看它是否有效,但它可能 .

  • 54

    以上解决方案对我来说没有按预期工作,我稍微改变了Mizipzor提出的行为如下:

    从这一部分

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

    对此

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

    我没有将此行为附加到Window或UserControl,但控制我想最初聚焦,例如:

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

    哦,抱歉不同的命名我正在使用附加属性的InitialFocus名称 .

    这对我有用,也许它可以帮助别人 .

  • 1
    <Window FocusManager.FocusedElement="{Binding ElementName=yourControlName}">
    
  • 0

    基于接受的answer实现为附加行为:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace UI.Behaviors
    {
        public static class FocusBehavior
        {
            public static readonly DependencyProperty FocusFirstProperty =
                DependencyProperty.RegisterAttached(
                    "FocusFirst",
                    typeof(bool),
                    typeof(FocusBehavior),
                    new PropertyMetadata(false, OnFocusFirstPropertyChanged));
    
            public static bool GetFocusFirst(Control control)
            {
                return (bool)control.GetValue(FocusFirstProperty);
            }
    
            public static void SetFocusFirst (Control control, bool value)
            {
                control.SetValue(FocusFirstProperty, value);
            }
    
            static void OnFocusFirstPropertyChanged(
                DependencyObject obj, DependencyPropertyChangedEventArgs args)
            {
                Control control = obj as Control;
                if (control == null || !(args.NewValue is bool))
                {
                    return;
                }
    
                if ((bool)args.NewValue)
                {
                    control.Loaded += (sender, e) =>
                        control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
                }
            }
        }
    }
    

    像这样用它:

    <Window xmlns:Behaviors="clr-namespace:UI.Behaviors"
            Behaviors:FocusBehavior.FocusFirst="true">
    
  • 135

    我发现了另一种可能的解Mark Smith发布了一个FirstFocusedElement markup extension用于FocusManager.FocusedElement .

    <UserControl x:Class="FocusTest.Page2"
        xmlns:FocusTest="clr-namespace:FocusTest"
        FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">
    
  • 8

    有同样的问题通过简单的解决方案解决了它:在主窗口中:

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

    在用户控件中:

    private void UserControl_GotFocus_1(object sender, RoutedEventArgs e)
            {
                targetcontrol.Focus();
                this.GotFocus -= UserControl_GotFocus_1;  // to set focus only once
            }
    
  • -1

    C#6的最小版本Mizipzor's answer .

    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));
    }
    

    在XAML中使用:

    <Window local:FocusBehavior.GiveInitialFocus="True" />
    
  • 8

    我有一个聪明的主意,就是通过Reflector来查看Focusable属性的使用位置,并找到了解决这个问题的方法 . 我只需要将以下代码添加到我的Window的构造函数中:

    Loaded += (sender, e) =>
        MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    

    这将自动选择Tab键顺序中的第一个控件,因此它是一个通用的解决方案,应该可以放入任何窗口和Just Work .

  • 0

    在有了“WPF初始焦点噩梦”并基于堆叠上的一些答案之后,以下证明了我是最佳解决方案 .

    首先,添加您的App.xaml OnStartup()以下内容:

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

    然后在App.xaml中添加'WindowLoaded'事件:

    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));
    
            }));
        }
    

    由于某些框架竞争条件,WPF初始焦点大多失败,因此必须使用线程问题 .

    我发现以下解决方案最佳,因为它在整个应用程序中全局使用 .

    希望能帮助到你...

    奥兰

  • 8

    如果你像我一样,并且你正在使用一些框架,以某种方式,搞乱基本的焦点行为,并使所有解决方案无关紧要,你仍然可以这样做:

    1 - 注意获得焦点的元素(无论它是什么!)

    2 - 在xxx.xaml.cs后面的代码中添加它

    private bool _firstLoad;
    

    3 - 在获得第一个焦点的元素上添加它:

    GotFocus="Element_GotFocus"
    

    4 - 在后面的代码中添加Element_GotFocus方法,并指定需要第一个焦点的WPF命名元素:

    private void Element_GotFocus(object sender, RoutedEventArgs e)
    {
        if(_firstLoad)
        {
            this.MyElementWithFistFocus.Focus();
            _firstLoad = false;
        }
    }
    

    5 - 管理已加载的事件

    在XAML中

    Loaded="MyWindow_Loaded"
    

    在xaml.cs中

    private void MyWindow_Loaded(object sender, RoutedEventArgs e)
    {
            _firstLoad = true;
            this.Element_GotFocus(null, null);
    }
    

    希望这将有助于作为最后的解决方案

  • 1

    我也遇到了同样的问题 . 我在canvas容器中有三个文本框,并希望在用户控件打开时聚焦第一个文本框 . WPF代码遵循MVVM模式 . 我创建了一个单独的行为类来聚焦元素,并将其绑定到我的视图中 .

    画布行为代码

    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);
            }
    
        }
    
    }
    

    视图代码

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

    这也有效:

    <Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">
    
       <DataGrid x:Name="SomeElement">
         ...
       </DataGrid>
    </Window>
    

相关问题