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
只会添加到该元素中:
我正在尝试创建一个视觉效果 "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
只会添加到该元素中: