web-dev-qa-db-ja.com

UserControlの子にフォーカスを設定できません

UserControlを含むTextBoxがあります。メインウィンドウが読み込まれたら、このテキストボックスにフォーカスを設定するため、UserControls定義に_Focusable="True" GotFocus="UC_GotFocus"_を追加し、メインウィンドウ定義に_FocusManager.FocusedElement="{Binding ElementName=login}"_を追加しました。 _UC_GotFocus_メソッドでは、フォーカスしたいコントロールで.Focus()を呼び出すだけですが、これは機能しません。

私がする必要があるのは、TextBoxUserControlがあり、アプリケーションの起動時にフォーカスを受け取ることです。

どんな助けでも感謝します、ありがとう。

38
Stimul8d

私は最近、メインウィンドウが最初に読み込まれたときにストーリーボードを介して表示されるログインスプラッシュスクリーンのこの問題を修正しました。

修正には2つの鍵があったと思います。 1つは、包含要素をフォーカススコープにすることでした。もう1つは、読み込まれているウィンドウによってトリガーされたストーリーボードのStoryboard Completedイベントを処理することでした。

このストーリーボードは、ユーザー名とパスワードのキャンバスを表示し、100%不透明になるまでフェードします。重要なのは、ストーリーボードが実行されるまでユーザー名コントロールが表示されなかったため、そのコントロールが表示されるまでkeyboardフォーカスを取得できなかったことです。しばらく私を驚かせたのは、「フォーカス」があるということです(つまり、フォーカスは真でしたが、これは論理的なフォーカスにすぎませんでした)、KPF Boogaartの答えて、MicrosoftのWPFを見る リンクテキスト

私がそれをやった後、私の特定の問題の解決策は簡単でした:

1)含まれている要素をフォーカススコープにします

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

2)完成したイベントハンドラーをストーリーボードに接続する

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

そして

3)ストーリーボードの完了イベントハンドラーでキーボードフォーカスを持つようにユーザー名TextBoxを設定します。

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

Item.Focus()を呼び出すとKeyboard.Focus(this)が呼び出されるため、明示的に呼び出す必要はありません。 Keyboard.Focus(item)とitem.Focusの違い に関するこの質問を参照してください

26
eesh

その愚かですが、それは動作します:

しばらく待ってから戻ってきて、必要なフォーカスを設定するスレッドをポップします。要素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();

                            }));
                        }
                   );

}
16
fuzquat

つい最近、いくつかのTextBlockを格納するリストボックスがありました。テキストブロックをダブルクリックしてTextBoxに変えてから、それに焦点を合わせてすべてのテキストを選択できるようにしたかったので、ユーザーは新しい名前の入力を開始できます(Adobe Layersと同様)

とにかく、私はイベントでこれをしていましたが、うまくいきませんでした。ここでの私にとっての特効薬は、イベントを処理するように設定することでした。私はそれを考えますwasフォーカスを設定しますが、イベントがパスを下るとすぐに、論理フォーカスを切り替えていました。

ストーリーの教訓は、イベントを処理済みとしてマークしていることを確認することです。これが問題になる可能性があります。

7
Vassi

「アプリケーションの起動時に初期フォーカスを設定する場合、フォーカスを受け取る要素をPresentationSourceに接続し、要素のFocusableおよびIsVisibleをtrueに設定する必要があります。初期フォーカスを設定する推奨場所は、Loadedイベントハンドラー(MSDN)です

Window(またはControl)のコンストラクターに「Loaded」イベントハンドラーを追加し、そのイベントハンドラーでターゲットコントロールのFocus()メソッドを呼び出します。

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

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

fuzquatのソリューションを試してみて最も一般的なものであることがわかったので、別のバージョンを共有すると思ったのです。ここにあります:

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

thread.Sleep、ThreadPoolはありません。十分にきれいに願っています。私は他の人々のソリューションにコメントできるように本当にいくつかの担当者を使用できます。

更新:

人々はきれいなコードを好むようだから:

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

これで次のように呼び出すことができます:

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

WPFは、2種類のフォーカスをサポートしています。

  1. キーボードフォーカス
  2. 論理的焦点

FocusedElementプロパティは、フォーカススコープ内の論理フォーカスを取得または設定します。 TextBoxdoesに論理的なフォーカスがあると思われますが、そのフォーカススコープはアクティブフォーカススコープではありません。エルゴ、それしないキーボードフォーカスを持っています。

