visual - wpf usercontrol example



無法將焦點設置為UserControl的子節點 (12)

  1. 將用戶控件設置為Focusable =“True” (XAML)
  2. 處理控件上的GotFocus事件並調用yourTextBox.Focus()
  3. 處理窗口上的Loaded事件並調用yourControl.Focus()

在我輸入時,我有一個運行此解決方案的示例應用程序。 如果這對您不起作用,則必須存在導致問題的應用或環境特定的內容。 在您的原始問題中,我認為綁定導致問題。 我希望這有幫助。

我有一個包含TextBoxUserControl 。 當我的主窗口加載時,我想將焦點設置到此文本框,因此我將Focusable="True" GotFocus="UC_GotFocus"UserControl的定義,並將FocusManager.FocusedElement="{Binding ElementName=login}"到我的主窗口定義。 在UC_GotFocus方法中,我只是在我想要關注的控件上調用.Focus() ,但這不起作用。

我需要做的就是在應用程序啟動時在UserControl接收焦點中有一個TextBox

任何幫助將不勝感激,謝謝。


Answer #1

“在應用程序啟動時設置初始焦點時,接收焦點的元素必須連接到PresentationSource,並且元素必須將Focusable和IsVisible設置為true。 建議初始焦點的建議位置是“已加載的事件處理程序”(MSDN)

只需在Window(或Control)的構造函數中添加一個“Loaded”事件處理程序,並在該事件處理程序中調用目標控件上的Focus()方法。

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

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

Answer #2

假設您要為Username文本框設置焦點,因此用戶可以在每次顯示時直接輸入。

在您的控件的構造函數中:

this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);

Answer #3

因為我嘗試了一個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());

Answer #4

在進行了“WPF初始焦點噩夢”並基於堆棧上的一些答案後,以下證明我是最佳解決方案。

首先,添加您的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的初始焦點主要是由於某些框架競爭條件而失敗。

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

希望能幫助到你...

奧蘭


Answer #5

它的愚蠢,但它的工作原理:

彈出等待一段時間的線程然後返回並設置您想要的焦點。 它甚至可以在元素主機的上下文中工作。

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

                            }));
                        }
                   );

}

Answer #6

我不喜歡為UserControl設置另一個選項卡範圍的解決方案。 在這種情況下,當您通過鍵盤導航時,您將有兩個不同的插入符號:在窗口上,另一個 - 在用戶控件內部。 我的解決方案只是將焦點從用戶控件重定向到內部子控件。 將用戶控件設置為可聚焦(因為默認情況下為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);
}

Answer #7

我在PageLoaded()或控件加載中設置它,但後來我正在調用WCF異步服務並做一些似乎失去焦點的東西。 我必須在我做的所有事情的最後設置它。 這很好,但有時我會對代碼進行更改,然後我忘記了我也在設置光標。


Answer #8

我將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();
                }));
            });
        }
    }
}

Answer #9

我最近修復了這個問題,因為登錄初始屏幕是在首次加載主窗口時通過故事板顯示的。

我相信修復有兩個關鍵。 一個是使包含元素成為焦點範圍。 另一個是處理由加載窗口觸發的故事板的Storyboard Completed事件。

此故事板使用戶名和密碼畫布可見,然後淡入100%不透明。 關鍵是在故事板運行之前,用戶名控件是不可見的,因此該控件在可見之前無法獲得鍵盤焦點。 讓我離開一段時間的是它有“焦點”(即焦點是真的,但事實證明這只是邏輯焦點)並且我不知道WPF在閱讀Kent 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,使鍵盤焦點在storyboard完成的事件處理程序中。

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

請注意,調用item.Focus()會導致調用Keyboard.Focus(this),因此您無需顯式調用它。 看到這個關於Keyboard.Focus(item)和item.Focus之間區別的問題







focusmanager