FrameworkElement GetAdornerRoot(DependencyObject d) { var ret = VisualTreeHelperExtension.Ancestors(d) .OfType <FrameworkElement>() .Reverse() .FirstOrDefault(x => AdornerLayer.GetAdornerLayer(x) != null); return(ret); }
// MouseEnter/Leaveの挙動とDragEnter/Leaveの挙動が違う...マウスキャプチャしてる関係と思われる // - トンネルしていくイベントの回数が違う Dragはいちいち構成要素のコントロールに対して発生する // - DragEnter/Leaveは1つのコントロールしかEnter状態にならない?(必ずLeaveしてから次にEnterしている) // MouseEnter/Leaveは複数のコントロールにEnterした状態になる // - スクロールの中にコントロールがある場合、DragEnter/Leaveを発生させずにBorderに出入りできてしまう // 中に入った時点でBorderからはLeaveしてるから? // じゃぁどうすればいいのか // DragOverは発火し続けるみたい // 未表示ならShowIndicator表示 // 未起動なら0.1秒タイマを起動 // 最後のDragOver時刻を更新 // => Tickで最後のDragOver時刻から0.1秒経過していたら閉じる private void OnPreviewDragOver(object sender, DragEventArgs e) { LastDragOver = DateTime.Now; if (Timer == null) { Timer = new DispatcherTimer(); Timer.Interval = TimeSpan.FromSeconds(0.05); Timer.Tick += Timer_Tick; Timer.Start(); System.Diagnostics.Debug.WriteLine( "DropBehavior.DragOver START ({0}, {1}, {2})", sender.GetType().Name, e.Source.GetType().Name, e.OriginalSource.GetType().Name ); // ここでDrop対象かどうか判定する if (e.Data.GetDataPresent(DataType?.ToString() ?? "test")) { IsAcceptable = true; } else { IsAcceptable = false; } // 自分のindicatorを出したい時、 // まず親に表示中のやつがいないかチェックして、いれば隠す // それから自分を表示 if (IsAcceptable) { var ancestors = VisualTreeHelperExtension .AncestorsOrSelf(AssociatedObject) .Behaviors() .OfType <DropBehavior>() .Where(b => b != this) .Where(b => b.IsAcceptable) ; foreach (var ancestor in ancestors) { ancestor.AddIntercepter(this); } this.ShowIndicator(); } } }
private void OnDragDelta(object sender, DragDeltaEventArgs e) { if (Target == null) { return; } // itemscontrolのitemscontainerを探す方法がよくわからない var container = VisualTreeHelperExtension .Ancestors(AssociatedObject) .OfType <UIElement>() .TakeUntilButNotIncluding(x => x is Canvas) .LastOrDefault(); if (container == null) { return; } Canvas.SetLeft(container, Math.Max(0, Canvas.GetLeft(container) + e.HorizontalChange)); Canvas.SetTop(container, Math.Max(0, Canvas.GetTop(container) + e.VerticalChange)); }
private void Timer_Tick(object sender, EventArgs e) { // DragOverが一定期間発生していなければ、マウスが外れたと判定して自分のAdornerを隠す if (DateTime.Now > LastDragOver + TimeSpan.FromSeconds(0.1)) { Timer.Stop(); Timer.Tick -= Timer_Tick; Timer = null; IsAcceptable = false; System.Diagnostics.Debug.WriteLine( "{0} DropBehavior.DragOver FINISHED", DateTime.Now.ToString("HH:mm:ss.fff") ); // 自分のindicatorを隠す場合、 // まず自分を隠す // 親にドロップ可能なやつがいないかチェックして、いれば表示 if (IsShowAdorner) { this.HideIndicator(); var ancestors = VisualTreeHelperExtension .AncestorsOrSelf(AssociatedObject) .Behaviors() .OfType <DropBehavior>() .Where(b => b != this) ; foreach (var ancestor in ancestors) { ancestor.RemoveIntercepter(this); } } } }
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e) { Scroll = VisualTreeHelperExtension.DescendantsOrSelf(AssociatedObject).OfType <ScrollViewer>().First(); }