it-swarm.com.de

Der Fokus kann nicht auf ein untergeordnetes Element von UserControl gesetzt werden

Ich habe eine UserControl, die eine TextBox enthält. Wenn mein Hauptfenster geladen wird, möchte ich den Fokus auf dieses Textfeld setzen, also habe ich Focusable="True" GotFocus="UC_GotFocus" zur UserControls-Definition und FocusManager.FocusedElement="{Binding ElementName=login}" zu meiner Hauptfenster-Definition hinzugefügt. In der UC_GotFocus-Methode rufe ich einfach .Focus() auf der Steuerung auf, auf die ich mich konzentrieren möchte, aber das funktioniert nicht.

Alles was ich tun muss, ist ein TextBox in einem UserControl-Fokus, wenn die Anwendung startet.

Jede Hilfe wäre dankbar, danke.

37
Stimul8d

Ich habe dieses Problem vor kurzem für ein Anmeldefenster behoben, das beim ersten Laden des Hauptfensters über ein Storyboard angezeigt wird. 

Ich glaube, es gab zwei Schlüssel für das Update. Zum einen sollte das übergeordnete Element zum Fokusumfang werden. Die andere bestand darin, das Storyboard Completed-Ereignis für das Storyboard zu behandeln, das durch das Laden des Fensters ausgelöst wurde. 

Dieses Storyboard macht den Benutzernamen- und Kennwortbereich sichtbar und wird dann zu 100% undurchsichtig. Der Schlüssel ist, dass das Steuerelement für den Benutzernamen nicht sichtbar war, bis das Storyboard ausgeführt wurde. Daher konnte das Steuerelement den Fokus keyboard nicht erhalten, bis es sichtbar war. Was mich für eine Weile abwarf, war, dass es "Fokus" hatte (dh der Fokus war wahr, aber wie sich herausstellte, war dies nur ein logischer Fokus), und ich wusste nicht, dass WPF das Konzept des logischen und des Tastaturfokus hatte, bis er das Buch von Kent Boogaart las Antworten Sie und schauen Sie sich die WPF von Microsoft an Linktext

Nachdem ich das getan hatte, war die Lösung für mein spezielles Problem einfach:

1) Machen Sie das enthaltende Element zu einem Fokusbereich

<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
    <TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
    </TextBox>
</Canvas>

2) Fügen Sie einen abgeschlossenen Ereignishandler an das Storyboard an

    <Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>

und

3) Legen Sie meinen Benutzernamen TextBox so fest, dass der Tastaturfokus im Eventboard des Storyboards abgeschlossen ist.

void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
 m_uxUsername.Focus();
}

Beachten Sie, dass der Aufruf von item.Focus () den Aufruf Keyboard.Focus (this) zur Folge hat, sodass Sie dies nicht explizit aufrufen müssen. Siehe diese Frage zum Unterschied zwischen Keyboard.Focus (item) und item.Focus.

25
eesh

Es ist blöd, aber es funktioniert:

Pop einen Thread, der eine Weile wartet, dann kommt er zurück und setzt den gewünschten Fokus. Es funktioniert sogar im Kontext eines Elements Host.

private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

 System.Threading.ThreadPool.QueueUserWorkItem(
                   (a) =>
                        {
                            System.Threading.Thread.Sleep(100);
                            someUiElementThatWantsFocus.Dispatcher.Invoke(
                            new Action(() =>
                            {
                                someUiElementThatWantsFocus.Focus();

                            }));
                        }
                   );

}
15
fuzquat

Vor kurzem hatte ich ein Listenfeld mit einigen TextBlocks. Ich wollte in der Lage sein, doppelt auf den Textblock zu klicken und ihn in eine TextBox umwandeln zu lassen. Dann konzentriere mich darauf und wähle den gesamten Text aus, damit der Benutzer den neuen Namen eingeben kann (Akin to Adobe Layers)

Jedenfalls habe ich das mit einer Veranstaltung gemacht und es hat einfach nicht funktioniert. Die magische Kugel für mich hier stellte sicher, dass ich das Ereignis als erledigt definierte. Ich schätze es war Fokus gesetzt, aber sobald das Ereignis den Weg eingeschlagen hatte, wechselte es den logischen Fokus.

Die Moral der Geschichte ist, stellen Sie sicher, dass Sie das Ereignis als behandelt markieren. Dies könnte Ihr Problem sein.

7
Vassi

