W aplikacji WPF korzystającej z MVVM mam kontrolę użytkownika z elementem widoku listy. W czasie wykonywania użyje wiązania danych, aby wypełnić widok listy kolekcją obiektów.
Jaki jest prawidłowy sposób dołączenia zdarzenia dwukrotnego kliknięcia do elementów w widoku listy, tak aby po dwukrotnym kliknięciu elementu w widoku listy odpowiadające mu zdarzenie w modelu widoku było uruchamiane i miało odniesienie do klikniętego elementu?
Jak można to zrobić w czysty sposób MVVM, tj. Bez kodu w widoku?
Jestem w stanie zmusić to do pracy z .NET 4.5. Wydaje się proste i nie są potrzebne żadne strony trzecie ani kod.
źródło
InputBindings
są dostępne w .NET 3.0 i nie są dostępne w Silverlight.Lubię korzystać z zachowań i poleceń dołączonych poleceń. Marlon Grech ma bardzo dobrą implementację zachowań Attached Command. Korzystając z nich, możemy następnie przypisać styl do właściwości ItemContainerStyle elementu ListView, która ustawi polecenie dla każdego ListViewItem.
Tutaj ustawiamy polecenie, które ma być uruchamiane po zdarzeniu MouseDoubleClick, a CommandParameter będzie obiektem danych, na który klikamy. Tutaj podróżuję po drzewie wizualnym, aby uzyskać polecenie, którego używam, ale równie łatwo możesz utworzyć polecenia dotyczące całej aplikacji.
W przypadku poleceń możesz zaimplementować ICommand bezpośrednio lub użyć niektórych pomocników, takich jak te, które znajdują się w zestawie narzędzi MVVM .
źródło
acb:
= AttachedCommandBehavior. Kod można znaleźć w pierwszym linku w odpowiedziZnalazłem bardzo łatwy i czysty sposób na zrobienie tego za pomocą wyzwalaczy zdarzeń Blend SDK. Czysty MVVM, wielokrotnego użytku i bez kodu źródłowego.
Prawdopodobnie masz już coś takiego:
Teraz dołącz ControlTemplate dla ListViewItem w ten sposób, jeśli jeszcze go nie używasz:
GridViewRowPresenter będzie wizualnym korzeniem wszystkich elementów „wewnątrz” tworzących element wiersza listy. Teraz możemy wstawić tam wyzwalacz, aby szukać zdarzeń kierowanych przez MouseDoubleClick i wywołać polecenie za pośrednictwem InvokeCommandAction w następujący sposób:
Jeśli masz elementy wizualne „nad” GridRowPresenter (prawdopodobnie zaczynając od siatki), możesz również umieścić tam wyzwalacz.
Niestety zdarzenia MouseDoubleClick nie są generowane z każdego elementu wizualnego (pochodzą z Controls, ale nie na przykład z FrameworkElements). Sposób obejścia problemu polega na wyprowadzeniu klasy z EventTrigger i wyszukaniu MouseButtonEventArgs z wartością ClickCount równą 2. To skutecznie odfiltrowuje wszystkie zdarzenia inne niż MouseButtonEvents i wszystkie zdarzenia MoseButtonEvents z wartością ClickCount! = 2.
Teraz możemy napisać to ('h' to przestrzeń nazw powyższej klasy pomocniczej):
źródło
Zdaję sobie sprawę, że ta dyskusja ma już rok, ale czy w przypadku .NET 4 są jakieś przemyślenia na temat tego rozwiązania? Absolutnie zgadzam się, że celem MVVM NIE jest eliminacja kodu związanego z plikiem. Czuję też bardzo mocno, że to, że coś jest skomplikowane, nie oznacza, że jest lepiej. Oto, co umieściłem w kodzie:
źródło
Możesz użyć funkcji Action Caliburn do mapowania zdarzeń na metody w Twoim ViewModel. Zakładając, że masz
ItemActivated
metodę na swojejViewModel
, odpowiedni kod XAML wyglądałby następująco:Aby uzyskać więcej informacji, zapoznaj się z dokumentacją i próbkami Caliburn.
źródło
Wydaje mi się, że łatwiej jest połączyć polecenie podczas tworzenia widoku:
W moim przypadku
BindAndShow
wygląda to tak (kontrola aktualizacji + avalondock):Chociaż podejście powinno działać z dowolną metodą otwierania nowych widoków.
źródło
Widziałem rozwiązanie z rushui z InuptBindings, ale nadal nie byłem w stanie trafić w obszar ListViewItem, w którym nie ma tekstu - nawet po ustawieniu tła na przezroczyste, więc rozwiązałem to za pomocą różnych szablonów.
Ten szablon jest przeznaczony dla sytuacji, gdy ListViewItem został wybrany i jest aktywny:
Ten szablon jest używany, gdy ListViewItem został wybrany i jest nieaktywny:
To jest domyślny styl używany dla ListViewItem:
To, co mi się nie podoba, to powtarzanie TextBlock i jego wiązanie tekstu, nie wiem, czy mogę obejść się, deklarując, że tylko w jednym miejscu.
Mam nadzieję, że to komuś pomoże!
źródło
listviewitem
, prawdopodobnie nie obchodzi go, czy jest już zaznaczony, czy nie. Należy również zauważyć, że efekt podświetlenia może również wymagać dostosowania, aby pasował dolistview
stylu. Głosowano za.Udało mi się stworzyć tę funkcjonalność z frameworkiem .Net 4.7 przy użyciu biblioteki interaktywności, przede wszystkim upewnij się, że zadeklarowałem przestrzeń nazw w pliku XAML
Następnie ustaw wyzwalacz zdarzenia z jego odpowiednim InvokeCommandAction wewnątrz ListView, jak poniżej.
Widok:
Dostosowanie powyższego kodu powinno wystarczyć, aby zdarzenie dwukrotnego kliknięcia działało na Twoim ViewModel, jednak dodałem Ci klasę Model i View Model z mojego przykładu, abyś miał pełny pomysł.
Model:
Zobacz model:
Na wypadek, gdybyś potrzebował implementacji klasy DelegateCommand .
źródło
Oto zachowanie, które robi to na obu
ListBox
iListView
.Oto klasa rozszerzenia używana do znalezienia rodzica.
Stosowanie:
źródło