Canvas 控件
C# wpf 实现Canvas内控件拖动
实现方式一:
1.注册鼠标事件
拖动的控件需要注册3个鼠标事件分别是,鼠标按下、鼠标移动、鼠标弹起。
以Button为例
<Button PreviewMouseDown="Button_MouseDown" PreviewMouseMove="Button_MouseMove" PreviewMouseUp="Button_MouseUp"> </Button>
2.记录位置
在鼠标按下事件中记录位置。记录位置时需要判断属性值是否为NAN,如果为NAN则记录为0。
//鼠标是否按下 bool _isMouseDown = false; //鼠标按下的位置 Point _mouseDownPosition; //鼠标按下控件的位置 Point _mouseDownControlPosition; //鼠标按下事件 private void Button_MouseDown(object sender, MouseButtonEventArgs e) { var c = sender as Control; _isMouseDown = true; _mouseDownPosition = e.GetPosition(this); _mouseDownControlPosition = new Point(double.IsNaN(Canvas.GetLeft(c))? 0:Canvas.GetLeft(c),double.IsNaN(Canvas.GetTop(c)) ? 0 : Canvas.GetTop(c) ); c.CaptureMouse(); }
3.跟随鼠标移动
鼠标按下后移动鼠标,控件需要跟随鼠标移动。直接计算移动距离,设置Canvas.Left和Canvas.Top即可。
private void Button_MouseMove(object sender, MouseEventArgs e) { if (_isMouseDown) { var c = sender as Control; var pos = e.GetPosition(this); var dp = pos - _mouseDownPosition; Canvas.SetLeft(c, _mouseDownControlPosition.X+ dp.X); Canvas.SetTop(c, _mouseDownControlPosition.Y + dp.Y); } }
4.恢复标识
鼠标弹起后需要恢复标识,让控件不再跟随鼠标移动。
private void Button_MouseUp(object sender, MouseButtonEventArgs e) { var c = sender as Control; _isMouseDown = false; c.ReleaseMouseCapture(); }
二、示例
示例代码:
<Window x:Class="WpfControlMove.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfControlMove" mc:Ignorable="d" Title="MainWindow" Height="360" Width="640"> <Canvas> <Button Width="120" Height="50" Content="移动" PreviewMouseDown="Button_MouseDown" PreviewMouseMove="Button_MouseMove" PreviewMouseUp="Button_MouseUp"> </Button> </Canvas> </Window>
实现方式二:
矩形_rectangle在Canvas中
/// 移动矩形
MouseDragElementBehavior dragBehavior = new MouseDragElementBehavior();
dragBehavior.Attach(_rectangle);
dragBehavior.DragFinished += onDragFinished;
在Canvas中设置控件坐标
Label label = new Label { Content = "测试", FontSize = 14, Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF0000")) }; Canvas.SetTop(label, 10.9);//在c#后台代码中动态设置 Canvas.SetLeft(label, 20.39); printArea.Children.Add(label);
这种方式适合动态增加控件的页面。
动态创建控件
1.容器控件.RegisterName("Name",要注册的控件) //注册控件
2.容器控件.FindName("Name") as 控件类型 //找到控件并转换成相应类型
注意:仅通过 控件.Name来设置是不能通过FindName来找到控件的,必须注册
动态删除控件
1.容器控件.Children.Remove(控件) //移除控件
2.容器控件.UnregisterName("Name") //取消注册
其它设置
1.控件.SetValue(Grid.RowProperty, 0); //设置控件在Grid面板中的行数
控件.SetValue(Grid.ColumnProperty, 1); //设置控件在Grid面板中的列数
2.Canvas.SetLeft("控件名", 50); //设置控件在Canvas面板中的横坐标
Canvas.SetTop("控件名", 50); //设置控件在Canvas面板中的纵坐标
在mvvm 模式下,Canvas 实现动态添加元素
Subjectview
<ItemsControl Margin="0,0,0,20" ItemsSource="{Binding Balloons}" x:Name="canvasBackground" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <!-- IsItemsHost=true表示子元素将显示在此容器中。 在SubjectViewModel中增删改Balloons集合对象就可以设置 Canvas中元素的。--> <Canvas IsItemsHost="True"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style> <!-- Canvas.Left\Canvas.Top对应 ItemViewModel中的X\Y属性,--> <Setter Property="Canvas.Left" Value="{Binding X}"/> <Setter Property="Canvas.Top" Value="{Binding Y}"/> </Style> </ItemsControl.ItemContainerStyle> </ItemsControl>
ItemViewModel
internal partial class BalloonViewModel : ObservableObject { ///其他代码 /// <summary> /// 坐标点 /// </summary> /// [ObservableProperty] public double? x; [ObservableProperty] public double? y; }
SubjectViewModel
internal partial class SubjectViewModel: ObservableObject { ///其他代码 /// <summary> /// 元素集合 /// </summary> /// [ObservableProperty] ObservableCollection<BalloonViewModel>? balloons=new(); }
只需少量更改即可使用<Canvas IsItemsHost=“True” />, IsItemsHost=true表示子元素将显示在此容器中。
Canvas 复杂矢量图形布局
如果希望Path的各个部分使用不同的颜色,就需要创建彼此独立的Path对象。 此时就需要使用View+Canvas+path的组合方式 来设计复杂的矢量图形。
注意必须给canvas设置一个初始的 Width、 Height的,否则无法显示。
<Viewbox Stretch="Uniform" > <Canvas Width="80" Height="220" > <!--球体--> <Path Canvas.Left="0" Canvas.Top="0" Fill="{Binding BalloonColor}" Data="M57.078,140.071h6.175L69,153l-18.054-.946ZM61,0c33.689,0,61,31.34,61,70s-27.311,70-61,70S0,108.66,0,70,27.311,0,61,0Z" /> <!--反光--> <Path Fill="{Binding ReflectLight}" Data="M33.978,35.095c6.638,1.091,10.462,11.335,8.542,22.881S33.66,78,27.022,76.905,16.56,65.57,18.48,54.025,27.34,34,33.978,35.095Z" /> <!--线条--> <Path StrokeThickness="4" Stroke="{Binding Line}" Data="M62,152c-4.764,15.394-5.243,29.971,0,43,2.406,5.98,7.875,14.606,14,23,4.172,5.717,6.546,9.83,8,16,3.84,16.294-3.737,52.7-11,67" /> </Canvas> </Viewbox>