2011-07-20 10 views
20

Piszę niestandardowy formant i chciałbym, aby formant przełączył stan edycji na normalny stan, gdy użytkownik kliknie poza formant. Zajmuję się zdarzeniem LostFocus i to pomaga, gdy użytkownik odsuwa się lub klika na inną kontrolkę, która może być ustawiana. Ale jeśli nie klikną na coś, co można ustawić, nie będzie to miało wpływu na stan edycji. Mam więc dwa rozwiązania na uwadze:W jaki sposób sterowanie może obsługiwać kliknięcie myszą poza tym sterowaniem?

  • Podejdź do drzewa na górę większości elementu, gdy idzie się do stanu edycji i dodać do obsługi MouseDownEvent (i uchwyt „obchodzić” wydarzenia). W programie obsługi wykopię sterowanie ze stanu edycji i usunę moduł obsługi z najbardziej elementowego elementu. Wydaje się to być trochę hackerem, ale prawdopodobnie działałoby dobrze.

Przykładowy kod:

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; 
} 
  • Zastosowanie Mouse.PreviewMouseDownOutsideCapturedElement i dodać do obsługi moją kontrolą. W programie obsługi wykopię kontrolę ze stanu edycji. Ale wydaje mi się, że nie wyda się tego wydarzenia. Kiedy wyskoczy Mouse.PreviewMouseDownOutsideCapturedElement?

Przykład Kod:

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

Odpowiedz

12

przechwytywania myszy. Gdy obiekt przechwytuje myszkę, wszystkie zdarzenia związane z myszką są traktowane tak, jakby obiekt z przechwytywaniem myszy wykonał zdarzenie, nawet jeśli wskaźnik myszy znajduje się nad innym obiektem.

+2

To zadziałało idealnie. Jedyne, co musiałem zrobić, to Przechwyć mysz, kiedy wszedłem do trybu edycji, a następnie WPF automatycznie odciąża obiekt od elementu po kliknięciu poza nim. Po tym, jak straciłem ostrość, musiałem tylko uważać na ReleaseMouseCapture(). Dzięki! – chrislarson

+3

Jedyną rzeczą, na którą musiałem uważać, było to, że po naciśnięciu klawisza Windows lub uruchomieniu innej aplikacji straciłbym przechwytywanie myszy bez zatrzymania kontroli nad stanem edycji. Musiałem więc obsłużyć zdarzenie IsMouseCapturedChanged. Np. 'Private void CustomControlIsMouseCapturedChanged (obiekt nadawca, DependencyPropertyChangedEventArgs e) { if ((bool) e.NewValue == false) { IsEditing = false; } } ' – chrislarson

0

Podejdę do tego w inny sposób - jeśli formularz zawiera kontrolkę, usuń z niej kontrolę, gdy użytkownik kliknie inną część formularza.

Luźne ognisko jest luźniejsze niż próba skupienia się na "symulowaniu" ostrości w określonych sytuacjach, gdy tak naprawdę nie jest. Pamiętaj, że jeśli kontroler naprawdę nie stracił ostrości, nadal będzie akceptował takie rzeczy jak wprowadzanie danych z klawiatury.

+0

Czyli mówisz, że nadaję formę, aby można ją było skupić? Ponieważ fokus nie zostanie automatycznie usunięty, chyba że zostanie przesunięty na inny element, prawda? Na przykład nie będzie to koncentrować się na TextBox: ' \t \t \t \t ' – chrislarson

+0

@chrislarson Możesz ustawić inną kontrolę (na przykład etykietę, prawdopodobnie bez tekstu), aby ustawić ostrość - patrz [Czy istnieje sposób, aby element interfejsu uległ utracie] (http://stackoverflow.com/questions/ 2664460/wpf-is-there-a-way-to-cause-an-ui-element-to-loose-focus-without-changing-the-fo) – Justin

+0

To na pewno w porządku ze mną, wciąż mogę tylko bazować, czy nie kontrola jest w stanie edycji, czy ma fokus, czy nie. Ale nadal potrzebuję sposobu, aby niezawodnie utracić kontrolę, gdy użytkownik kliknie poza kontrolą. – chrislarson

30

Wystarczy, aby wyjaśnić odpowiedź przewidzianego o naciskiem myszki - to było przydatne, ale musiałem zrobić jakieś dalsze kopanie + mucking dostać coś, co faktycznie przepracowanych:

starałem się zaimplementować coś jak combobox i potrzebne podobne zachowanie - aby zejście w dół zniknęło po kliknięciu w coś innego, a kontrola nie miała wiedzy o czymś innym.

miałem następujące zdarzenie dla rozwijanej listy:

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

CaptureMode.SubTree oznacza, że ​​otrzymasz zdarzenia, które są poza kontrolą i jakiejkolwiek aktywności myszy w kontroli jest przekazywana wyłącznie za pośrednictwem rzeczy jak normalny . Nie masz możliwości dostarczenia tej Enum w CaptureMouse UIElementa, oznacza to, że otrzymasz połączenia do HandleClickOutsideOfControl INSTEAD połączeń z dowolnymi kontrolkami podrzędnymi lub innymi kontrolerami w ramach kontroli. Dzieje się tak nawet wtedy, gdy nie subskrybujesz zdarzeń, których używają - pełne przechwytywanie myszą to trochę za dużo!

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

będzie też trzeba powiesić na + wyjąć obsługi w odpowiednich punktach, ale zostawiłem że tu dla zachowania jasności/zwięzłości.

Wreszcie w programie obsługi należy ponownie zwolnić przechwytywanie.

+7

Niektóre kontrolki, takie jak TextBox, wydają się powodować caputre po kliknięciu, więc będziesz musiał ponownie dołączyć handler za każdym razem, gdy kontrola wzrośnie 'LostMouseCapture' zdarzenia. Tylko moja obserwacja. –

0

Zwykle uzyskuję okno nadrzędne i dodaje obsługę podglądu, nawet jeśli jest już obsługiwane. Czasami, gdy MouseCapture nie wystarcza, ta technika jest przydatna:

Window.GetWindow(this).AddHandler 
(
    UIElement.MouseDownEvent, 
    (MouseButtonEventHandler)TextBox_PreviewMouseDown, 
    true 
);