Skip to content

Instantly share code, notes, and snippets.

@mfakane
Created September 6, 2011 09:51
Show Gist options
  • Save mfakane/1197150 to your computer and use it in GitHub Desktop.
Save mfakane/1197150 to your computer and use it in GitHub Desktop.
ListBox などの項目のドラッグアンドドロップ移動のビヘイビア
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace Ignition.Presentation
{
public class DragDropBehavior : Behavior<Selector>
{
readonly CompositeDisposable observer = new CompositeDisposable();
protected override void OnAttached()
{
observer.Add(Observable.FromEvent<MouseButtonEventHandler, MouseButtonEventArgs>(_ => (sender, e) => _(e), _ => this.AssociatedObject.PreviewMouseDown += _, _ => this.AssociatedObject.PreviewMouseDown -= _)
.Where(_ => _.LeftButton == MouseButtonState.Pressed && this.AssociatedObject.ContainerFromElement((DependencyObject)_.OriginalSource) != null)
.Select(_ => _.GetPosition(this.AssociatedObject))
.SelectMany(pt => Observable.FromEvent<MouseEventHandler, MouseEventArgs>(_ => (sender, e) => _(e), _ => this.AssociatedObject.PreviewMouseMove += _, _ => this.AssociatedObject.PreviewMouseMove -= _)
.TakeUntil(Observable.FromEvent<MouseButtonEventHandler, MouseButtonEventArgs>(_ => (sender, e) => _(e), _ => this.AssociatedObject.PreviewMouseUp += _, _ => this.AssociatedObject.PreviewMouseUp -= _))
.Select(_ => new
{
Items = this.AssociatedObject.Items.Cast<object>().Select(i => new
{
Container = this.AssociatedObject.ItemContainerGenerator.ContainerFromItem(i),
Item = i
}).Where(i => Selector.GetIsSelected(i.Container)).Select(i => i.Item).ToArray(),
Vector = pt - _.GetPosition(this.AssociatedObject),
})
.Where(_ => Math.Abs(_.Vector.X) > SystemParameters.MinimumHorizontalDragDistance || Math.Abs(_.Vector.Y) > SystemParameters.MinimumVerticalDragDistance)
.Take(1))
.Subscribe(e =>
{
using (Observable.FromEvent<DragEventHandler, DragEventArgs>(_ => (sender, e2) => _(e2), _ => this.AssociatedObject.Drop += _, _ => this.AssociatedObject.Drop -= _)
.Where(_ => _.Data.GetDataPresent(typeof(DragDropInfo)))
.Select(_ => new
{
EventArgs = _,
Data = (DragDropInfo)_.Data.GetData(typeof(DragDropInfo)),
})
.Subscribe(p =>
{
var list = this.AssociatedObject.ItemsSource as IList ?? this.AssociatedObject.Items;
var item = list.Cast<object>().Select((_, i) => new
{
Container = _ as FrameworkElement ?? (FrameworkElement)this.AssociatedObject.ItemContainerGenerator.ContainerFromIndex(i),
Item = _,
})
.Where(_ => _.Container != null)
.LastOrDefault(_ => VisualTreeHelper.HitTest(_.Container, p.EventArgs.GetPosition(_.Container)) != null);
if (item == null)
foreach (var i in p.Data.Items)
{
list.Remove(i);
list.Add(i);
}
else
foreach (var i in p.Data.Items.Where(_ => _ != item.Item && !object.Equals(_, item.Item)))
{
list.Remove(i);
list.Insert(list.IndexOf(item.Item), i);
}
}))
{
var ad = this.AssociatedObject.AllowDrop;
this.AssociatedObject.AllowDrop = true;
DragDrop.DoDragDrop(this.AssociatedObject, new DragDropInfo(e.Items), DragDropEffects.Move);
this.AssociatedObject.AllowDrop = ad;
}
}));
base.OnAttached();
}
protected override void OnDetaching()
{
observer.Dispose();
base.OnDetaching();
}
class DragDropInfo
{
public IEnumerable<object> Items
{
get;
private set;
}
public DragDropInfo(IEnumerable<object> items)
{
this.Items = items;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment