2009-05-15 15 views
5

Próbuję użyć wzorca MVVM po raz pierwszy. Tak więc mam obiekt ItemsControl wypełniony moimi obiektami widoku, wyświetlane przy użyciu DataTemplate; obiekty to "węzły" i "krawędzie" reprezentowane przez obiekty i Polyline i chcę być w stanie wykryć kliknięcia i przeciągnięcia na ItemsControl w celu przesunięcia węzłów i krawędzi.WPF: Jak dołączać zdarzenia myszy do viewmodelu?

dwa pytania:

  • Jak mogę dołączyć obsługi zdarzeń myszy do Polyline 's oraz Thumb' s być obsługiwane przez małe ViewModels? (Mogę dołączyć Thumb.DragDelta obsługi do ItemsControl i e.OriginalSource punktów do Thumb, ale w jaki sposób mogę uzyskać odpowiedni obiekt ViewModel?)
  • Jak mogę dołączyć myszy obsługi zdarzeń do ItemsControl do wykrywania kliknięć myszką i ciągnie na puste miejsce ? (odpowiedź jest poniżej)

Uwaga: Wiem, że może to nie być odpowiedni ViewModel, jeśli bezpośrednio obsługuje zdarzenia z widoku. Ważne jest jednak to, że muszę obsługiwać zdarzenia myszy i nie jestem pewien, jak je dołączyć.

Odpowiedz

2

Ułożyłem odpowiedź na drugie pytanie. Potrzebowałem elementu ItemsControl, który obsługuje przewijanie, a ja potrzebowałem elementów na siatce zamiast domyślnego StackPanel. Aby spełnić wymagania zarówno użyłem ControlTemplate:

<!--In the resources...--> 
<ControlTemplate x:Key="GraphTemplate" TargetType="ItemsControl"> 
    <ScrollViewer Name="ScrollViewer" 
        Padding="{TemplateBinding Padding}" 
        HorizontalScrollBarVisibility="Auto"> 
     ... 
      <Grid Name="Panel" IsItemsHost="True" 
        Background="{TemplateBinding ItemsControl.Background}"/> 
     ... 
    </ScrollViewer> 
</ControlTemplate> 
<!--Later...--> 
<ItemsControl x:Name="_itemsControl" 
       ItemsSource="{Binding Items}" 
       Template="{StaticResource GraphTemplate}" 
       Background="LightYellow"/> 

W celu uzyskania zdarzeń myszy z sensownych współrzędnych myszy (tj współrzędne w przewijalnej przestrzeni), konieczne było uzyskać odwołanie do sieci przy użyciu dziwne zaklęcie:

Grid grid = (Grid)_itemsControl.Template.FindName("Panel", _itemsControl); 

Następnie dołączasz programy obsługi zdarzeń do siatki, a wewnątrz obsługi zdarzeń myszy uzyskasz współrzędne myszy. siatka użyciu

Point p = e.GetPosition((IInputElement)sender); 

w celu uzyskania zdarzeń myszy na całej powierzchni, kontrola (właściwie siatka) musi posiadać doświadczenie, więc mogę ustawić tło = „jasnożółte” powyżej, który rozchodzi się do sieci za pośrednictwem powiązanie w ControlTemplate.

6

Znalazłem sposób obsługi zdarzeń wywołanych przez obiekty w DataTemplate.

(1) dołączyć obsługi zdarzeń do ItemsControl

<ItemsControl x:Name="_itemsControl" 
       Thumb.DragStarted="Node_DragStarted" 
       Thumb.DragDelta="Node_DragDelta" 
       Thumb.DragCompleted="Node_DragCompleted" 
       MouseDoubleClick="OnMouseDoubleClick" 
       .../> 

(2), aby dowiedzieć się, który element zdarzenie dotyczy, traktować OriginalSource jako FrameworkElement i uzyskać jego DataContext:

void Node_DragStarted(object sender, DragStartedEventArgs e) 
{ 
    var os = (FrameworkElement)e.OriginalSource; 
    var vm = os.DataContext as ItemViewModel; 
    if (vm != null) 
     // do something with the item ViewModel 
} 
+2

+1 za wykonanie zadań. – Ant

1

Są sposoby na zrobienie tego bez kodem z tyłu ...

Można skorzystać z załączonego wzoru zachowań mapować zdarzeń do poleceń, patrz realizacja Marlon Grech za here

Można również użyć markup extension że napisałem do związania InputBindings do poleceń ViewModel coś takiego:

<UserControl.InputBindings> 
    <MouseBinding Gesture="LeftClick" Command="{input:CommandBinding SomeCommand}"/> 
</UserControl.InputBindings> 

Jednak nie jestem pewien, czy pasuje do twoich specyficznych potrzeb ...

+0

Nie sądzę, ponieważ jest to interfejs graficzny do tworzenia i przenoszenia obiektów graficznych, więc potrzebuję współrzędnych myszy i muszę wyświetlać informację zwrotną podczas przeciągania. – Qwertie

3

Model ViewModel powinien zostać odłączony od GUI, więc nie wie nic o kontrolkach ani kliknięciach myszki.

dwie opcje:

  • wezwać poleceń w ViewModel, jak sugeruje Thomas
  • Bind pozycja kciuka do właściwości w ViewModel, a następnie, gdy porusza się kontroli wokół WPF zaktualizuje wartości pozycji w ViewModel.
+0

Widzę, jak sam kciuk poruszyłby się? – Qwertie

+0

Zobacz http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part1.aspx, aby dowiedzieć się, jak wykonać ruchomy kciuk. –

+0

Ten projekt po prostu przesuwa kciuki z tyłu kodu, obsługując zdarzenie DragDelta. – Qwertie

1

Bea Stollnitz ma przykład "przeciągnij i upuść" zatytułowany "Jak przeciągać i upuszczać elementy między elementami ItemControls związanymi z danymi?". Opublikuję link, ale StackOverflow mi nie pozwala.

Może zajść potrzeba podzielenia informacji zwrotnej interfejsu użytkownika podczas przeciągania i czynności wykonanej po jej ostatecznym upuszczeniu.

Zgodziłbym się jednak z Thomasem i Cameronem powyżej. Będziesz chciał ograniczyć mieszanie/dopasowywanie obsługi zdarzeń i powiązania danych. Jeśli wybierasz ścieżkę obsługi zdarzeń, możesz nie chcieć unikać używania terminu "Wyświetl model" dla swoich obiektów, ponieważ na ogół oznacza to opcję wiążącą dane.

+0

Link: http://bea.stollnitz.com/blog/?p=53 – Qwertie

+0

To nie jest przydatne dla mnie, ale dzięki za interesujący artykuł! – Qwertie

0

Używam znacznie bardziej eleganckiej metody. Używam Prism 2 i datatemplates. Więc to, co zrobiłem, to:

<ItemsControl x:Name="SearchImagesList" ItemTemplate="{StaticResource SearchResultsAlbum}" 

aw ItemTemplate właśnie utworzyłem przycisk wewnątrz!

<DataTemplate x:Key="SearchResultsAlbum">       
    <Button CommandParameter="{Binding}"     
      Command="{Binding Source={x:Static PhotoBookPRMainModule:ServiceProvider.DesignEditorViewManager}, Path=NavigationCommands.NavigateSearchResultAction}"> 
Powiązane problemy