wpf - Arrastrar y soltar en MVVM con ScatterView
drag-and-drop pixelsense (2)
Estoy intentando implementar la funcionalidad de arrastrar y soltar en una aplicación de superficie que se construye 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.
Estoy tratando de producir la siguiente funcionalidad:
- El usuario contacta con FrameworkElement dentro de ScatterViewItem para comenzar una operación de arrastre (una parte específica del ScatterViewItem inicia la funcionalidad de arrastrar / soltar)
- 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 en última instancia caerá
- El usuario puede colocar el elemento en otro ScatterViewItem (colocado 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 dentro de un ScatterView en lugar de un ListBox.
No estoy seguro de cómo proceder para habilitar la comunicación adecuada entre mis ViewModels para proporcionar esta funcionalidad. El problema principal que he encontrado es replicar ScatterViewItem cuando el usuario contacta con FrameworkElement.
Puede usar una propiedad adjunta. Cree una propiedad adjunta y en el método setproperty, vincule al evento droped:
public static void SetDropCommand(ListView source, ICommand command)
{
source.Drop += (sender, args) =>
{
var data = args.Data.GetData("FileDrop");
command.Execute(data);
};
}
Luego puede vincular un comando en su modelo de vista al control relevante de 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.
Intenté que funcionara 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 tus efectos secundarios: WPF no tiene que ir allí, puede ir directamente a DependencyObject.SetValue
, pero se llamará a PropertyChangedCallback
.
Por lo tanto, aquí está completo y funciona el código para la propiedad adjunta personalizada:
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 donde desea utilizar esto, 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 simplemente asegurarse de que su ViewModel, enlaces y comando es correcto.
Esta versión IDataObject
un IDataObject
al 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.