Wpf,如何在可拖动元素内拖动对象?
Wpf, How to drag object inside draggable element?
我正在开发 WPF 应用程序。我应该在其他可拖动对象中实现带有可拖动对象的设计器页面。看图:
现在我的 拖放 1 和 2 工作,但是当我试图拖动 内部对象 1 并执行 拖放 3 它不能正常工作。我没有拖动 内部对象 1,而是拖动 主对象 1。
我的xaml代码:
<ItemsControl ItemsSource="{Binding MasterObjects}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Width" Value="{Binding Path=Width}" />
<Setter Property="Height" Value="{Binding Path=Height}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid behaviors:DragBehavior.Drag="True">
<Rectangle Fill="LightGray" Stroke="SlateGray" StrokeThickness="1" />
<TextBlock Text="{Binding Name}" />
<ItemsControl ItemsSource="{Binding InnerObjects}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Width" Value="{Binding Path=Width}" />
<Setter Property="Height" Value="{Binding Path=Height}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid behaviors:DragBehavior.Drag="True">
<Rectangle Fill="LightGray" Stroke="SlateGray" StrokeThickness="1" />
<TextBlock Text="{Binding Name}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
还有我的 DragBehavior class:
public class DragBehavior
{
public readonly TranslateTransform Transform = new TranslateTransform();
private Point _elementStartPosition2;
private Point _mouseStartPosition2;
private static DragBehavior _instance = new DragBehavior();
public static DragBehavior Instance
{
get { return _instance; }
set { _instance = value; }
}
public static bool GetDrag(DependencyObject obj)
{
return (bool)obj.GetValue(IsDragProperty);
}
public static void SetDrag(DependencyObject obj, bool value)
{
obj.SetValue(IsDragProperty, value);
}
public static readonly DependencyProperty IsDragProperty =
DependencyProperty.RegisterAttached(
"Drag",
typeof(bool),
typeof(DragBehavior),
new PropertyMetadata(false, OnDragChanged));
private static void OnDragChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// ignoring error checking
var element = (UIElement)sender;
var isDrag = (bool)(e.NewValue);
Instance = new DragBehavior();
((UIElement)sender).RenderTransform = Instance.Transform;
if (isDrag)
{
element.MouseLeftButtonDown += Instance.ElementOnMouseLeftButtonDown;
element.MouseLeftButtonUp += Instance.ElementOnMouseLeftButtonUp;
element.MouseMove += Instance.ElementOnMouseMove;
}
else
{
element.MouseLeftButtonDown -= Instance.ElementOnMouseLeftButtonDown;
element.MouseLeftButtonUp -= Instance.ElementOnMouseLeftButtonUp;
element.MouseMove -= Instance.ElementOnMouseMove;
}
}
private void ElementOnMouseLeftButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
var parent = Application.Current.MainWindow;
_mouseStartPosition2 = mouseButtonEventArgs.GetPosition(parent);
((UIElement)sender).CaptureMouse();
}
private void ElementOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
((UIElement)sender).ReleaseMouseCapture();
_elementStartPosition2.X = Transform.X;
_elementStartPosition2.Y = Transform.Y;
}
private void ElementOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
{
var parent = Application.Current.MainWindow;
var mousePos = mouseEventArgs.GetPosition(parent);
var diff = (mousePos - _mouseStartPosition2);
if (!((UIElement)sender).IsMouseCaptured) return;
Transform.X = _elementStartPosition2.X + diff.X;
Transform.Y = _elementStartPosition2.Y + diff.Y;
}
}
我想我应该修复 DragBehaviour class,但我不知道如何修复。现在我真的很困惑。
MouseLeftButtonDown 事件是从内部容器到父容器的bubbling。尝试在事件处理程序中将 e.Handled 属性 设置为 true。在这种情况下,只会引发第一个单击元素的处理程序,您的代码应该可以正常工作。
我还建议您使用 DevExpress 提供的 attached behavior instead of a class with several attached properties. You can find it in a free MVVM Framework。
通常,在这种情况下,行为会给你更多的自由。
我正在开发 WPF 应用程序。我应该在其他可拖动对象中实现带有可拖动对象的设计器页面。看图:
现在我的 拖放 1 和 2 工作,但是当我试图拖动 内部对象 1 并执行 拖放 3 它不能正常工作。我没有拖动 内部对象 1,而是拖动 主对象 1。
我的xaml代码:
<ItemsControl ItemsSource="{Binding MasterObjects}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Width" Value="{Binding Path=Width}" />
<Setter Property="Height" Value="{Binding Path=Height}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid behaviors:DragBehavior.Drag="True">
<Rectangle Fill="LightGray" Stroke="SlateGray" StrokeThickness="1" />
<TextBlock Text="{Binding Name}" />
<ItemsControl ItemsSource="{Binding InnerObjects}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Width" Value="{Binding Path=Width}" />
<Setter Property="Height" Value="{Binding Path=Height}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid behaviors:DragBehavior.Drag="True">
<Rectangle Fill="LightGray" Stroke="SlateGray" StrokeThickness="1" />
<TextBlock Text="{Binding Name}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
还有我的 DragBehavior class:
public class DragBehavior
{
public readonly TranslateTransform Transform = new TranslateTransform();
private Point _elementStartPosition2;
private Point _mouseStartPosition2;
private static DragBehavior _instance = new DragBehavior();
public static DragBehavior Instance
{
get { return _instance; }
set { _instance = value; }
}
public static bool GetDrag(DependencyObject obj)
{
return (bool)obj.GetValue(IsDragProperty);
}
public static void SetDrag(DependencyObject obj, bool value)
{
obj.SetValue(IsDragProperty, value);
}
public static readonly DependencyProperty IsDragProperty =
DependencyProperty.RegisterAttached(
"Drag",
typeof(bool),
typeof(DragBehavior),
new PropertyMetadata(false, OnDragChanged));
private static void OnDragChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// ignoring error checking
var element = (UIElement)sender;
var isDrag = (bool)(e.NewValue);
Instance = new DragBehavior();
((UIElement)sender).RenderTransform = Instance.Transform;
if (isDrag)
{
element.MouseLeftButtonDown += Instance.ElementOnMouseLeftButtonDown;
element.MouseLeftButtonUp += Instance.ElementOnMouseLeftButtonUp;
element.MouseMove += Instance.ElementOnMouseMove;
}
else
{
element.MouseLeftButtonDown -= Instance.ElementOnMouseLeftButtonDown;
element.MouseLeftButtonUp -= Instance.ElementOnMouseLeftButtonUp;
element.MouseMove -= Instance.ElementOnMouseMove;
}
}
private void ElementOnMouseLeftButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
var parent = Application.Current.MainWindow;
_mouseStartPosition2 = mouseButtonEventArgs.GetPosition(parent);
((UIElement)sender).CaptureMouse();
}
private void ElementOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
((UIElement)sender).ReleaseMouseCapture();
_elementStartPosition2.X = Transform.X;
_elementStartPosition2.Y = Transform.Y;
}
private void ElementOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
{
var parent = Application.Current.MainWindow;
var mousePos = mouseEventArgs.GetPosition(parent);
var diff = (mousePos - _mouseStartPosition2);
if (!((UIElement)sender).IsMouseCaptured) return;
Transform.X = _elementStartPosition2.X + diff.X;
Transform.Y = _elementStartPosition2.Y + diff.Y;
}
}
我想我应该修复 DragBehaviour class,但我不知道如何修复。现在我真的很困惑。
MouseLeftButtonDown 事件是从内部容器到父容器的bubbling。尝试在事件处理程序中将 e.Handled 属性 设置为 true。在这种情况下,只会引发第一个单击元素的处理程序,您的代码应该可以正常工作。
我还建议您使用 DevExpress 提供的 attached behavior instead of a class with several attached properties. You can find it in a free MVVM Framework。 通常,在这种情况下,行为会给你更多的自由。