引用地址:https://blog.csdn.net/redfox6843/article/details/126117819
文章目录
WPF Prism MVVM【动态添加控件并可用鼠标、拖动、缩放、旋转】
前言
项目运行截图
一、基本类
1.控件对应的实体类
2.控件缩放和旋转的核心类
3.查找控件的方法
4.MVVM向ViewModel传递多个参数的类
二、为标识方向的控件
1.XAML代码
2.CS代码
三、主程序
1.AXML代码
2.ViewModel端的CS代码
总结
前言
本文中所开发的功能是为了给后台目标检测算法做区域标注的一个Demo。为视频中标注电子围栏和框选区域。主要采用了Prism.DryIoc的MVVM方式,用到控件和方法:ItemsControl(控件模板)、Thumb(可拖动控件)、Adorner(装饰器)、CommandParameter的多参数传递、GetChildObjectByUid(通过UID查找某类型的子控件)
项目运行截图
一、基本类
1.控件对应的实体类
这个类只是为了给生成的控件一个数据的支撑(可以理解为灵魂:😜)
using Prism.Commands;
using Prism.Mvvm;
namespace BlankApp2
{
public class ObjEntity : BindableBase
{
public int ID { get; set; }
/// <summary>
/// 节点名称
/// </summary>
public string Name { set; get; }
/// <summary>
/// 拖动事件
/// </summary>
public DelegateCommand<object> onDragDeltaCommand { get; set; }
/// <summary>
/// 控件加载后事件
/// </summary>
public DelegateCommand<object> onThumbLoadedCommand { get; set; }
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2.控件缩放和旋转的核心类
GridAdorner(Grid装饰器)这个类主要是在动态添加到前端的Loaded事件中为其添加上一些Thumb控件,并且用鼠标操作这些Thumb来调整其控件的大小和旋转。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace BlankApp2
{
/// <summary>
/// Grid装饰器
/// </summary>
public class GridAdorner : Adorner
{
//4条边
Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
//4个角
Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
Thumb _middleThumb;
//布局容器,如果不使用布局容器,则需要给上述8个控件布局,实现和Grid布局定位是一样的,会比较繁琐且意义不大。
Grid _grid;
UIElement _adornedElement;
public GridAdorner(UIElement adornedElement) : base(adornedElement)
{
_adornedElement = adornedElement;
//初始化四周和中间的thumb
_middleThumb = new Thumb();
_middleThumb.HorizontalAlignment = HorizontalAlignment.Center;
_middleThumb.VerticalAlignment = VerticalAlignment.Center;
_middleThumb.Cursor =Cursors.Cross;
_leftThumb = new Thumb();
_leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
_leftThumb.VerticalAlignment = VerticalAlignment.Center;
_leftThumb.Cursor = Cursors.SizeWE;
_topThumb = new Thumb();
_topThumb.HorizontalAlignment = HorizontalAlignment.Center;
_topThumb.VerticalAlignment = VerticalAlignment.Top;
_topThumb.Cursor = Cursors.SizeNS;
_rightThumb = new Thumb();
_rightThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightThumb.VerticalAlignment = VerticalAlignment.Center;
_rightThumb.Cursor = Cursors.SizeWE;
_bottomThumb = new Thumb();
_bottomThumb.HorizontalAlignment = HorizontalAlignment.Center;
_bottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_bottomThumb.Cursor = Cursors.SizeNS;
_lefTopThumb = new Thumb();
_lefTopThumb.HorizontalAlignment = HorizontalAlignment.Left;
_lefTopThumb.VerticalAlignment = VerticalAlignment.Top;
_lefTopThumb.Cursor = Cursors.SizeNWSE;
_rightTopThumb = new Thumb();
_rightTopThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightTopThumb.VerticalAlignment = VerticalAlignment.Top;
_rightTopThumb.Cursor = Cursors.SizeNESW;
_rightBottomThumb = new Thumb();
_rightBottomThumb.HorizontalAlignment = HorizontalAlignment.Right;
_rightBottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_rightBottomThumb.Cursor = Cursors.SizeNWSE;
_leftbottomThumb = new Thumb();
_leftbottomThumb.HorizontalAlignment = HorizontalAlignment.Left;
_leftbottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
_leftbottomThumb.Cursor = Cursors.SizeNESW;
_grid = new Grid();
_grid.Children.Add(_middleThumb);
_grid.Children.Add(_leftThumb);
_grid.Children.Add(_topThumb);
_grid.Children.Add(_rightThumb);
_grid.Children.Add(_bottomThumb);
_grid.Children.Add(_lefTopThumb);
_grid.Children.Add(_rightTopThumb);
_grid.Children.Add(_rightBottomThumb);
_grid.Children.Add(_leftbottomThumb);
AddVisualChild(_grid);
foreach (Thumb thumb in _grid.Children)
{
thumb.Width = 13;
thumb.Height = 13;
thumb.Background = Brushes.Green;
thumb.Template = new ControlTemplate(typeof(Thumb))
{
VisualTree = GetFactory(new SolidColorBrush(Colors.White))
};
thumb.DragDelta += Thumb_DragDelta;
}
}
/// <summary>
/// 控件的旋转事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void _zhongThumb_MouseMove(object sender, MouseEventArgs e)
{
if (Mouse.Captured == _adornedElement)
{
double a = Math.PI;
var c = _adornedElement as FrameworkElement;
// c.RenderTransformOrigin = new Point(0.5, 0.5);
// Get the current mouse position relative to the volume control
Point currentLocation = Mouse.GetPosition(this);
// We want to rotate around the center of the knob, not the top corner
Point knobCenter = new Point(this.ActualHeight / 2, this.ActualWidth / 2);
// Calculate an angle
//double radians = Math.Atan((currentLocation.Y - knobCenter.Y) /
// (currentLocation.X - knobCenter.X));
double radians = Math.Atan((currentLocation.Y)/
(currentLocation.X));
RotateTransform rt = new RotateTransform();
rt.Angle = radians * 180 / Math.PI;
rt.Angle = radians ;
// Apply a 180 degree shift when X is negative so that we can rotate
// all of the way around
//if (currentLocation.X - knobCenter.X < 0)
//{
// rt.Angle += 180;
//}
c.RenderTransform = rt;
// c.RenderTransformOrigin = new Point(0, 0);
}
}
/// <summary>
/// 鼠标在旋转控件上抬起
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void _zhongThumb_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
}
/// <summary>
/// 鼠标在旋转控件上按下
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void _zhongThumb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(this);
}
protected override Visual GetVisualChild(int index)
{
return _grid;
}
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
protected override Size ArrangeOverride(Size finalSize)
{ //直接给grid布局,grid内部的thumb会自动布局。
_grid.Arrange(new Rect(new Point(-_leftThumb.Width / 2, -_leftThumb.Height / 2), new Size(finalSize.Width + _leftThumb.Width, finalSize.Height + _leftThumb.Height)));
return finalSize;
}
/// <summary>
/// 拖动事件逻辑
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
var c = _adornedElement as FrameworkElement;
var thumb = sender as FrameworkElement;
double left, top, right, bottom, width, height;
if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
{
right = c.Margin.Right;
left = c.Margin.Left + e.HorizontalChange;
width = (double.IsNaN(c.Width) ? c.ActualWidth : c.Width) - e.HorizontalChange;
}
else
{
left = c.Margin.Left;
right = c.Margin.Right - e.HorizontalChange;
width = (double.IsNaN(c.Width) ? c.ActualWidth : c.Width) + e.HorizontalChange;
}
if (thumb.VerticalAlignment == VerticalAlignment.Top)
{
bottom = c.Margin.Bottom;
top = c.Margin.Top + e.VerticalChange;
height = (double.IsNaN(c.Height) ? c.ActualHeight : c.Height) - e.VerticalChange;
}
else
{
top = c.Margin.Top;
bottom = c.Margin.Bottom - e.VerticalChange;
height = (double.IsNaN(c.Height) ? c.ActualHeight : c.Height) + e.VerticalChange;
}
if (thumb.HorizontalAlignment != HorizontalAlignment.Center)
{
if (width >= 0)
{
c.Margin = new Thickness(left, c.Margin.Top, right, c.Margin.Bottom);
c.Width = width;
}
}
if (thumb.VerticalAlignment != VerticalAlignment.Center)
{
if (height >= 0)
{
c.Margin = new Thickness(c.Margin.Left, top, c.Margin.Right, bottom);
c.Height = height;
}
}
if (thumb.HorizontalAlignment == HorizontalAlignment.Center && thumb.VerticalAlignment == VerticalAlignment.Center)
{
Point currentLocation = Mouse.GetPosition(this);
// 我们想绕着旋钮的中心旋转,而不是顶角
Point knobCenter = new Point(this.ActualHeight / 2, this.ActualWidth / 2);
// 计算角度
double radians = Math.Atan((currentLocation.Y - knobCenter.Y) /
(currentLocation.X - knobCenter.X));
RotateTransform rt = new RotateTransform();
rt.Angle = radians * 180 / Math.PI;
// 当X为负时,应用180度偏移,这样我们可以旋转所有的方向,但是这个地方怎么看着效果不是那么好看
if (currentLocation.X - knobCenter.X < 0)
{
rt.Angle += 180;
}
c.RenderTransform = rt;
}
}
/// <summary>
/// 四周thumb的样式
/// </summary>
/// <param name="back"></param>
/// <returns></returns>
FrameworkElementFactory GetFactory(Brush back)
{
var fef = new FrameworkElementFactory(typeof(Ellipse));
fef.SetValue(Ellipse.FillProperty, back);
fef.SetValue(Ellipse.StrokeProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")));
fef.SetValue(Ellipse.StrokeThicknessProperty, (double)2);
return fef;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
3.查找控件的方法
由于在控件模板里有些控件的Name可能无法用Binding来绑定的,所以为了后面查找控件方便采用了UID来做为标识
/// <summary>
/// 通过UID查找某类型的子控件
/// </summary>
/// <example>StackPanel sp = GetChildObject<StackPanel>(this.LayoutRoot, "spDemoPanel")</example>
/// <typeparam name="T">子控件类型</typeparam>
/// <param name="obj">父控件</param>
/// <param name="name">子控件名称,默认为空</param>
/// <returns></returns>
public static T GetChildObjectByUid<T>(DependencyObject obj, string uid = null) where T : FrameworkElement
{
DependencyObject child = null;
T grandChild = null;
for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
{
child = VisualTreeHelper.GetChild(obj, i);
if (child is T && (((T)child).Uid == uid | string.IsNullOrEmpty(uid)))
{
return (T)child;
}
else
{
grandChild = GetChildObjectByUid<T>(child, uid);
if (grandChild != null)
return grandChild;
}
}
return null;
}
/// <summary>
/// 通过名称查找某类型的子控件
/// </summary>
/// <example>StackPanel sp = GetChildObject<StackPanel>(this.LayoutRoot, "spDemoPanel")</example>
/// <typeparam name="T">子控件类型</typeparam>
/// <param name="obj">父控件</param>
/// <param name="name">子控件名称,默认为空</param>
/// <returns></returns>
public static T GetChildObject<T>(DependencyObject obj, string name = null) where T : FrameworkElement
{
DependencyObject child = null;
T grandChild = null;
for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
{
child = VisualTreeHelper.GetChild(obj, i);
if (child is T && (((T)child).Name == name | string.IsNullOrEmpty(name)))
{
return (T)child;
}
else
{
grandChild = GetChildObject<T>(child, name);
if (grandChild != null)
return grandChild;
}
}
return null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
4.MVVM向ViewModel传递多个参数的类
using System;
using System.Linq;
using System.Windows.Data;
namespace WPF_Common
{
/// <summary>
/// CommandParameter 多参数传递
/// </summary>
public class ObjectConvert : IMultiValueConverter
{
#region IMultiValueConverter Members
public static object ConverterObject;
public object Convert(object[] values, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
ConverterObject = values;
string str = values.GetType().ToString();
return values.ToArray();
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
二、为标识方向的控件
1.XAML代码
在这里面的ID_Head是用来标识方向的,最后我们可以获它的相对坐标就可以了。
<UserControl x:Class="BlankApp2.Views.ArrowControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BlankApp2.Views"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="100">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="2"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0" Fill="Red" Panel.ZIndex="0" Data="M -15,8 L 17,17 C 17,17 19,18 17,19 L 17,19 L -15,28 C -15,28 -17,28.2 -16,26 L -16,26 L -5,18 L -16,10 C -16,10 -17,8.5 -15,8 Z" Margin="0,0,0,0" Stretch="Fill"/>
<Ellipse Grid.Column="1" Name="ID_Head" Height="1" Width="1" Stroke="Black" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</UserControl>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2.CS代码
这里为了方便就没用MVVM
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
namespace BlankApp2.Views
{
/// <summary>
/// UserControl.xaml 的交互逻辑
/// </summary>
public partial class ArrowControl : UserControl
{
public ArrowControl()
{
InitializeComponent();
}
#region ID
/// <summary>
/// 左面标题
/// </summary>
public string ID
{
get => (string)GetValue(IDProperty);
set => SetValue(IDProperty, value);
}
public static readonly DependencyProperty IDProperty =
DependencyProperty.RegisterAttached(
"ID",
typeof(string),
typeof(ArrowControl),
new FrameworkPropertyMetadata("", new PropertyChangedCallback(OnPropertyChanged)));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var b = d as ArrowControl;
if (b != null && IDProperty != null)
{
// b.Title;
}
}
#endregion
public Ellipse Direction
{
get { return this.ID_Head; }
}
public static readonly DependencyProperty DirectionProperty =
DependencyProperty.RegisterAttached(
"Direction",
typeof(string),
typeof(ArrowControl),
new FrameworkPropertyMetadata("", null));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
三、主程序
1.AXML代码
在界面上主要用了两个ItemsControl 分别用来动态加载“线头”和“方框” 要注意的事,这两个ItemsControl是叠加在一起的,这样是为了让用户感觉在同一区域操作。但是叠加后会有一个控件遮挡的问题(鼠标是点击不到下面的控件的)。为了解决这个问题需要为最上层的控件背景设置为: Background=“{x:Null}” 并且 把穿透设置为: IsHitTestVisible=“True” 。
<UserControl xmlns:Views="clr-namespace:BlankApp2.Views" x:Class="BlankApp2.Views.PrismUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local1="clr-namespace:WPF_Common;assembly=WPF_Common"
prism:ViewModelLocator.AutoWireViewModel="True" Background="Bisque">
<UserControl.Resources>
<ResourceDictionary>
<!--多参数的初始化-->
<local1:ObjectConvert x:Key="objectConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<Grid Background="Gainsboro" AllowDrop="True" >
<Grid.RowDefinitions>
<RowDefinition Height="200*"/>
<RowDefinition Height="50*"/>
</Grid.RowDefinitions>
<!--鼠标点击穿透:背景设置为: Background="{x:Null}" 并且 把穿透设置为: IsHitTestVisible="True"-->
<ItemsControl x:Name="ic" Background="{x:Null}" ItemsSource="{Binding objSource}" Grid.Column="0" Grid.Row="0" IsHitTestVisible="True" >
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Left" Value="{Binding CnvLeft}"/>
<Setter Property="Canvas.Top" Value="{Binding CnvTop}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate >
<DataTemplate >
<Thumb IsHitTestVisible="True" Name="Thumbs" Uid="{Binding Name}" Tag="{Binding Name}" Background="Black" VerticalAlignment="Center" HorizontalAlignment="Center" TextElement.FontStyle="Normal" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="DragDelta">
<i:InvokeCommandAction Command="{Binding onDragDeltaCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Thumb.ContextMenu>
<ContextMenu>
<MenuItem Header="删除" Name="miClickMe" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding onThumbDeleteCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</Thumb.ContextMenu>
<Thumb.Template>
<ControlTemplate >
<!--将旋转的点改为中心RenderTransformOrigin = "0.5,0.5"-->
<Grid Name="wpl" IsHitTestVisible="True" HorizontalAlignment="Center"
VerticalAlignment="Center" Tag="{Binding ID}" RenderTransformOrigin = "0.5,0.5" Background="Transparent" Height="80" Width="80" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding onThumbLoadedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<!--将样式做成线头-->
<Views:ArrowControl ID="{Binding ID}" x:Name="Arrow" Width="100" Height="50" />
<Border Height="{Binding ElementName=wpl,Path=Height}" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Width="6" Background="LightYellow" BorderThickness="1" Panel.ZIndex="1">
<Grid Background="Black">
<!--为线两端加上两个圆用于获取线的两端坐标-->
<Ellipse Name="LineTop" Height="10" Width="10" Stroke="White" Fill="White" VerticalAlignment="Top" HorizontalAlignment="Center" />
<Ellipse Name="LineBottom" Height="10" Width="10" Stroke="Gold" Fill="Gold" VerticalAlignment="Bottom" HorizontalAlignment="Center" />
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Name="myG" Grid.Column="0" Grid.Row="0" IsHitTestVisible="True" Background="Blue">
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl x:Name="ic2" ItemsSource="{Binding objSource2}" Background="{x:Null}" Grid.Column="0" Grid.Row="0" Panel.ZIndex="1" IsHitTestVisible="True" >
<ItemsControl.ItemTemplate >
<DataTemplate >
<Thumb IsHitTestVisible="True" Name="Thumbs" Tag="{Binding Name}" Background="Black" VerticalAlignment="Center" HorizontalAlignment="Center" TextElement.FontStyle="Normal" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="DragDelta">
<i:InvokeCommandAction Command="{Binding onDragDeltaCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Thumb.ContextMenu>
<ContextMenu>
<MenuItem Header="删除" Name="miClickMe" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding onThumbDeleteCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
</Thumb.ContextMenu>
<Thumb.Template>
<ControlTemplate >
<!--将旋转的点改为中心RenderTransformOrigin = "0.5,0.5"-->
<Grid Name="wpl" HorizontalAlignment="Center"
VerticalAlignment="Center" Tag="{Binding ID}" RenderTransformOrigin = "0.5,0.5" Background="Transparent" Height="80" Width="80" >
<i:Interaction.Triggers>
<!--控件加载后调用事件-->
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding onThumbLoadedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<!--将样式改成一个方框-->
<Rectangle x:Name="rl" StrokeThickness="2" Stroke="Red" Fill="AliceBlue" Opacity="0.5"/>
</Grid>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate >
<Grid Name="myG2" Grid.Column="0" Grid.Row="0" Background="{x:Null}" IsHitTestVisible="True" >
<!--<Grid.Background>
<ImageBrush Stretch="None"
ImageSource="{Binding ImageSources}"
AlignmentY="Center"
AlignmentX="Center">
</ImageBrush>
</Grid.Background>-->
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Button Content="线头" HorizontalAlignment="Left" Margin="88,34,0,0" Grid.Row="1" VerticalAlignment="Top" Command="{Binding AddT}"/>
<Button Content="方框" HorizontalAlignment="Left" Margin="138,34,0,0" Grid.Row="1" VerticalAlignment="Top" Command="{Binding AddT2}"/>
<Button Content="Get" HorizontalAlignment="Left" Margin="50,34,0,0" Grid.Row="1" VerticalAlignment="Top" Command="{Binding GetT}" >
<Button.CommandParameter>
<MultiBinding Converter="{ StaticResource ResourceKey=objectConverter}">
<Binding ElementName="ic"></Binding>
<Binding ElementName="rtl"></Binding>
</MultiBinding>
</Button.CommandParameter>
</Button>
<TextBlock Grid.Row="1" Margin="200,34,0,0" Text="{Binding MarginValue}"/>
</Grid>
</UserControl>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
2.ViewModel端的CS代码
using Prism.Commands;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using WPF_Common;
namespace BlankApp2.ViewModels
{
public class PrismUserControl1ViewModel : BindableBase, IModule
{
/// <summary>
/// 拖动事件
/// </summary>
public DelegateCommand<object> onDragDeltaCommand { get; private set; }
/// <summary>
/// 控件加载后事件
/// </summary>
public DelegateCommand<object> onThumbLoadedCommand { get; private set; }
/// <summary>
/// 控件删除事件
/// </summary>
public DelegateCommand<object> onThumbDeleteCommand { get; private set; }
/// <summary>
/// 获取坐标事件
/// </summary>
public DelegateCommand<object> GetT { get; private set; }
/// <summary>
/// 添加线头事件
/// </summary>
public DelegateCommand AddT { get; private set; }
/// <summary>
/// 添加方框事件
/// </summary>
public DelegateCommand AddT2 { get; private set; }
/// <summary>
/// 加载本页面事件
/// </summary>
public PrismUserControl1ViewModel()
{
onDragDeltaCommand = new DelegateCommand<object>(onDragDelta);
onThumbLoadedCommand = new DelegateCommand<object>(onThumbLoaded);
onThumbDeleteCommand = new DelegateCommand<object>(onThumbDelete);
AddT = new DelegateCommand(Add);
AddT2 = new DelegateCommand(Add2);
GetT = new DelegateCommand<object>(GetTOne);
}
/// <summary>
/// 获取坐标事件
/// </summary>
/// <param name="obj"></param>
private void GetTOne(object obj)
{
///obj对像是View端传来的多参数
object[] multiObj = obj as object[];
Grid grid = FindChildControlHelper.GetChildObject<Grid>(multiObj[0] as DependencyObject, "myG");
//Grid wplGrid = FindChildControlHelper.GetChildObject<Grid>(multiObj[0] as DependencyObject, "wpl");
//Ellipse eps = FindChildControlHelper.GetChildObject<Ellipse>(multiObj[0] as DependencyObject , "ID_Head");
//Ellipse LineTop = FindChildControlHelper.GetChildObject<Ellipse>(multiObj[0] as DependencyObject, "LineTop");
//Ellipse LineBottom = FindChildControlHelper.GetChildObject<Ellipse>(multiObj[0] as DependencyObject, "LineBottom");
//Rectangle obj1 = FindChildControlHelper.GetChildObject<Rectangle>(multiObj[0] as DependencyObject, "rtl");
//System.Windows.Point pointeps = eps.TranslatePoint(new System.Windows.Point(), grid);
//System.Windows.Point pointLineTop = LineTop.TranslatePoint(new System.Windows.Point(), grid);
//System.Windows.Point pointLineBottom = LineBottom.TranslatePoint(new System.Windows.Point(), grid);
for (int i = 0; i < objSource.Count; i++)
{
string sourceName = objSource[i].Name;
Thumb Thumb1 = FindChildControlHelper.GetChildObjectByUid<Thumb>(multiObj[0] as DependencyObject, sourceName);
Grid wplGrid = FindChildControlHelper.GetChildObject<Grid>(Thumb1 as DependencyObject, "wpl");
System.Windows.Point point = Thumb1.TranslatePoint(new System.Windows.Point(), grid);//获取控件在grid的相对坐标
MessageBox.Show(Thumb1.Name + ";" + Thumb1.Tag + "H:" + Thumb1.Height + ";" + "W:" + Thumb1.Width + "T:" + Thumb1.Margin.Top + ";" + "L:" + Thumb1.Margin.Left);
}
}
private string _MarginValue;
/// <summary>
/// Margin四个方向的值
/// </summary>
public string MarginValue
{
get { return _MarginValue; }
set { SetProperty(ref _MarginValue, value); }
}
private int _CanvasWidth = 600;
public int CanvasWidth
{
get { return _CanvasWidth; }
set { SetProperty(ref _CanvasWidth, value); }
}
private int _CanvasHeight = 700;
public int CanvasHeight
{
get { return _CanvasHeight; }
set { SetProperty(ref _CanvasHeight, value); }
}
/// <summary>
/// 添加线头
/// </summary>
private void Add()
{
for (int i = 1; i < 2; i++)
{
int k = objSource.Count + 1;
ObjEntity obj = new ObjEntity();
obj.ID = k;
obj.Name = "Name" + k;
obj.onDragDeltaCommand = onDragDeltaCommand;
obj.onThumbLoadedCommand = onThumbLoadedCommand;
objSource.Add(obj);
}
}
/// <summary>
/// 添加方框
/// </summary>
private void Add2()
{
for (int i = 1; i < 2; i++)
{
int k = objSource.Count + 1;
ObjEntity obj = new ObjEntity();
obj.ID = k;
obj.Name = "NameL" + k;
obj.onDragDeltaCommand = onDragDeltaCommand;
obj.onThumbLoadedCommand = onThumbLoadedCommand;
objSource2.Add(obj);
}
}
/// <summary>
/// 删除
/// </summary>
/// <param name="obj"></param>
/// <exception cref="NotImplementedException"></exception>
private void onThumbDelete(object obj)
{
objSource.Remove(obj as ObjEntity);
}
/// <summary>
/// 加载四周的Thumb
/// </summary>
/// <param name="obj"></param>
private void onThumbLoaded(object obj)
{
if (obj is System.Windows.RoutedEventArgs e)
{
AdornerLayer layer = AdornerLayer.GetAdornerLayer((Grid)e.Source);
layer.Add(new GridAdorner((Grid)e.Source));
}
}
/// <summary>
/// 拖动逻辑
/// </summary>
/// <param name="obj"></param>
private void onDragDelta(object obj)
{
if (obj is DragDeltaEventArgs e)
{
if (((System.Windows.FrameworkElement)e.Source).DataContext is ObjEntity t)
{
var m = ((System.Windows.FrameworkElement)e.Source).Margin;
MarginValue = $"; m.Left={m.Left} + e.HorizontalChange={e.HorizontalChange} ;;m.Top={m.Top} + e.VerticalChange={e.VerticalChange};; m.Right={m.Right};;m.Bottom={m.Bottom}";
((System.Windows.FrameworkElement)e.Source).Margin = new Thickness(m.Left + e.HorizontalChange, m.Top + e.VerticalChange, m.Right, m.Bottom);
}
}
}
/// <summary>
/// 线头
/// </summary>
private ObservableCollection<ObjEntity> _objSource = new ObservableCollection<ObjEntity>();
public ObservableCollection<ObjEntity> objSource
{
get { return _objSource; }
set { SetProperty(ref _objSource, value); }
}
/// <summary>
/// 方框
/// </summary>
private ObservableCollection<ObjEntity> _objSource2 = new ObservableCollection<ObjEntity>();
public ObservableCollection<ObjEntity> objSource2
{
get { return _objSource2; }
set { SetProperty(ref _objSource2, value); }
}
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("ContentRegion", typeof(Views.PrismUserControl1));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
// throw new NotImplementedException();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
总结
本文功能只是一个很简陋的Demo希望对大家有帮助。发辉你们的想想去拓展它吧。
源码下载
————————————————
版权声明:本文为CSDN博主「redfox6843」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/redfox6843/article/details/126117819
2379

被折叠的 条评论
为什么被折叠?



