2009-06-23 10 views
6

Estoy tratando de implementar la funcionalidad de arrastrar y soltar en una aplicación de superficie que se genera utilizando el patrón MVVM. Estoy luchando para encontrar un medio para implementar esto mientras me adhiero al patrón MVVM. Aunque estoy tratando de hacer esto dentro de una Aplicación de Superficie, creo que la solución es lo suficientemente general como para aplicarla también a WPF.Arrastrar y soltar en MVVM con ScatterView

Estoy tratando de producir las siguientes funcionalidades:

  • contactos del usuario FrameworkElement dentro de un ScatterViewItem para comenzar una operación de arrastre (una parte específica de la ScatterViewItem inicia el arrastrar/soltar funcionalidad)
  • Cuando la operación de arrastre comienza una copia de ese ScatterViewItem se crea e impone sobre el ScatterViewItem original, la copia es lo que el usuario arrastrará y finalmente soltará
  • El usuario puede colocar el elemento en otro ScatterViewItem (ubicado en un ScatterView por separado)

La interacción general es bastante similar a la aplicación ShoppingCart proporcionada en Surface SDK, excepto que los objetos fuente están contenidos en un ScatterView en lugar de un ListBox.

No estoy seguro de cómo proceder para habilitar la comunicación adecuada entre mis ViewModels con el fin de proporcionar esta funcionalidad. El problema principal que he encontrado es replicar ScatterViewItem cuando el usuario contacta con FrameworkElement.

+0

¿Hay alguna posibilidad de ver algún código? ¿Cómo ScatterViewItems contiene controles para niños? ¿Cómo lo vinculan a un modelo de vista? –

+0

Trataré de proporcionar una respuesta 'real' más tarde, pero básicamente una operación de arrastrar y soltar ocurre principalmente en las vistas.El hecho de que esté ocurriendo un arrastre probablemente no requiera ninguna comunicación con el modelo de vista de la vista original hasta que ocurra la caída. Cuando se detecta la caída, puede llamar a un método o ejecutar un comando en su modelo de vista y pasar la información sobre lo que se eliminó. La máquina virtual lo agregaría a una lista que está vinculada a su vista de dispersión de destino. La vista de origen también debe procesar la llamada completada y pasarla a su modelo de vista. –

Respuesta

4

Puede usar una propiedad adjunta. Crear una propiedad adjunta y en el método bind setproperty al evento Droped:


public static void SetDropCommand(ListView source, ICommand command) 
     { 
      source.Drop += (sender, args) => 
           { 
            var data = args.Data.GetData("FileDrop"); 
            command.Execute(data); 
           }; 
     } 

A continuación, se puede unir un comando en su modelo de vista con el control correspondiente en la vista. Obviamente, es posible que desee hacer que su propiedad adjunta se aplique a su tipo de control específico en lugar de una vista de lista.

Espero que ayude.

2

He intentado hacer funcionar la idea de Steve Psaltis. Tomó un tiempo: las propiedades de dependencia personalizadas son fáciles de equivocarse. Me parece que el SetXXX es el lugar equivocado para poner sus efectos secundarios, WPF no tiene que pasar, puede ir directamente al DependencyObject.SetValue, pero siempre se llamará al PropertyChangedCallback.

tanto, aquí está completa y trabajando el código de la propiedad especializado adjunto:

using System.Windows; 
using System.Windows.Input; 

namespace WpfApplication1 
{ 
    public static class PropertyHelper 
    { 
     public static readonly DependencyProperty DropCommandProperty = DependencyProperty.RegisterAttached(
      "DropCommand", 
      typeof(ICommand), 
      typeof(PropertyHelper), 
      new PropertyMetadata(null, OnDropCommandChange)); 

     public static void SetDropCommand(DependencyObject source, ICommand value) 
     { 
      source.SetValue(DropCommandProperty, value); 
     } 

     public static ICommand GetDropCommand(DependencyObject source) 
     { 
      return (ICommand)source.GetValue(DropCommandProperty); 
     } 

     private static void OnDropCommandChange(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      ICommand command = e.NewValue as ICommand; 
      UIElement uiElement = d as UIElement; 
      if (command != null && uiElement != null) 
      { 
       uiElement.Drop += (sender, args) => command.Execute(args.Data); 
      } 

      // todo: if e.OldValue is not null, detatch the handler that references it 
     } 
    } 
} 

en el marcado XAML en la que desea utilizar esto, se puede hacer, por ejemplo,

xmlns:local="clr-namespace:WpfApplication1" 
... 
<Button Content="Drop here" Padding="12" AllowDrop="True" 
    local:PropertyHelper.DropCommand="{Binding DropCommand}" /> 

.. Y el resto es solo asegurarse de que su ViewModel, enlaces y comando son correctos.

Esta versión pasa un IDataObject a través del comando que me parece mejor, puede consultarlo en busca de archivos o lo que sea en el comando. Pero eso es solo una preferencia actual, no una característica esencial de la respuesta.