主要使用布局面板Canvas作为背景,通过其属性Children添加Line 来实现画线。可以理解为 每一个Line 就是一个点。
不清楚Canvas的用法可以参见:点击打开链接 Line的参见:点击打开链接
代码解析
线由点组成,当然我这里的点其实就是线。线由开始点与结束点构成,想必看到过msdn上line的解释就会一目了然。至于鼠标事件,会有鼠标左键按下以及移动,松开动作。 还需要有个一集合来存放点,取名为List<Point> 类型。 在鼠标按下事件中可以这样写:
/// <summary>
/// 起始位置
/// </summary>
Point startPoint;
/// <summary>
/// 点集合
/// </summary>
List<Point> pointList = new List<Point>();
/// <summary>
/// 鼠标左键按下获取开始Point
/// </summary>
private void Canvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(myCanvas);
}
记录开始位置startPoint 。按下之后随之的就是Move动作,在移动事件中这样写:
/// <summary>
/// 按下鼠标左键移动
/// </summary>
private void Canvas_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
// 返回指针相对于Canvas的位置
Point point = e.GetPosition(myCanvas);
if (pointList.Count == 0)
{
// 加入起始点
pointList.Add(new Point(this.startPoint.X, this.startPoint.Y));
}
else
{
// 加入移动过程中的point
pointList.Add(point);
}
// 去重复点
var disList = pointList.Distinct().ToList();
var count = disList.Count(); // 总点数
if (point != this.startPoint && this.startPoint != null)
{
var l = new Line();
string color = (cboColor.SelectedItem as ComboBoxItem).Content as string;
if (color == "默认")
{
l.Stroke = Brushes.Black;
}
if (color == "红色")
{
l.Stroke = Brushes.Red;
}
if (color == "绿色")
{
l.Stroke = Brushes.Green;
}
l.StrokeThickness = 1;
if (count < 2)
return;
l.X1 = disList[count - 2].X; // count-2 保证 line的起始点为点集合中的倒数第二个点。
l.Y1 = disList[count - 2].Y;
// 终点X,Y 为当前point的X,Y
l.X2 = point.X;
l.Y2 = point.Y;
myCanvas.Children.Add(l);
}
}
}
移动过程中创建Line对象并加入Canvas中。 代码中的颜色判断最好修改成枚举类型。
/// <summary>
/// 选择颜色
/// </summary>
private void cboColor_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string color = (cboColor.SelectedItem as ComboBoxItem).Content as string;
if (this.myCanvas != null)
{
List<Line> list = GetChildObjects<Line>(this.myCanvas);
if (list.Count > 0)
{
list.ForEach(l =>
{
if (color == "默认")
{
l.Stroke = Brushes.Black;
}
if (color == "红色")
{
l.Stroke = Brushes.Red;
}
if (color == "绿色")
{
l.Stroke = Brushes.Green;
}
});
list.Clear();
}
}
}
/// <summary>
/// 选择style
/// </summary>
private void cboStyle_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string style = (cboStyle.SelectedItem as ComboBoxItem).Content as string;
if (this.myCanvas == null)
{
return;
}
List<Line> list = GetChildObjects<Line>(this.myCanvas);
if (list.Count > 0)
{
list.ForEach(l =>
{
if (style == "默认")
{
l.StrokeDashArray = new DoubleCollection(new List<double>() { });
}
if (style == "虚线")
{
l.StrokeDashArray = new DoubleCollection(new List<double>() {
1,1,1,1
});
}
});
list.Clear();
}
}
前台XAML
主要用到了WrapPanel,StackPanel布局控件。
<WrapPanel>
<StackPanel>
<WrapPanel>
<Label Content="颜色:" VerticalAlignment="Center"></Label>
<ComboBox x:Name="cboColor" SelectedIndex="0" Width="120" Margin="10" SelectionChanged="cboColor_SelectionChanged">
<ComboBoxItem>默认</ComboBoxItem>
<ComboBoxItem>红色</ComboBoxItem>
<ComboBoxItem>绿色</ComboBoxItem>
</ComboBox>
</WrapPanel>
<WrapPanel>
<Label Content="样式:" VerticalAlignment="Center"></Label>
<ComboBox x:Name="cboStyle" Width="120" Margin="10" SelectionChanged="cboStyle_SelectionChanged">
<ComboBoxItem IsSelected="True">默认</ComboBoxItem>
<ComboBoxItem>虚线</ComboBoxItem>
</ComboBox>
</WrapPanel>
</StackPanel>
<Canvas Width="500" Height="500" Background="Gray" x:Name="myCanvas" PreviewMouseLeftButtonDown="Canvas_PreviewMouseLeftButtonDown" PreviewMouseMove="Canvas_PreviewMouseMove">
</Canvas>
</WrapPanel>
/// <summary>
/// 获得指定元素的所有子元素
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public List<T> GetChildObjects<T>(DependencyObject obj) where T : FrameworkElement
{
DependencyObject child = null;
List<T> childList = new List<T>();
for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
{
child = VisualTreeHelper.GetChild(obj, i);
if (child is T)
{
childList.Add((T)child);
}
childList.AddRange(GetChildObjects<T>(child));
}
return childList;
}