缓慢平移和缩放在WPF [英] Slow pan and zoom in WPF

查看:205
本文介绍了缓慢平移和缩放在WPF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经绘制的线条和文字的一个很好的协议在WPF几个画布。我已经使用了最轻便的元素可能在WPF: DrawingVisual

I have drawn a good deal of lines and texts on several canvases in WPF. I have used the most lightweight element possible in WPF: DrawingVisual

我得出一个不同的画布,我行已绑定的厚度来缩放因子的倒数,使变焦时,我可以得到均匀的线条粗细。当我缩放我只是重绘与线画布手段。与文本的画布仅在程序开始创建的。

I have drawn lines on a different canvas and I have bound their thickness to the inverse of the zoom factor so that I can get a uniform line thickness while zooming. That means when I'm zooming I'm only redrawing the canvas with the lines. The canvas with the texts is only created at the start of the program.

现在我遇到了一个相当奇怪的问题。当我变焦我得到一个缓慢的表现。当我用虚线样式表现变得更糟。慢,当你输入一个字装入一个大的文本文件一样,你必须滚动它的问题!

Now I have encountered a rather odd problem. When I'm zooming I'm getting a slow performance. The performance gets worse when I use dashed line style. Slow like when you load a big text file in a word and you have problems scrolling it!

我的第一个念头是,也许行的创建正在太多。自从我创建的各缩放(鼠标滚轮),所以我用一个温和秒表来测量它需要我的时候滚动鼠标滚轮,直到行的创建结束之间的时间。出乎我的意料,只需要1毫秒!因此,线的创建不能成为问题。

My first thought was that maybe the creation of the lines is taking too much. Since I'm creating those at each zoom (On mouse wheel), So I used a modest stopwatch to measure the time it takes between when I scroll mouse wheel till the creation of the lines ends. To my surprise it only takes 1 ms! So the creation of the lines cannot be the issue.

通过进一步的检查我想通了,我得到一个相当缓慢的性能,同时平移!慢就像当你一个艰难的平移非常非常大的图像窗口!

With further examination I figured out that I'm getting a rather slow performance while panning! Slow like when you a trying to pan in very very big image in windows!

所以,可能是什么问题呢?我知道你会想一些代码,但因为代码是很长,我会只显示在鼠标滚轮发生的事情事件:

So what could be the problem? I know you will want some code but since the code is very long I'll only show what goes on inside Mousewheel event:

private void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
    var sw = new Stopwatch();
    sw.Start();

    var st = GetScaleTransform(Window);
    var tt = GetTranslateTransform(Window);

    var absoluteX = MousePos.Current.X * st.ScaleX + tt.X;
    var absoluteY = MousePos.Current.Y * st.ScaleY + tt.Y;

    const double zoomfactorforwheel = 1.3;
    if (e.Delta > 0)
    {
        st.ScaleX = Math.Min(st.ScaleX * zoomfactorforwheel, Scalemax);
        st.ScaleY = Math.Min(st.ScaleY * zoomfactorforwheel, Scalemax);
    }
    else
    {
        st.ScaleX = Math.Max(st.ScaleX / zoomfactorforwheel, Scalemin);
        st.ScaleY = Math.Max(st.ScaleY / zoomfactorforwheel, Scalemin);
    }
    tt.X = absoluteX - MousePos.Current.X * st.ScaleX;
    tt.Y = absoluteY - MousePos.Current.Y * st.ScaleY;

    Scale = st.ScaleX;

    // Inside this function I'm drawing the lines on drawingvisual
    // Then I'm adding the drawingvisual to a canvas
    DrawZeroWidthDrawing(Scale);

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}



我开始想,也许它必须做一些事情的方式事情变得有多么鼠标按钮在WPF得到处理呈现在WPF,或者?的这看起来像是用鼠标事件的频率干扰的。 。任何建议都非常赞赏。

I'm starting to think that maybe it has to do something with the way things get rendered in WPF, or maybe with how mouse buttons are getting handled in WPF? It seems like something is interfering with mouse event frequency. Any suggestions are very appreciated.

更​​新:我试图实现什么GameAlchem​​ist在我的代码让我吃惊的是仍然缓慢说

Update: I have tried to implement what GameAlchemist said in my code to my surprise it is still slow.

private MouseWheelEventArgs e;
private bool zoomNeeded;

CompositionTarget.Rendering += CompositionTargetOnRendering;