„Beim Festlegen des Anfangsfokus beim Start der Anwendung muss das Element, das den Fokus erhalten soll, mit einer PresentationSource verbunden sein, und für das Element müssen Focusable und IsVisible auf true gesetzt sein. Der empfohlene Ort zum Festlegen des anfänglichen Fokus ist im Loaded Event Handler "(MSDN).

Fügen Sie einfach einen "Loaded" -Ereignishandler im Konstruktor Ihres Fensters (oder Steuerelements) hinzu, und in diesem Fall rufen Sie den Focus () - Modus des Zielsteuerelements auf.

    public MyWindow() {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
    }

    void MyWindow_Loaded(object sender, RoutedEventArgs e) {
        textBox.Focus();
    }
6
David

da ich die Lösung von Fuzquat ausprobiert und als die allgemeinste Lösung empfunden habe, dachte ich, ich würde eine andere Version verwenden, da sich einige darüber beschwert haben, dass sie unordentlich aussieht. hier ist es also:

                casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
                {
                    x.Focus();
                }), DispatcherPriority.ApplicationIdle, casted);

kein Thread.Sleep, kein ThreadPool. Sauber genug, hoffe ich. Könnte wirklich einige Repräsentanten verwenden, damit ich die Lösungen anderer Leute kommentieren kann.

AKTUALISIEREN:

Da scheinen die Leute hübschen Code zu mögen:

public static class WpfExtensions
{
    public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement
    {
        element.Dispatcher.BeginInvoke(priority, action);
    }
}

jetzt kannst du es so nennen:

child.BeginInvoke(d => d.Focus());
5
Dbl

Ich habe eine gute Serie von Blogbeiträgen zum WPF-Fokus gefunden.

Sie sind alle gut zu lesen, aber der dritte Teil befasst sich speziell mit dem Setzen des Fokus auf ein Oberflächenelement in einem UserControl.

4
Ashley Davis

WPF unterstützt zwei verschiedene Arten von Fokus:

  1. Tastaturfokus
  2. Logischer Fokus

Die FocusedElement-Eigenschaft erhält oder setzt einen logischen Fokus innerhalb eines Fokusbereichs. Ich vermute, dass Ihre TextBoxdo einen logischen Fokus hat, aber der enthaltene Fokusbereich ist nicht der aktive Fokusbereich. Ergo hat nicht Tastaturfokus.

Die Frage ist also: Haben Sie mehrere Fokusbereiche in Ihrem visuellen Baum?

3
Kent Boogaart
  1. Setzen Sie Ihre Benutzersteuerung auf Focusable = "True" (XAML)
  2. Behandeln Sie das GotFocus -Ereignis auf Ihrem Steuerelement und rufen Sie yourTextBox.Focus () auf.
  3. Behandeln Sie das Loaded -Ereignis in Ihrem Fenster und rufen Sie yourControl.Focus () auf.

Ich habe eine Beispiel-App, die mit dieser Lösung während der Eingabe ausgeführt wird. Wenn dies für Sie nicht funktioniert, muss etwas für Ihre App oder Umgebung spezifisch sein, das das Problem verursacht. In Ihrer ursprünglichen Frage glaube ich, dass die Bindung das Problem verursacht ... Ich hoffe, das hilft.

3
Josh F.

Ich habe die Antwort von Fuzquat in eine Erweiterungsmethode umgewandelt. Ich verwende dies anstelle von Focus (), wo Focus () nicht funktionierte.

using System;
using System.Threading;
using System.Windows;

namespace YourProject.Extensions
{
    public static class UIElementExtension
    {
        public static void WaitAndFocus(this UIElement element, int ms = 100)
        {
            ThreadPool.QueueUserWorkItem(f =>
            {
                Thread.Sleep(ms);

                element.Dispatcher.Invoke(new Action(() =>
                {
                    element.Focus();
                }));
            });
        }
    }
}
1
Tempeck

Ich habe ein Fokusproblem festgestellt, das sich speziell auf das Hosten von WPF UserControls in ElementHosts bezieht, die in einem Formular enthalten sind, das über die MdiParent-Eigenschaft als MDI - Kind festgelegt wird.

Ich bin nicht sicher, ob dies das gleiche Problem ist, mit dem andere konfrontiert sind, aber Sie können sich die Details genauer ansehen, indem Sie dem Link unten folgen.

