Drag/drop 控制子 Canvas 而不通知父 Canvas

Drag/drop controls onto child Canvas without parent Canvas being notified

我正在尝试创建一个视觉效果 "designer",允许用户将控件从工具箱拖动到设计 canvas 上。优秀的教程 here 帮助我建立了一个基本的系统 - 我可以从工具箱中拖动控件,select 并调整它们的大小等。除其他外,代码使用修改后的 Canvas 控件,重写 OnDrop 方法。

但是,我想为用户提供在设计中定义 "panels" 的选项:有效地缩小包含工具箱控件的 Canvas - 例如:

因此,当用户将按钮拖到 Canvas_1 上时,OnDrop 会触发,一切正常。但是,如果用户创建 Canvas_2,然后将按钮拖到 Canvas_2 上 - 它本身是 Canvas_1 的子控件 - 父控件 OnDrop 仍然触发并且按钮被添加到Canvas_1。

我已经尝试将 Canvas_2 的 ZIndex 设置为大于 Canvas_1,但无济于事 - 父 Canvas 总是获得事件。我怎样才能确保 Canvas_2 获得 OnDrop 控件登陆它的事件?我应该使用其他方法吗?

事件DragDrop.DragEnter采用了冒泡路由策略,即事件将从源元素开始在可视化树中向上传播,让沿途的所有元素都有机会处理该事件。

当你在内部 Canvas 中放置一些东西时,它会处理它,但不会停止事件传播,因此父元素(包含 Canvas)将再次处理它。

在覆盖的 OnDrop 方法中,您有一个 DragEventArgs 参数。 如果你想防止包含元素来处理相同的事件,请将其 Handled 属性 设置为 true

例子

我也创建了一个简单的派生 Canvas

public class MyCanvas : Canvas
{
    public static readonly DependencyProperty StopDropPropagationProperty = DependencyProperty.Register(
        "StopDropPropagation", typeof (bool), typeof (MyCanvas), new PropertyMetadata(default(bool)));

    public bool StopDropPropagation
    {
        get { return (bool) GetValue(StopDropPropagationProperty); }
        set { SetValue(StopDropPropagationProperty, value); }
    }

    protected override void OnDrop(DragEventArgs e)
    {
        Children.Add(new TextBlock
        {
            Text = "Dropped here"
        });

        e.Handled = StopDropPropagation;
    }
}

在视图中我放了两个,一个嵌套在另一个里面。

<local:MyCanvas AllowDrop="True" Background="DarkGray">
    <local:MyCanvas Width="300" Height="300" Canvas.Left="100" Canvas.Top="10" Background="BurlyWood" 
                    StopDropPropagation="True"></local:MyCanvas>
</local:MyCanvas>

需要注意的是,我添加了名为StopDropPropagation的新DependencyProperty,并在内部Canvas中将其设置为true。这会将 Handled 设置为 true。

所以当我在内部 Canvas 中放置一些东西时,TextBlock 只会添加到该元素中: