WPF Canvas子控件拖拽行为,以及ListBox+Canvas场景
1
public class DragMoveBehavior : Behavior<UIElement> { Window window; Canvas parent; bool isDown; Point prePosition = new Point(); public Type TargetType { get; set; } UIElement Target { get; set; } protected override void OnAttached() { base.OnAttached(); Target = TargetType == null ? AssociatedObject : (UIElement)base.AssociatedObject.FirstParentOrNull(TargetType); Target.PreviewMouseLeftButtonDown += MouseLeftButtonDown; Target.PreviewMouseLeftButtonUp += MouseLeftButtonUp; window = Window.GetWindow(Target); window.LostFocus += Window_LostFocus; parent = LogicalTreeHelper.GetParent(Target) as Canvas; if (parent == null) parent = Target.FirstParentOrNull<Canvas>(); parent.PreviewMouseLeftButtonUp += MouseLeftButtonUp; parent.PreviewMouseMove += MouseMove; } private void Window_LostFocus(object sender, RoutedEventArgs e) { isDown = false; parent.ReleaseMouseCapture(); } private void MouseMove(object sender, MouseEventArgs e) { if (!isDown) return; Point currentPosition = GetPosition(e); double offsetx = currentPosition.X - prePosition.X; double offsety = currentPosition.Y - prePosition.Y; double left = Canvas.GetLeft(Target); double top = Canvas.GetTop(Target); double l = double.IsNaN(left) ? 0 : left + offsetx; double t = double.IsNaN(top) ? 0 : top + offsety; Canvas.SetLeft(Target, l); Canvas.SetTop(Target, t); prePosition = currentPosition; } private void MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { parent.ReleaseMouseCapture(); isDown = false; } private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (isDown) return; isDown = true; prePosition = GetPosition(e); parent.CaptureMouse(); } Point GetPosition(MouseEventArgs e) { return e.GetPosition(parent); } protected override void OnDetaching() { base.OnDetaching(); Target.PreviewMouseLeftButtonDown -= MouseLeftButtonDown; Target.PreviewMouseLeftButtonUp -= MouseLeftButtonUp; window.LostFocus -= Window_LostFocus; parent.PreviewMouseLeftButtonUp -= MouseLeftButtonUp; parent.PreviewMouseMove -= MouseMove; } }
2、调用方式:
.net framework方式
引用System.Windows.Interactivity类库;
在xaml中添加
xmlns:action="http://schemas.microsoft.com/expression/2010/interactivity"
.net5 .net6方式
nuget引用Microsoft.Xaml.Behaviors.Wpf包
在xaml中添加
xmlns:action="http://schemas.microsoft.com/xaml/behaviors"
然后在想要移动的控件里添加如下代码,比如是想拖动button:
案例一:
<Button Width="100" Height="50" Content="拖动我"> <action:Interaction.Behaviors> <local:DragMoveBehavior /> </action:Interaction.Behaviors> </Button>
案例二:
<ListBox SelectionMode="Extended" x:Name="listCanvas"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <Canvas/> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemContainerStyle> <Style TargetType="ListBoxItem"> <Setter Property="Canvas.Left" Value="{Binding Left}"/> <Setter Property="Canvas.Top" Value="{Binding Top}"/> <Setter Property="Width" Value="{Binding Width}"/> <Setter Property="Height" Value="{Binding Height}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> <Button Background="{Binding Brush}"> <action:Interaction.Behaviors> <local:DragMoveBehavior TargetType="{x:Type ListBoxItem}"/> </action:Interaction.Behaviors> </Button> </ControlTemplate> </Setter.Value> </Setter> </Style> </ListBox.ItemContainerStyle> </ListBox>
public class CanvaObj { public double Left { get; set; } public double Top { get; set; } public double Width { get; set; } public double Height { get; set; } public Brush Brush { get; set; } } List<CanvaObj> list = new List<CanvaObj> { new CanvaObj { Left = 50, Top = 20, Width = 40, Height = 40, Brush = Brushes.AliceBlue }, new CanvaObj { Left = 150, Top = 20, Width = 60, Height = 20, Brush = Brushes.Aquamarine }, new CanvaObj { Left = 50, Top = 120, Width = 30, Height = 60, Brush = Brushes.Fuchsia } }; listCanvas.ItemsSource = list;