2009-05-15 8 views
5

Estoy tratando de usar el patrón MVVM por primera vez. Así que tengo un ItemsControl lleno con mis objetos viewmodel, que se muestran usando DataTemplate; los objetos son "nodos" y "bordes" representados en DataTemplate con objetos Thumb y Polyline y quiero poder detectar clics y arrastres en el ItemsControl para mover los nodos y los bordes.WPF: cómo adjuntar eventos de mouse a un modelo de vista?

dos preguntas:

  • ¿Cómo adjunto controladores de eventos de ratón a los Polyline 's y Thumb' s para ser manejado por los pequeños ViewModels? (Podría adjuntar un controlador de Thumb.DragDelta a los ItemsControl y e.OriginalSource puntos a la Thumb, pero ¿cómo puedo obtener el objeto de modelo de vista correspondiente?)
  • ¿Cómo adjunto controladores de eventos del ratón al ItemsControl para detectar clics del ratón y arrastra el espacio en blanco ? (la respuesta es más abajo)

Nota: Sé que podría no considerarse un ViewModel adecuado si se trata directamente de eventos de la Vista. Pero el punto importante es que necesito manejar los eventos del mouse y no estoy seguro de cómo adjuntarlos.

Respuesta

2

Descubrí la respuesta a la segunda pregunta. Necesitaba un ItemsControl que admitiera el desplazamiento, y necesitaba tener los elementos en un Grid en lugar del StackPanel predeterminado. Para cumplir ambos requisitos, utilicé 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"/> 

el fin de obtener los eventos del ratón con coordenadas significativas de ratón (es decir, las coordenadas en el espacio de desplazamiento), era necesario para obtener una referencia a la red usando un extraño encantamiento:

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

a continuación, asociar controladores de eventos a la red, y dentro de los controladores de eventos de ratón, obtener las coordenadas del ratón wRT la red usando

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

el fin de obtener los eventos del ratón sobre toda la superficie, el control (en realidad la red) debe tener un fondo, por lo que establecer Antecedentes = "amarillo claro" anterior, que se propaga a la red a través de una vinculante en ControlTemplate.

6

Encontré una forma de manejar eventos generados por objetos en el DataTemplate.

(1) asociar controladores de eventos a ItemsControl

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

(2) para averiguar qué elemento del evento se aplica a, el tratamiento de la OriginalSource como FrameworkElement, y obtener su 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 para hacer cosas. – Ant

1

Hay formas de hacerlo sin código subyacente ...

podría utilizar el patrón de comportamiento adjunto para mapear los eventos a los comandos, consulte la aplicación de Marlon Grech here

También es posible usar un markup extension que escribí para unirse InputBindings a los comandos de modelo de vista, así:

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

Sin embargo, no estoy seguro de que se ajuste a sus necesidades específicas ...

+0

No lo creo, ya que esta es una interfaz gráfica para crear y mover objetos gráficos, así que necesito las coordenadas del mouse, y necesito mostrar los comentarios mientras el arrastre está en progreso. – Qwertie

3

El ViewModel debe estar desconectado de la GUI, por lo que no sabe nada sobre controles o mouseclicks.

Dos opciones:

  • llamar a un comando en el ViewModel, según lo sugerido por Thomas
  • Enlazar la posición del pulgar a una propiedad en el modelo de vista, entonces, cuando los movimientos de control alrededor de WPF cuando actualizará los valores de posición en ViewModel.
+0

Veo, ¿cómo harías un movimiento de pulgar por sí mismo? – Qwertie

+0

Consulte http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part1.aspx para ver un ejemplo de cómo hacer un control de pulgar móvil. –

+0

Ese proyecto simplemente mueve los pulgares en el código subyacente manejando el evento DragDelta. – Qwertie

1

Bea Stollnitz tiene un ejemplo de arrastrar y soltar titulado "¿Cómo puedo arrastrar y soltar elementos entre ItemsControls enlazados a datos?". Publicaba el enlace, pero StackOverflow no me deja.

Es posible que desee dividir la retroalimentación de la UI mientras se está arrastrando y la acción se lleva a cabo cuando finalmente se descarta.

Estoy de acuerdo con Thomas y Cameron anteriormente, sin embargo. Querrá limitar la mezcla/coincidencia de manejo de eventos y enlace de datos. Si va a la ruta de manejo de eventos, puede que no desee evitar el uso del término "Ver modelo" para sus objetos, ya que generalmente denota la alternativa de enlace de datos.

+0

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

+0

Esto no es realmente útil para mí, ¡pero gracias por el interesante artículo! – Qwertie

0

Estoy usando un método mucho más elegante. Yo uso Prism 2 y datatemplates. Entonces lo que he hecho es esto:

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

y en el ItemTemplate Acabo de crear un botón en el interior!

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