WPF e focus iniziale

Sembra che quando inizia l’applicazione WPF, nulla è focalizzato.

Questo è veramente strano Ogni altro framework che ho usato fa proprio quello che ti aspetteresti: pone l’attenzione iniziale sul primo controllo nell’ordine di tabulazione. Ma ho confermato che è WPF, non solo la mia app – se creo una nuova finestra, e ci metto solo un TextBox, ed eseguo l’app, il TextBox non ha focus finché non clicco su di esso o premo Tab . Che schifo.

La mia app effettiva è più complicata di un semplice TextBox. Ho diversi livelli di UserControls all’interno di UserControls. Uno di questi UserControls ha Focusable = “True” e KeyDown / KeyUp handler, e voglio che abbia il focus non appena si apre la mia finestra. Sono ancora un po ‘un novizio del WPF, però, e non ho molta fortuna a capire come farlo.

Se avvio la mia app e premo il tasto Tab, la messa a fuoco passa al mio controllo focalizzabile e inizia a funzionare nel modo desiderato. Ma non voglio che i miei utenti debbano premere Tab prima di poter iniziare a usare la finestra.

Ho giocato con FocusManager.FocusedElement, ma non sono sicuro su quale controllo impostarlo (la finestra di livello superiore? Il genitore che contiene il controllo focalizzabile? Il controllo focalizzabile stesso?) O su cosa impostarlo.

Cosa devo fare per far sì che il mio controllo profondamente annidato abbia il focus iniziale non appena si apre la finestra? O meglio ancora, per focalizzare il primo controllo focalizzabile nell’ordine di tabulazione?

Ho avuto la brillante idea di scavare attraverso Reflector per vedere dove viene utilizzata la proprietà Focusable e ho trovato la mia strada verso questa soluzione. Devo solo aggiungere il seguente codice al costruttore della mia finestra:

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

Questo selezionerà automaticamente il primo controllo nell’ordine di tabulazione, quindi è una soluzione generale che dovrebbe essere lasciata cadere in qualsiasi finestra e Just Work.

Anche questo funziona:

   ...   

Basato sulla risposta accettata implementata come comportamento allegato:

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

Usalo in questo modo:

  

Ho trovato un’altra ansible soluzione. Mark Smith ha pubblicato un’estensione di markup FirstFocusedElement da utilizzare con FocusManager.FocusedElement.

  

Dopo aver avuto un ‘incubo di Focus iniziale WPF’ e basato su alcune risposte sullo stack, il seguente ha dimostrato di essere la soluzione migliore.

Per prima cosa aggiungi la tua app.xaml OnStartup () come segue:

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

Quindi aggiungi l’evento ‘WindowLoaded’ anche 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)); })); } 

Il problema del threading deve essere utilizzato in quanto il focus iniziale di WPF per lo più fallisce a causa di alcune condizioni di gara del framework.

Ho trovato la seguente soluzione migliore poiché viene utilizzata globalmente per l’intera app.

Spero che sia d’aiuto…

Oran

Lo stesso problema lo aveva risolto con una soluzione semplice: nella finestra principale:

   

Nel controllo utente:

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

Puoi facilmente avere il controllo impostato come elemento focalizzato in XAML.

   ...   

Non ho mai provato ad impostarlo in un controllo utente e vedere se funziona, ma può farlo.

Una versione minimale della risposta di Mizipzor per 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)); } 

Usa nel tuo XAML:

  

Se sei come me, e stai utilizzando alcuni framework che, in qualche modo, incasinano i comportamenti di base dell’objective e rendono tutte le soluzioni sopra irrilevanti, puoi comunque farlo:

1 – Nota l’elemento che ottiene il focus (qualunque cosa sia!)

2 – Aggiungi questo nel tuo codice dietro xxx.xaml.cs

 private bool _firstLoad; 

3 – Aggiungi questo sull’elemento che ottiene il primo focus:

 GotFocus="Element_GotFocus" 

4 – Aggiungi il metodo Element_GotFocus nel codice sottostante e specifica l’elemento denominato WPF che ha bisogno del primo focus:

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

5 – Gestire l’evento caricato

in XAML

 Loaded="MyWindow_Loaded" 

in xaml.cs

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

Spero che questo possa essere d’aiuto come soluzione di ultima istanza

  

Ho anche affrontato lo stesso problema. Avevo tre caselle di testo all’interno del contenitore di canvas e volevo che la prima casella di testo fosse focalizzata quando si apre il controllo utente. Il codice WPF ha seguito lo schema MVVM. Ho creato una class di comportamento separata per focalizzare l’elemento e legarlo alla mia vista in questo modo.

Codice di comportamento della canvas

 public class CanvasLoadedBehavior : Behavior { 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); } } } 

Codice per la vista

                                                                 

La soluzione di cui sopra non funzionava come previsto per me, ho modificato leggermente il comportamento proposto da Mizipzor come segue:

Da questa parte

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

A questa

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

E non sto attaccando questo comportamento a Window o UserControl, ma per controllare voglio focalizzarmi inizialmente, ad esempio:

  

Oh, mi dispiace per nome diverso sto usando il nome InitialFocus per la proprietà allegata.

E questo funziona per me, forse potrebbe aiutare qualcun altro.