Photoshop上的画布绘制形状滞后

时间:2015-02-12 11:45:30

标签: wpf

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

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

您可以下载示例项目here

当鼠标快速移动时,图片上的内容就像:

enter image description 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,也计时器每隔20ms改变第二个点,但它没有帮助。

我有遗留项目,代码在很大程度上依赖于这种方法(canvas mouseMove和shapes)。因此,我需要最简单的方法来消除这种滞后或关于此错误原因的一些想法)谢谢。

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

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

我也尝试使用WritableBitmap绘制线 - 没有区别。

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

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

2 个答案:

答案 0 :(得分:1)

这是无法修复的,因为这是由WPF的内部渲染系统引起的。即使视觉树很简单,总会有延迟。复杂的可视化树导致更多延迟。我花了很多时间来解决这个问题。

答案 1 :(得分:0)

请不要在主画布上而是在Window本身上使用MouseMove事件。 我最近在MouseMove上使用Image时遇到了同样的问题,这很糟糕 切换到window的事件对我很有帮助。

<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;
        }