2009-05-03 72 views
156

似乎WPF應用程序啓動時,沒有任何焦點。WPF和初始焦點

這真的很奇怪。我用過的其他所有框架都完全符合您的期望:首先將注意力集中在Tab選項中的第一個控件上。但我已經確認它是WPF,不僅僅是我的應用程序 - 如果我創建一個新窗口,並且只是放置一個TextBox並運行應用程序,那麼TextBox就沒有焦點,直到我點擊它或按Tab 。呸。

我的實際應用程序比TextBox更復雜。我在UserControls內有幾層UserControls。其中一個UserControls擁有Focusable =「True」和KeyDown/KeyUp處理程序,並且我希望它在我的窗口打開後立即擁有焦點。不過,我仍然是WPF新手,而且我沒有太多的運氣來搞清楚如何做到這一點。

如果我啓動我的應用程序並按下Tab鍵,然後焦點轉到我的可對焦控件上,然後按我想要的方式開始工作。但是我不希望我的用戶在開始使用該窗口之前不得不點擊Tab。

我已經玩過FocusManager.FocusedElement,但我不確定將其設置在哪個控件上(頂層Window?包含可聚焦控件的父級?可聚焦控件本身?將其設置爲。

當窗口打開後,我需要做什麼才能讓我的深層嵌套控件具有初始焦點?或者更好的是,按照Tab鍵順序聚焦第一個可調焦控件?

回答

141

我有一個聰明的想法,通過反射器來查看Focusable屬性的使用位置,並找到了解決方案。我只需要下面的代碼添加到我的窗口的構造函數:

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

這會自動選擇Tab鍵順序的第一控制,所以它是一個通用的解決方案,應該是能夠被丟棄到任何窗口,只是工作。

+19

加入轉變爲行爲。 <窗口 FocusBehavior.FocusFirst =「真」> ... – wekempf 2009-05-08 16:08:19

+4

@wekempf,我不熟悉行爲的想法,但我看着它,這不是一個壞主意。如果其他人(如我)不熟悉附加行爲,請參考以下解釋:http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx – 2009-05-09 13:43:00

+1

此外,如果所需元素是UserControl,包含實際可聚焦元素(即使在深層次結構中)。大! – 2015-05-21 10:08:41

13

我發現了另一種可能的解決方案。 Mark Smith發佈了一個用於FocusManager.FocusedElement的FirstFocusedElement markup extension

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

完全浮油!謝謝! – Andy 2017-05-10 02:13:14

125

這工作,也:

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

    <DataGrid x:Name="SomeElement"> 
    ... 
    </DataGrid> 
</Window> 
+20

在UserControls中似乎不起作用。 – Nathan 2012-12-04 16:19:04

7

有「WPF最初的重點夢魘」和基於棧的答案,以下證明了我是最好的解決方案後。

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

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

然後還加了 'WindowLoaded' 事件中的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)); 

     })); 
    } 

線程問題必須使用因爲WPF最初的重點大多因爲一些框架競爭條件而失敗。

我發現以下解決方案最好,因爲它是全局使用整個應用程序。

希望它有幫助...

奧蘭

49

基於作爲附加的行爲實施的接受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"> 
0
<Window FocusManager.FocusedElement="{Binding ElementName=yourControlName}"> 
7

當初同樣的問題簡單的解決方案解決了它: 在主窗口中:

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

您可以很容易地控制自己設定爲XAML聚焦元素。

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

我從來沒有試過在usercontrol中設置它,看看它是否有效,但它可能。

0

我也遇到了同樣的問題。我有三個文本框內的畫布容器,並希望第一個文本框被關注時用戶控件打開。 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> 
1

Mizipzor's answer的最小版本爲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)); 
} 

使用在您的XAML:

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

如果你像我一樣,你使用的是一些框架,不知何故,亂用基本集中行爲,並作出上述不相干的所有解決方案,你還可以這樣做:

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

希望這將幫助作爲最後的手段解決

0

以上溶液未正常工作對我來說,我已經略有改變如下由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名稱。

這是爲我工作,也許它可以幫助別人。