Il semble que lorsqu'une application WPF démarre, rien n'a le focus.
C'est vraiment bizarre. Tous les autres frameworks que j'ai utilisés font exactement ce que vous attendez: met l'accent initial sur le premier contrôle dans l'ordre de tabulation. Mais j'ai confirmé qu'il s'agissait de WPF, pas seulement de mon application - si je crée une nouvelle fenêtre et y mets simplement une zone de texte et exécute l'application, la zone de texte n'a pas le focus tant que je n'ai pas cliqué dessus ou que j'ai appuyé sur Tab . Beurk.
Mon application actuelle est plus compliquée qu'une simple zone de texte. J'ai plusieurs couches de UserControls dans UserControls. Un de ces UserControls a des gestionnaires Focusable = "True" et KeyDown / KeyUp, et je veux qu'il ait le focus dès que ma fenêtre s'ouvre. Cependant, je suis toujours un peu novice de WPF et je n'ai pas beaucoup de chance de savoir comment faire cela.
Si je démarre mon application et que j'appuie sur la touche Tab, le focus va à mon contrôle focusable et il commence à fonctionner comme je le souhaite. Mais je ne veux pas que mes utilisateurs doivent appuyer sur Tab avant de pouvoir commencer à utiliser la fenêtre.
J'ai joué avec FocusManager.FocusedElement, mais je ne sais pas sur quel contrôle le définir (la fenêtre de niveau supérieur? Le parent qui contient le contrôle focusable? Le contrôle focusable lui-même?) Ou sur quoi le définir.
Que dois-je faire pour que mon contrôle profondément imbriqué ait le focus initial dès que la fenêtre s'ouvre? Ou mieux encore, pour concentrer le premier contrôle focusable dans l'ordre de tabulation?
J'ai eu la brillante idée de fouiller dans Reflector pour voir où la propriété Focusable est utilisée, et j'ai trouvé mon chemin vers cette solution. J'ai juste besoin d'ajouter le code suivant au constructeur de ma fenêtre:
Loaded += (sender, e) => MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
Cela sélectionnera automatiquement le premier contrôle dans l'ordre de tabulation, c'est donc une solution générale qui devrait pouvoir être déposée dans n'importe quelle fenêtre et Just Work.
la source
Button
. Pour résoudre ce problème, je retourne l'MoveFocus
appel sur le répartiteur enContextIdle
priorité (Background
ou plus ne fonctionne pas). En outre, il y a unFocusNavigationDirection.First
qui correspond mieux à l'intention et fait la même chose dans ce cas.Basé sur la réponse acceptée implémentée en tant que comportement attaché:
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)); } } } }
Utilisez-le comme ceci:
<Window xmlns:Behaviors="clr-namespace:UI.Behaviors" Behaviors:FocusBehavior.FocusFirst="true">
la source
DependencyProperty.RegisterAttached
. Le troisième paramètre devrait êtretypeof(FocusBehavior)
, nontypeof(Control)
. Cette modification empêchera le concepteur de signaler la propriété «FocusFirst» déjà enregistrée par des erreurs «Control».J'ai trouvé une autre solution possible. Mark Smith a publié une extension de balisage FirstFocusedElement à utiliser avec FocusManager.FocusedElement.
<UserControl x:Class="FocusTest.Page2" xmlns:FocusTest="clr-namespace:FocusTest" FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">
la source
Avait le même problème résolu avec une solution simple: Dans la fenêtre principale:
<Window .... FocusManager.FocusedElement="{Binding ElementName=usercontrolelementname}" ... />
Dans le contrôle utilisateur:
private void UserControl_GotFocus_1(object sender, RoutedEventArgs e) { targetcontrol.Focus(); this.GotFocus -= UserControl_GotFocus_1; // to set focus only once }
la source
Après avoir eu un 'WPF Initial Focus Nightmare' et sur la base de quelques réponses sur la pile, ce qui suit s'est avéré être la meilleure solution.
Tout d'abord, ajoutez votre App.xaml OnStartup () les éléments suivants:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent, new RoutedEventHandler(WindowLoaded));
Ajoutez ensuite l'événement 'WindowLoaded' également dans 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)); })); }
Le problème de threading doit être utilisé car le focus initial de WPF échoue principalement en raison de certaines conditions de concurrence du cadre.
J'ai trouvé la meilleure solution car elle est utilisée dans le monde entier pour l'ensemble de l'application.
J'espère que cela aide...
Oran
la source
BeginInvoke
place de cetteSleep(100)
déclaration effrayante .Vous pouvez facilement définir le contrôle lui-même en tant qu'élément ciblé dans XAML.
<Window> <DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"> ... </DataGrid> </Window>
Je n'ai jamais essayé de définir cela dans un contrôle utilisateur et de voir si cela fonctionne, mais cela peut.
la source
Une version minimale de la réponse de Mizipzor pour 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)); }
Utilisez dans votre XAML:
<Window local:FocusBehavior.GiveInitialFocus="True" />
la source
Si vous êtes comme moi et que vous utilisez des frameworks qui, d'une manière ou d'une autre, gâchent les comportements de mise au point de base et rendent toutes les solutions ci-dessus non pertinentes, vous pouvez toujours le faire:
1 - Notez l'élément qui obtient le focus (quel qu'il soit!)
2 - Ajoutez ceci dans votre code derrière xxx.xaml.cs
private bool _firstLoad;
3 - Ajoutez ceci sur l'élément qui obtient le premier focus:
GotFocus="Element_GotFocus"
4 - Ajoutez la méthode Element_GotFocus dans le code derrière, et spécifiez l'élément nommé WPF qui a besoin du premier focus:
private void Element_GotFocus(object sender, RoutedEventArgs e) { if(_firstLoad) { this.MyElementWithFistFocus.Focus(); _firstLoad = false; } }
5 - Gérer l'événement Loaded
en XAML
Loaded="MyWindow_Loaded"
dans xaml.cs
private void MyWindow_Loaded(object sender, RoutedEventArgs e) { _firstLoad = true; this.Element_GotFocus(null, null); }
J'espère que cela aidera en tant que solution de dernier recours
la source
J'ai également rencontré le même problème. J'avais trois zones de texte à l'intérieur du conteneur de canevas et je voulais que la première zone de texte soit focalisée lorsque le contrôle utilisateur s'ouvre. Le code WPF a suivi le modèle MVVM. J'ai créé une classe de comportement distincte pour focaliser l'élément et l'ai lié à ma vue comme ceci.
Code de comportement du canevas
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 pour la vue
<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>
la source
La solution ci-dessus ne fonctionnait pas comme prévu pour moi, j'ai légèrement modifié le comportement proposé par Mizipzor comme suit:
De cette partie
if ((bool)args.NewValue) { control.Loaded += (sender, e) => control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); }
Pour ça
if ((bool)args.NewValue) { control.Loaded += (sender, e) => control.Focus(); }
ET Je n'attache pas ce comportement à Window ou UserControl, mais pour contrôler je veux me concentrer initialement, par exemple:
<TextBox ui:FocusBehavior.InitialFocus="True" />
Oh, désolé pour un nom différent J'utilise le nom InitialFocus pour la propriété jointe.
Et cela fonctionne pour moi, peut-être que cela pourrait aider quelqu'un d'autre.
la source
<Window FocusManager.FocusedElement="{Binding ElementName=yourControlName}">
la source