質問は、ビジュアルツリーに複数のフォーカススコープがありますか?

3
Kent Boogaart
  1. ユーザーコントロールをFocusable = "True"(XAML)に設定します
  2. コントロールでGotFocusイベントを処理し、yourTextBox.Focus()を呼び出します
  3. ウィンドウでLoadedイベントを処理し、yourControl.Focus()を呼び出します

入力中にこのソリューションで実行するサンプルアプリがあります。これがうまくいかない場合は、問題の原因となるアプリまたは環境に固有のものが必要です。あなたの元の質問では、バインディングが問題を引き起こしていると思います。これがお役に立てば幸いです。

3
Josh F.

WPFフォーカスに関する一連の優れたブログ記事を見つけました。

これらはすべて読むのに適していますが、第3部では特にUserControlのUI要素にフォーカスを設定することを扱います。

3
Ashley Davis

Fuzquatの答えを拡張メソッドに変換しました。 Focus()が機能しなかったFocus()の代わりにこれを使用しています。

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

MdiParentプロパティを介してMDI子として設定されているフォーム内に含まれるElementHosts内のWPF UserControlsのホストに特に関連するフォーカスの問題に気付きました。

これが他の人が経験しているのと同じ問題であるかどうかはわかりませんが、以下のリンクに従って詳細を掘り下げてください。

WindowsForms子のElementHost内でホストされるWPF UserControl内にフォーカスを設定する際の問題MDI form

1
jpierson

私にとってのトリックは、FocusManager.FocusedElement属性でした。最初にUserControlで設定しようとしましたが、うまくいきませんでした。

そこで、代わりにUserControlの最初の子に配置してみました。

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

...そしてそれはうまくいきました! :)

1
Crono

「WPF Initial Focus Nightmare」を取得し、スタックに関するいくつかの回答に基づいて、次のことが最良のソリューションであることが証明されました。

まず、次の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の初期フォーカスがほとんど失敗するため、スレッドの問題を使用する必要があります。

アプリ全体でグローバルに使用されているため、次のソリューションが最適であることがわかりました。

それが役に立てば幸い...

オラン

1
OrPaz

PageLoaded()またはロードされたコントロールに設定しますが、その後、WCF非同期サービスを呼び出して、フォーカスを失いそうなことをしています。私はすべてのことの最後に設定する必要があります。これで問題ありませんが、コードに変更を加えると、カーソルを設定していることを忘れてしまうことがあります。

0
Dan Parker

UserControlに別のタブスコープを設定するソリューションは好きではありません。その場合、キーボードでナビゲートするときに2つの異なるキャレットがあります。ウィンドウ上ともう1つ-ユーザーコントロール内です。私の解決策は、ユーザーコントロールから内側の子コントロールにフォーカスをリダイレクトすることです。ユーザーコントロールをフォーカス可能に設定します(既定ではfalseであるため)。

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

コードビハインドでフォーカスイベントハンドラーをオーバーライドします。

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

ユーザー名テキストボックスにフォーカスを設定すると仮定すると、ユーザーは表示されるたびに直接入力できます。

コントロールのコンストラクターで:

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

ユーザーコントロールがあります-2つのテキストボックスがあるスタックパネル。テキストボックスは、xamlではなく、コンストラクターに追加されました。最初のテキストボックスにフォーカスしようとすると、何も起こりませんでした。 Loadedイベントでのsiggestionは私の問題を修正します。 Loadedイベントおよびその他すべてでcontrol.Focus()を呼び出しました。

0
charino

上記の提案の組み合わせを試した後、次の方法で子UserControlの目的のテキストボックスに確実にフォーカスを割り当てることができました。基本的に、子コントロールにフォーカスを与え、子UserControlにそのTextBoxにフォーカスを与えます。 TextBoxのフォーカスステートメントはそれ自体でtrueを返しましたが、UserControlにもフォーカスが与えられるまで、目的の結果は得られませんでした。また、UserControlはそれ自体にフォーカスを要求することができず、Windowによって提供されなければならなかったことにも注意する必要があります。

簡潔にするため、WindowおよびUserControlのLoadedイベントの登録は省略しました。

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

UserControl

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