2009-05-15 8 views
5

Sto provando a utilizzare il pattern MVVM per la prima volta. Quindi ho uno ItemsControl pieno di oggetti viewmodel, visualizzati usando DataTemplate; gli oggetti sono "nodi" e "spigoli" rappresentati negli oggetti DataTemplate con Thumb e Polyline e voglio essere in grado di rilevare clic e trascinamenti sullo ItemsControl per spostare nodi e spigoli.WPF: come si collegano gli eventi del mouse a un modello view?

due domande:

  • Come posso allegare del mouse gestori di eventi per il 's e Thumb' Polyline s essere gestita dai piccoli ViewModels? (Ho potuto allegare un gestore Thumb.DragDelta alle ItemsControl e e.OriginalSource punti al Thumb, ma come faccio a ottenere l'oggetto ViewModel corrisponde?)
  • Come posso allegare del mouse gestori di eventi al ItemsControl per rilevare clic del mouse e si trascina spazio vuoto ? (risposta è sotto)

Nota: so che potrebbe non essere considerato un ViewModel corretto se gestisce direttamente gli eventi della vista. Ma il punto importante è che ho bisogno di gestire gli eventi del mouse e non sono sicuro di come collegarli.

risposta

2

Ho trovato la risposta alla seconda domanda. Avevo bisogno di un ItemsControl che supportava lo scrolling, e avevo bisogno di avere gli elementi su una griglia piuttosto che sullo StackPanel predefinito. Per adempiere entrambi i requisiti, ho usato un 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"/> 

Al fine di ottenere gli eventi del mouse con coordinate significative del mouse (cioè le coordinate nello spazio scorrevole), è stato necessario ottenere un riferimento alla griglia utilizzando uno strano incantesimo:

Quindi si collegano i gestori di eventi alla griglia e, all'interno dei gestori di eventi del mouse, si ottengono le coordinate del mouse. la griglia utilizzando

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

Per ottenere eventi del mouse su tutta la superficie, il controllo (in realtà griglia) deve avere un fondo, quindi impostare Sfondo = "lightyellow" sopra, che si propaga alla rete tramite un vincolante nel ControlTemplate.

6

Ho trovato un modo per gestire gli eventi generati dagli oggetti nel DataTemplate.

(1) collegare i gestori di eventi al ItemsControl

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

(2) per scoprire quale oggetto l'evento si applica a, trattare l'OriginalSource come un FrameworkElement, e ottenere la sua 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 per fare le cose. – Ant

1

Ci sono modi per farlo senza code-behind ...

è possibile utilizzare il modello di comportamento attaccato per mappare gli eventi ai comandi, vedere la realizzazione di Marlon Grech here

Si potrebbe anche usare un markup extension che ho scritto di legarsi InputBindings ai comandi ViewModel, in questo modo:

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

Tuttavia non sono sicuro che soddisfi le vostre esigenze specifiche ...

+0

Non credo, poiché si tratta di un'interfaccia grafica per la creazione e lo spostamento di oggetti grafici, quindi ho bisogno delle coordinate del mouse e ho bisogno di mostrare il feedback mentre il trascinamento è in corso. – Qwertie

3

ViewModel deve essere disconnesso dalla GUI, quindi non sa nulla di controlli o di mouse.

Due opzioni:

  • chiamare un comando nel ViewModel, come suggerito da Thomas
  • Bind la posizione del pollice a una proprietà nel ViewModel, poi quando il controllo si muove intorno WPF si aggiorneranno i valori di posizione nel ViewModel.
+0

Vedo, come faresti a muovere il pollice da solo? – Qwertie

+0

Controlla http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part1.aspx per un esempio di come rendere un controllo pollice mobile. –

+0

Questo progetto sposta semplicemente i pollici nel code-behind gestendo l'evento DragDelta. – Qwertie

1

Bea Stollnitz ha un esempio di trascinamento della selezione intitolato "Come posso trascinare elementi tra gli oggetti legati ai dati associati?". Pubblicherei il link, ma StackOverflow non mi lascia.

È possibile dividere il feedback dell'interfaccia utente mentre il trascinamento è in corso e l'azione eseguita quando viene infine interrotta.

Sarei d'accordo con Thomas/Cameron sopra, tuttavia. Dovrai limitare il mix/matching della gestione degli eventi e l'associazione dei dati. Se stai percorrendo il percorso di gestione degli eventi, potresti non voler evitare di utilizzare il termine "Visualizza modello" per i tuoi oggetti poiché generalmente indica l'alternativa di associazione dei dati.

+0

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

+0

Questo non è effettivamente utile per me, ma grazie per l'interessante articolo! – Qwertie

0

Sto usando un metodo molto più elegante. Io uso Prism 2 e datatemplates. Allora, cosa che ho fatto è questo:

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

e nel ItemTemplate ho appena creato un pulsante all'interno!

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