Problem mit dem Festlegen des Fokus in einem WPF-UserControl, das in einem ElementHost in einem untergeordneten WindowsForms-Formular MDI gehostet wird

1
jpierson

Der Trick für mich war das Attribut FocusManager.FocusedElement . Ich habe zuerst versucht, es in der UserControl zu setzen, aber es hat nicht funktioniert.

Also versuchte ich es stattdessen auf das erste Kind des UserControl zu setzen:

<UserControl x:Class="WpfApplication3.UserControl1"
         xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml">
<Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}">
    <TextBox x:Name="MyTextBox"/>
</Grid>

... und es hat funktioniert! :)

1
Crono

Nach einem WPF Initial Focus Nightmare und basierend auf einigen Antworten im Stapel erwies sich das Folgende als die beste Lösung für mich. 

Fügen Sie zunächst App.xaml OnStartup () wie folgt hinzu:

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

Fügen Sie dann das Ereignis 'WindowLoaded' auch in App.xaml hinzu: 

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

        }));
    }

Das Threading-Problem muss verwendet werden, da der anfängliche Fokus von WPF aufgrund einiger Rahmenrennen meistens fehlschlägt.

Ich fand die folgende Lösung am besten, da sie global für die gesamte App verwendet wird.

Ich hoffe es hilft...

Oran

1
OrPaz

Ich habe es in PageLoaded () oder Control geladen, aber dann rufe ich den WCF-Async-Dienst auf und mache Sachen, die den Fokus zu verlieren scheinen. Ich muss es am Ende all meiner Sachen einstellen. Das ist in Ordnung, aber manchmal ändere ich den Code und vergesse dann, dass ich auch den Cursor setze.

0
Dan Parker

Ich mag keine Lösungen, wenn Sie einen anderen Tab-Bereich für UserControl festlegen. In diesem Fall stehen Ihnen beim Navigieren mit der Tastatur zwei verschiedene Einfügemarken zur Verfügung: am Fenster und am anderen - innerhalb der Benutzersteuerung. Meine Lösung besteht einfach darin, den Fokus von der Benutzersteuerung auf die innere Kindsteuerung umzuleiten. Festlegen, dass das Benutzersteuerelement fokussierbar ist (weil es standardmäßig falsch ist):

<UserControl ..... Focusable="True">

und Überschreiben von Fokusereignishandlern in Code-behind:

protected override void OnGotFocus(RoutedEventArgs e)
{
    base.OnGotFocus(e);
    MyTextBox.Focus();
}

protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
    base.OnGotKeyboardFocus(e);
    Keyboard.Focus(MyTextBox);
}
0
white.zaz

Angenommen, Sie möchten den Fokus für das Benutzername-Textfeld festlegen, sodass der Benutzer jedes Mal, wenn er angezeigt wird, eine direkte Eingabe vornehmen kann.

Im Konstruktor Ihrer Kontrolle:

this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
0
Thai Anh Duc

Ich habe Benutzersteuerelement - Stapelbedienfeld mit zwei Textfeldern. Die Textfelder wurden im Konstruktor hinzugefügt, nicht im XAML. Wenn ich versuche, das erste Textfeld zu fokussieren, ist nichts passiert ... Die Siggestion mit Loaded-Ereignis behebt mein Problem. Wird bei geladenem Ereignis und everthing einfach control.Focus () genannt. 

0
charino

Nachdem ich die Kombinationen der obigen Vorschläge ausprobiert hatte, konnte ich dem gewünschten Textfeld in einem untergeordneten UserControl mit folgendem Fokus zuverlässig den Fokus zuweisen. Weisen Sie dem untergeordneten Steuerelement den Fokus zu, und lassen Sie das untergeordnete UserControl den Fokus auf seine TextBox setzen. Die focus-Anweisung der TextBox hat von sich aus den Wert true zurückgegeben, ergab jedoch nicht das gewünschte Ergebnis, bis das UserControl ebenfalls den Fokus erhielt. Ich sollte auch beachten, dass das UserControl keinen Fokus für sich selbst anfordern konnte und vom Fenster angegeben werden musste.

Der Kürze halber habe ich die Loaded-Ereignisse im Window und UserControl nicht registriert.

Fenster

private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
    ControlXYZ.Focus();
}

Nutzerkontrolle

private void OnControlLoaded(object sender, RoutedEventArgs e)
{
    TextBoxXYZ.Focus();
}
0
jtimperley