2011-07-20 30 views
20

我正在寫一個自定義控件,並且希望控件在用戶單擊控件時從編輯狀態切換到正常狀態。我正在處理LostFocus事件,這有助於當用戶退出或者他們點擊另一個Focusable控件時。但是如果他們沒有點擊Focusable,它將不會退出編輯狀態。所以我心裏有兩個解決方案:控件如何處理鼠標在該控件之外的點擊?

  • 走到樹最頂端的元素,當它進入到編輯狀態,並添加一個處理MouseDownEvent(和處理「處理」事件)。在處理程序中,我會將控制權踢出編輯狀態,並從最上面的元素中移除處理程序。這似乎有點破解,但它可能會運行良好。

示例代碼:

private void RegisterTopMostParentMouseClickEvent() 
{ 
    _topMostParent = this.FindLastVisualAncestor<FrameworkElement>(); 
    if (_topMostParent == null) 
     return; 
    _topMostParent.AddHandler(Mouse.MouseDownEvent, new MouseButtonEventHandler(CustomControlMouseDownEvent), true); 
} 

private void UnRegisterTopMostParentMouseClickEvent() 
{ 
    if (_topMostParent == null) 
     return; 
    _topMostParent.RemoveHandler(Mouse.MouseDownEvent, new MouseButtonEventHandler(CustomControlMouseDownEvent)); 
    _topMostParent = null; 
} 
  • 使用Mouse.PreviewMouseDownOutsideCapturedElement,並添加一個處理程序我的控制。在處理程序中,我會將控制權踢出編輯狀態。但我似乎沒有得到事件的火力。 Mouse.PreviewMouseDownOutsideCapturedElement何時被啓動?

示例代碼:

AddHandler(Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(EditableTextBlockPreviewMouseDownOutsideCapturedElementEvent), true); 

回答

12

捕獲鼠標。 當一個對象捕獲鼠標時,即使鼠標指針位於另一個對象上,所有與鼠標相關的事件也會被視爲具有鼠標捕獲的對象執行該事件。

+2

所以這個工作很完美。我所要做的只是在進入編輯模式時捕捉鼠標,然後當點擊它之外時,WPF會自動將焦點從元素上移開。在失去焦點後,我只需要小心ReleaseMouseCapture()。謝謝! – chrislarson

+3

我唯一需要注意的其他事情是,當您按下Windows鍵或其他應用程序啓動時,我將失去鼠標捕捉而不停止我的控件進入編輯狀態。所以我不得不處理IsMouseCapturedChanged事件。例如,private void CustomControlIsMouseCapturedChanged(object sender,DependencyPropertyChangedEventArgs e) if((bool)e.NewValue == false) IsEditing = false; } }' – chrislarson

0

我會採取這種不同的方式 - 當用戶單擊窗體的另一部分時,將包含控件的窗體從控件中移除焦點。

擁有控制實際上鬆散的焦點遠比在某些情況下試圖讓控制「模擬」焦點丟失時更清潔,而事實上它沒有。請記住,除非控件真的失去了焦點,否則它仍然會接受鍵盤輸入之類的東西。

+0

那麼你是說我讓表單可以聚焦?因爲焦點不會被自動帶走,除非它被轉移到另一個元素,對嗎?例如,這不會從TextBox獲得焦點:' \t \t \t \t ' – chrislarson

+0

@chrislarson你可以設置另一個控件(例如一個標籤,可能是一個沒有文本的標籤)來關注 - 請參閱[是否有一種方法來導致UI元素失去焦點](http://stackoverflow.com/questions/) 2664460/wpf-is-there-a-way-to-cause-an-ui-element-to-loose-focus-without-changing-the-fo) – Justin

+0

這對我來說確實很好,我仍然可以基於不是控件處於編輯狀態,而是由它是否具有焦點。但是我仍然需要一種方式來可靠地讓用戶在控制之外點擊時失去焦點。 – chrislarson

30

只是爲了澄清提供了關於鼠標焦點的答案 - 這是有用的,但我不得不做一些進一步的挖掘+瞎得到的東西,實際工作:

我想實現像一個組合框,需要類似的行爲 - 當點擊其他某些東西時,讓這個下拉消失,而沒有控制知道其他東西是什麼。

我有一個下拉按鈕在以下事件:

private void ClickButton(object sender, RoutedEventArgs routedEventArgs) 
    { 
     //do stuff (eg activate drop down) 
     Mouse.Capture(this, CaptureMode.SubTree); 
     AddHandler(); 
    } 

的CaptureMode.SubTree意味着你只能得到是控制和控制任何鼠標活動以外發生的事件是通過傳遞到事情正常。你沒有在UIElement的CaptureMouse中提供這個枚舉的選項,這意味着你將會調用HandleClickOutsideOfControl INSTEAD來調用控件中的任何子控件或其他處理程序。即使您不訂閱他們正在使用的事件,情況也是如此 - 完全鼠標捕捉有點太過分了!

private void AddHandler() 
    { 
     AddHandler(Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(HandleClickOutsideOfControl), true); 
    } 

您還需要掛到+刪除的處理程序在適當的點,但我已經離開了這一點這裏清晰/簡潔起見。

最後在處理程序中,您需要再次釋放捕獲。

private void HandleClickOutsideOfControl(object sender, MouseButtonEventArgs e) 
    { 
     //do stuff (eg close drop down) 
     ReleaseMouseCapture(); 
    } 
+7

像TextBox這樣的一些控件傾向於在點擊時釋放caputre,所以每次控制上升'LostMouseCapture'事件時你都必須重新附加處理程序。只是我的觀察。 –

0

我通常會得到父窗口,並添加一個預覽處理程序,即使已經處理。有時,當鼠標捕捉不夠時,這種技術很方便:

Window.GetWindow(this).AddHandler 
(
    UIElement.MouseDownEvent, 
    (MouseButtonEventHandler)TextBox_PreviewMouseDown, 
    true 
); 
相關問題