WPF使用Canvas绘制线条命中测试问题

需求描述

最近在使用WPF绘制图表的一个项目,图表中有很多线段,并且需要点击线段的时候可以选中,由于线条很细,不容易点击到,这里需要用户在点击线条附近的时候,默认他点击了线条。

在这里插入图片描述

解决思路

我们将线条画的很粗,但是使用渐变,将上下的颜色透明,这样线条看起来还是很细,但是点击的时候,当你点击到附近的时候也是命中的。
在这里插入图片描述
如图红色框都是可以命中区域。

在这里插入图片描述
渐变值说明

  • 0.3 线条的上30%是透明的,透明度为0
  • 0.301 增加一个最小单位,立刻设置为你想显示的颜色,并且 透明度设置为1
  • 0.69 同上
  • 0.7 这里和0.3 对应

全部代码

前端代码:

<Window x:Class="WpCanvas.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:WpCanvas"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel Orientation="Vertical">
            <Rectangle x:Name="_color" Margin="0 10" Width="100" Height="30">
                <Rectangle.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#00CB4545" Offset="0.3"/>
                        <GradientStop Color="#FF2B1A1A" Offset="0.301"/>
                        <GradientStop Color="#FF2B1A1A" Offset="0.699"/>
                        <GradientStop Color="#00CECECE" Offset="0.7"/>
                    </LinearGradientBrush>
                </Rectangle.Fill>
                
            </Rectangle>

            <local:DrawingCanvas x:Name="_canvas" MouseUp="_canvas_MouseUp">

            </local:DrawingCanvas>
        </StackPanel>


    </Grid>
</Window>

后端代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpCanvas
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Drwaw(100);
            Drwaw(140);
        }

        /// <summary>
        /// 绘制时间线
        /// </summary>
        private void Drwaw(double y)
        {

            Point p1 = new Point(200, y);
            Point p2 = new Point(400, y);

            this._canvas.DrawLine(p1, p2, _color.Fill, 4, null, "线条");
        }

        private void _canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            string key = this._canvas.GetVisualKey(e.GetPosition(sender as UIElement));

            MessageBox.Show($"选择 {key}");
          
        }
    }
}

注意事项

这种方式,只有在线条很细的情况下适用,如果你的线条够粗,那么你可能要适当的减少上下的透明区域,甚至不要透明区域。

<think>好的,用户想要在C# WPF使用MvvmLight框架进行CAD绘图的示例代码。首先,我需要回忆一下MvvmLight的基本结构,它主要用于MVVM模式,分离视图、模型和视图模型。CAD绘图通常涉及图形绘制和用户交互,比如鼠标事件处理。 接下来,我应该考虑如何在WPF中实现绘图功能。WPF有丰富的图形库,比如Shape类及其派生类(Line、Rectangle等),或者使用Path和Geometry来绘制复杂图形。同时,用户可能需要处理鼠标事件来进行绘图操作,比如点击、拖拽等,这需要路由事件的处理,如引用[3]中提到的路由事件侦听器。 然后,结合MVVM模式,需要将绘图逻辑放在ViewModel中,而不是代码后台。这就需要使用命令(Command)来处理用户输入,比如鼠标点击和移动。MvvmLight提供了RelayCommand,可以方便地绑定命令到ViewModel。 另外,数据绑定是关键。绘图元素可能需要绑定到ViewModel中的集合,比如ObservableCollection<Shape>,这样当添加或修改图形时,视图会自动更新。同时,命中测试(如引用[4]提到的)可能用于检测用户点击了哪个图形,这可以通过ModelUIElement3D或自定义的命中测试方法实现。 还需要考虑如何保存和加载图形数据,可能涉及将图形对象序列化,或者转换为视图模型中的数据结构。性能方面,如果图形复杂,可能需要优化渲染,比如使用虚拟化或简化图形数据。 用户提供的引用[2]提到WPF的矢量图形不会失真,适合CAD绘图。所以使用Path或Geometry来绘制线条、多边形等是合适的。引用[1]中的自定义控件绘制方法可能对美化界面有帮助,但核心是绘图逻辑。 现在需要将这些元素整合到MvvmLight框架中。例如,在ViewModel中定义命令来处理绘图动作,使用ObservableCollection保存图形数据,并在视图中通过ItemsControl绑定,使用DataTemplate将图形数据转换为WPF的Shape元素。 可能的步骤: 1. 创建ViewModel,包含绘图命令和图形集合。 2. 在视图中使用ItemsControl绑定到图形集合,用Canvas作为ItemsPanel以便定位。 3. 实现鼠标事件处理,通过命令将事件传递给ViewModel。 4. ViewModel处理绘图逻辑,更新图形集合。 5. 可能需要自定义行为或附加属性来处理鼠标交互,保持MVVM的分离。 需要注意的是,复杂的CAD功能如撤销/重做、图层管理、图形编辑等可能需要更复杂的结构,但示例代码应保持简单,演示基本绘图流程。同时,引用[3]中的路由事件处理可能需要适配到MVVM模式,使用命令而不是事件处理代码。 最后,确保代码示例正确使用MvvmLight的ViewModelLocator、RelayCommand等,并展示数据绑定和命令绑定的方式。可能还需要使用INotifyPropertyChanged来通知属性变更。</think>### C# WPF MvvmLight CAD 绘图实现思路 #### 1. MVVM 架构设计 - **ViewModel** 中定义图形集合和绘图命令: ```csharp public class MainViewModel : ViewModelBase { public ObservableCollection<ShapeViewModel> Shapes { get; } = new ObservableCollection<ShapeViewModel>(); public RelayCommand<MouseEventArgs> StartDrawingCommand { get; } public RelayCommand<MouseEventArgs> DrawingCommand { get; } } ``` - 使用 `ObservableCollection` 实现图形数据与 UI 的自动同步[^2] #### 2. 图形数据与视图绑定 - 通过 `ItemsControl` 绑定图形集合,并用 `Canvas` 实现自由绘图: ```xml <ItemsControl ItemsSource="{Binding Shapes}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Path Data="{Binding Geometry}" Stroke="Black" StrokeThickness="2"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> ``` - 使用 `Path` 控件实现矢量图形绘制 #### 3. 鼠标交互处理 - 创建附加属性处理画布事件: ```csharp public static class CanvasBehavior { public static readonly DependencyProperty IsDrawingProperty = DependencyProperty.RegisterAttached(...); private static void OnIsDrawingChanged(DependencyObject d, ...) { if (element is UIElement uie) { if ((bool)e.NewValue) { uie.MouseLeftButtonDown += StartDrawing; uie.MouseMove += Drawing; } } } } ``` #### 4. ViewModel 绘图逻辑 ```csharp private void StartDrawing(MouseEventArgs e) { var startPoint = e.GetPosition((IInputElement)e.Source); _currentShape = new PathGeometry(); _currentFigure = new PathFigure { StartPoint = startPoint }; _currentShape.Figures.Add(_currentFigure); } private void Drawing(MouseEventArgs e) { if (_currentFigure != null) { var point = e.GetPosition((IInputElement)e.Source); _currentFigure.Segments.Add(new LineSegment(point, true)); RaisePropertyChanged(nameof(Shapes)); } } ``` #### 5. 命令绑定配置 ```xml <Canvas local:CanvasBehavior.IsDrawing="True" mvvm:EventToCommand.Event="MouseLeftButtonDown" mvvm:EventToCommand.Command="{Binding StartDrawingCommand}"/> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云端上的蚂蚁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值