這是項目里的一個問題點,組里的同學在設置Focus事件時候,遇到了死鎖,最后StackOverFlow。
寫一個小例子
一個Textbox控件輸入值,一個TextBlock顯示結果,一個檢索Button
TextBox框里輸入一個ID,去系統里檢索一個值,把結果顯示在TextBlock里。
當查詢不到結果時候把焦點停留在TextBox里,當然觸發的條件有TextBox失去焦點時
和按檢索Button時。對於測試焦點的小例子,我們當然不用去連數據庫,寫個簡單的方法
如果輸入的值為【123】時候返回結果AAA,輸入其他以外的結果表示不存在,把焦點停留在
Textbox里
很多沒有同學開始寫的時候都會Button_Click方法和Textbox_LostFocus方法去實現自己
的代碼,Button_Click事件一點問題也沒有,但是LostFocus時候卻反生了異常終了,百思不得其解。
今天我們就來解決2個問題,為什么會不行?該怎么解決?
【原因】
請看一段
Private Shared Sub IsFocused_Changed(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs) Dim source As UIElement = DirectCast(d, UIElement) If CBool(e.NewValue) Then source.OnGotFocus(New RoutedEventArgs(UIElement.GotFocusEvent, source)) Else source.OnLostFocus(New RoutedEventArgs(UIElement.LostFocusEvent, source)) End If End Sub Public ReadOnly Property IsFocused As Boolean Get Return CBool(MyBase.GetValue(UIElement.IsFocusedProperty)) End Get End Property Friend Shared ReadOnly IsFocusedPropertyKey As DependencyPropertyKey = DependencyProperty.RegisterReadOnly("IsFocused", GetType(Boolean), GetType(UIElement), New PropertyMetadata(BooleanBoxes.FalseBox, New PropertyChangedCallback(AddressOf UIElement.IsFocused_Changed))) Public Custom Event LostFocus As RoutedEventHandler AddHandler(ByVal value As RoutedEventHandler) Me.AddHandler(UIElement.LostFocusEvent, value) End AddHandler RemoveHandler(ByVal value As RoutedEventHandler) Me.RemoveHandler(UIElement.LostFocusEvent, value) End RemoveHandler End Event
LostFocus事件沒有前置事件,所以不能e.Handled=True去控制,所以他被設置成一個只能執行的方法,擁有一個IsFocused的依賴屬性,當我們在寫代碼時候
前置寫方法Textbox1.Focus()時候,就造成LostFoucs事件沒有結束,還不能結束,進程互相等待,最后StackOverFLow
【解決方法】
1.替換事件
改用LostKeyBoardFocus事件。這個是在System.Windows.Input中完全是對於鍵盤事件的方法。當焦點完全離開對象時候,該事件才被觸發
所以把LostFocus的處理寫在LostKeyBoardFocus里就能解決上述問題
[SecurityCritical] private static void OnLostKeyboardFocusThunk(object sender, KeyboardFocusChangedEventArgs e) { Invariant.Assert(!e.Handled, "Unexpected: Event has already been handled."); UIElement uiElement = sender as UIElement; if (uiElement != null) { uiElement.OnLostKeyboardFocus(e); } else { ContentElement contentElement = sender as ContentElement; if (contentElement != null) contentElement.OnLostKeyboardFocus(e); else ((UIElement3D) sender).OnLostKeyboardFocus(e); } }
2.使用Dispatcher.BeginInvoke用異步的方法來更新
把更新Focus這件事放入UI進程的隊列中,等待前一處理結束后,進行設置
Private Sub TextBox1_LostFocus(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles TextBox1.LostFocus If Trim(TextBox1.Text).Equals("123") Then TextBlock2.Text = "AAA" Else TextBlock2.Text = String.Empty Me.Dispatcher.BeginInvoke(DispatcherPriority.Render, New Action(Sub() TextBox1.Focus())) End If End Sub