private void CompositionTargetOnRendering(object sender, EventArgs eventArgs)
{
    if (zoomNeeded)
    {
        zoomNeeded = false;
        DoZoom();

        DrawZeroWidthDrawing();              
    }
}

private void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
    this.e = e;
    zoomNeeded = true;
}

private void DoZoom()
{
    var st = GetScaleTransform(Window);
    var tt = GetTranslateTransform(Window);

    var absoluteX = MousePos.Current.X * st.ScaleX + tt.X;
    var absoluteY = MousePos.Current.Y * st.ScaleY + tt.Y;

    const double zoomfactorforwheel = 1.3;
    if (e.Delta > 0)
    {
        st.ScaleX = Math.Min(st.ScaleX * zoomfactorforwheel, Scalemax);
        st.ScaleY = Math.Min(st.ScaleY * zoomfactorforwheel, Scalemax);
    }
    else
    {
        st.ScaleX = Math.Max(st.ScaleX / zoomfactorforwheel, Scalemin);
        st.ScaleY = Math.Max(st.ScaleY / zoomfactorforwheel, Scalemin);
    }
    tt.X = absoluteX - MousePos.Current.X * st.ScaleX;
    tt.Y = absoluteY - MousePos.Current.Y * st.ScaleY;

    Scale = st.ScaleX;            
}

private static TranslateTransform GetTranslateTransform(UIElement element)
{
    return (TranslateTransform)((TransformGroup)element.RenderTransform)
      .Children.First(tr => tr is TranslateTransform);
}

private static ScaleTransform GetScaleTransform(UIElement element)
{
    return (ScaleTransform)((TransformGroup)element.RenderTransform)
      .Children.First(tr => tr is ScaleTransform);
}



我想通了,也许重绘行是罪魁祸首,但它似乎不是!我删除调用,实际上与新的厚度重绘他们,只剩比例部分的功能​​。结果并没有改变!我仍然缺乏的表现。

I figured out maybe redrawing the lines is the culprit but it seems not! I removed the call to the function that actually redraws them with the new thicknesses and only left the scaling part. The result didn't change! I'm still lacking performance.

private void CompositionTargetOnRendering(object sender, EventArgs eventArgs)
{
    if (zoomNeeded)
    {
        zoomNeeded = false;
        DoZoom();
    }
}



我试图来衡量使用WPF的性能工具的FPS,它属于回到16〜24变焦过程中

推荐答案

好吧,我的建议是:在你所有的事件处理程序,执行不画或修改任何有关渲染。由于该事件可能屏幕刷新(= 16毫秒为60Hz的画面)时触发一次以上,所以你最终可能会重新绘制几次没有结果
以便处理一些标志:在计算机图形学中,我们常说这些脏的标志,但称他们为你想要的。在这里,您可以使用两个布尔变量,可能是私人财产,我们姑且称之为 linesNeedsRedraw renderTransformNeedsUpdate (例如)。<通过 lineNeedsRedraw = TRUE ; BR>
现在在mouseWheelHandler,例如,只需更换您的来电 DrawZeroWidthDrawing(量表)。在鼠标移动处理器,取代 renderTransformNeedsUpdate =真正的你的RenderTransform变化;

Ok, Here's my advice : in all your events handler, do not draw or modify anything related to the render. Because the events might trigger more than once during a screen refresh (=16ms for 60Hz screen), so you might end up redrawing several times for nothing.
So handle some flags : in computer graphics, we often call them 'dirty' flags, but call them as you want. Here you might use two bools that might be private properties, let's call them linesNeedsRedraw and renderTransformNeedsUpdate (for instance).
Now in the mouseWheelHandler, for instance, just replace your call to DrawZeroWidthDrawing(Scale); by lineNeedsRedraw = true;. In the mouse move handler, replace your RenderTransform change by renderTransformNeedsUpdate=true;.

第二件事:勾上 CompositionTarget.Rendering 事件的方法。这个方法很简单:

Second thing : hook a method on CompositionTarget.Rendering event. This method will be very simple :

void repaintIfRequired() {
    if (linesNeedRedraw) {
       DrawZeroWidthDrawing(Scale);
       linesNeedRedraw = false;
    }
    if (renderTransformNeedsUpdate) {
       // ... do your transform change
       renderTransformNeedsUpdate = false;
    }
}



这种方式,你有一个最大的每帧更新。

This way you have a maximum of one update per frame.

我会一个问题结束:何不也用的RenderTransform做缩放

I'll end by a question : why not also use the renderTransform to do the scaling ?

好?运气。

这篇关于缓慢平移和缩放在WPF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