【问题标题】:canvas draw shape on MouseMove lag画布在 MouseMove 滞后上绘制形状
【发布时间】:2015-02-12 11:45:30
【问题描述】:

我有一个非常简单的场景:有一个画布,我需要使用 MouseMove 在画布上画一条线。但是当我移动鼠标指针时,第二行的点(在鼠标移动中设置)与当前鼠标位置不匹配。

UPD 2: Delta 取决于鼠标的速度,如果速度很大 - delta 很大并且很明显(滞后)。 我注意到如果你移动鼠标的速度不是很快也不是很慢,这个错误会更明显.

您可以下载示例项目here

鼠标快速移动时图片上的东西:

一些源代码:

<Window x:Class="WpfApplication32.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Width="525"
    Height="350">
<Canvas x:Name="MainCanvas"
        MouseLeftButtonDown="MainCanvas_OnMouseLeftButtonDown"
        MouseMove="MainCanvas_OnMouseMove"
        Background="White"
        />

    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Shapes;

    namespace WpfApplication32
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private Line _currentLine;
            private bool _isDrawing;

            public MainWindow()
            {
                InitializeComponent();

                this.Loaded += OnLoaded;
            }

            private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
            {
                MainCanvas.Focus();
            }

            private void MainCanvas_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                if (_isDrawing)
                {
                    _currentLine = null;
                    _isDrawing = false;
                    return;
                }

                _isDrawing = true;

                _currentLine = new Line(){Stroke = Brushes.Green};

                var p = e.GetPosition(MainCanvas);

                _currentLine.X1 = p.X;
                _currentLine.Y1 = p.Y;
                _currentLine.X2 = p.X;
                _currentLine.Y2 = p.Y;
                MainCanvas.Children.Add(_currentLine);
            }

            private void MainCanvas_OnMouseMove(object sender, MouseEventArgs e)
            {
                if (_currentLine == null)
                    return;

                var p = e.GetPosition(MainCanvas);
                _currentLine.X2 = p.X;
                _currentLine.Y2 = p.Y;
            }
        }
    }

我尝试使用 CompositeTarget.Render,还有每 20 毫秒更改第二个点的计时器,但没有帮助。

我有一个遗留项目,其中代码很大程度上依赖于这种方法(画布鼠标移动和形状)。所以我需要最简单的方法来消除这种滞后或一些关于这个错误原因的想法)谢谢。

统一更新: 我试过用这个问题录制视频,但我不擅长。这是我录制的一些屏幕以显示问题: http://prntscr.com/64hueg

UPD 2: 我尝试在没有画布的情况下使用 Window 对象的 OnRender 来做同样的事情。我已经使用 DataContext 来画线 - 这里有同样的问题。 DataContext 被认为比 Canvas 和 Line (Shape) 更快。所以这不是 Canvas 的问题。

我也尝试使用 WritableBitmap 来画线 - 没有区别。

我认为 MouseMove 事件可能存在问题 - 我读到是否有很多对象(不是我的情况,但仍然如此) MouseMove 可能会延迟触发,所以我使用了 Win32 WM_MOUSEMOVE 但它也没有帮助。在我的情况下,MW_MOUSEMOVE 和 wpf MouseMove 事件之间的延迟是

到目前为止,我看到的唯一答案是渲染延迟。我不知道如何改进它,因为它是 wpf internals =(. 顺便说一下,Paint.net 似乎使用 wpf,并且那里也出现了这个问题。

【问题讨论】:

  • 嗨,我试过你的源,它工作得很好,我没有看到线边缘和当前鼠标位置之间有任何偏移!!...你使用的是什么点网?跨度>
  • 嗨@joseph,我使用的是.net 4.0。我的 CPU 是 i3570k,我使用 hd4000 集成显卡。但是这个问题不仅仅出现在我的机器上,我在队友机器和客户机器上都重现了它。也许我的描述不好)当您快速移动鼠标时出现偏移,该行的第二个点开始与当前鼠标位置不匹配。更快的速度 - 第二点和当前鼠标位置(滞后)之间的空间更大。谢谢
  • 我将inkCanvas用于同样的目的,没有遇到任何问题。也许你可以试一试。
  • InkCanvas 也有同样的问题。据我所知,这无法修复,因为 WPF 内部渲染系统总会有延迟。

标签: wpf


【解决方案1】:

这是由于 WPF 的内部渲染系统造成的,因此无法修复。即使视觉树很简单,也总会有滞后。复杂的视觉树会导致更多延迟。我花了很多时间试图解决这个问题。

【讨论】:

  • 哦。我也遇到了这个问题。我猜 WPF 根本不擅长快速绘图..
【解决方案2】:

尝试不在主画布上而是在窗口本身上使用MouseMove 事件。 我最近在Image 上使用MouseMove 遇到了同样的问题,而且它非常滞后 切换到窗口的事件对我帮助很大。

<Window x:Name="Window1" x:Class="WpfApp2.MViewer"
        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:WpfApp2"
        mc:Ignorable="d"
        Title="MViewer" Height="454.411" Width="730.515" Loaded="Window_Loaded" Closing="Window1_Closing" ContentRendered="Window1_ContentRendered" MouseMove="Window1_MouseMove">
    <Grid>
        <Image x:Name="Image1" MouseMove="Image1_MouseMove"/>
        <Line Name="Line1" Visibility="Visible" Stroke="Red" StrokeThickness="0.75" />
        <Line Name="Line2" Visibility="Visible" Stroke="Red" StrokeThickness="0.75" />
    </Grid>
</Window>

        private void Window1_MouseMove(object sender, MouseEventArgs e)
        {
            Line1.Visibility = Visibility.Visible;
            Line1.X1 = Mouse.GetPosition(this).X;
            Line1.X2 = Mouse.GetPosition(this).X;
            Line1.Y1 = 0;
            Line1.Y2 = Window1.Height;

            Line2.Visibility = Visibility.Visible;
            Line2.X1 = 0;
            Line2.X2 = Window1.Width;
            Line2.Y1 = Mouse.GetPosition(this).Y;
            Line2.Y2 = Mouse.GetPosition(this).Y;
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    • 2012-04-25
    • 2012-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多