2010-09-15 59 views
2

我有一個WPF用戶控件,其中包含一個StackPanel,由於狀態更改而變得可見。當StackPanel變得可見時,我想將鍵盤焦點設置爲特定的子文本框。我發現,調用TextBox.Focus()將無法設置焦點(並返回false),除非我包裝在BeginInvoke的呼叫通話(大量的試驗和錯誤之後)如下所示:爲什麼我需要調用Dispatcher.BeginInvoke到SetFocus?

private void CtlClientLookupPanel_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { 
     LogThreadMsg(string.Format("CtlClientLookupPanel_IsVisibleChanged to {0}", CtlClientLookupPanel.Visibility)); 
     if (CtlClientLookupPanel.Visibility == Visibility.Visible) { 
      Dispatcher.BeginInvoke((ThreadStart)delegate { 
       bool gotFocus = CtlClientSearchText.Focus(); 
       LogThreadMsg(string.Format("CtlClientSearchText.Focus() returned {0}", gotFocus)); 
      }); 
     } 
    } 

    private void LogThreadMsg(string msg) { 
     string fullMsg = string.Format("Thread: {0} - {1}", Thread.CurrentThread.ManagedThreadId, msg); 
     System.Diagnostics.Trace.WriteLine(msg); 
    } 

兩個LogThreadMsg來電錶示,他們是在同一個(UI)線程如下所示:

[5232] Thread: 1 - CtlClientLookupPanel_IsVisibleChanged to Visible 
[5232] Thread: 1 - CtlClientSearchText.Focus() returned True 

那麼,爲什麼這個「黑客」需要?這似乎是某種時機問題,我正在尋找一個下游事件,可能會更好地調用Focus()而不訴諸於此,但尚未找到它。任何人都可以解釋這裏發生了什麼?

回答

3

這確實是一個計時問題。當CtlClientLookupPanel變得可見時,我認爲你的TextBox目前還不可見,因此無法專注。您可以嘗試處理上的IsVisibleChanged事件,而不是

+0

這個伎倆。謝謝! – 2010-09-16 01:34:35

1

實際上,可以更準確地說,當您試圖集中它時文本框還未呈現。 WPF的核心就像是一個消息泵,就像WinForms一樣,但它是一個更先進的--Dispatcher。分派器用於對工作進行排隊 - 當隊列中的消息根據其優先級進行處理時,您觸發的某些操作稍後將在同一個線程上執行。 BeginInvoke隊列分派器隊列上的另一個工作項目,並在首先需要的其他項目之後執行。

這是一個非常黑客的解釋,我鼓勵你閱讀更多關於它 - 只需谷歌WPF調度和閱讀任何噸的文章,大多數都非常好。

編輯:另外,在你的情況下處理好事件將是文本框的Loaded事件;通常只有在所有其他佈局工作完成並且控件實際可見後纔會觸發Loaded事件。但是,在Dispatcher上排隊項目也是處理事情的好方法。

+0

感謝您的好解釋。實際上,TextBox(和父級StackPanel)作爲UserControl的一部分加載並初始設置爲Collapsed; Loaded事件在我的情況下不起作用。但是,將焦點設置在TextBox的IsVisibleChanged上的確有用。 – 2010-09-16 01:36:33

相關問題