WPF 线段Line过长渲染出现的问题

来源:互联网 发布:吉林顺通网络的骗局 编辑:程序博客网 时间:2024/05/29 19:58

在使用WPF的时候,可以做一个实验,在canvas里添加一条线段LineStrokeThickness属性设置为1,然后通过放大canvas或者调整line起终点,将线段变得很长,你会发现一个奇怪的问题:线段不见了。当你把StrokeThickness设置成2时,它又出现了。

CodeProjectStackOverFlow上也有人提出过类似的问题:

==========================================================================================================================================

http://www.codeproject.com/Questions/192350/Elements-disappearing-on-large-Canvas 

I have a large Canvas which can be scrolled horizontally. My Canvas contains little lines (StrokeThickness = 1) positioned uniformly. 

When I scroll to right the lines start to disappear and appear when reaching an horizontal offset of 8.000.000 (more or less). How can I fix it?
 
Here an example. 10 lines to left, 10 lines to right. The first lines are visible while the last ones are partially visible (5 visible, 5 not).

<Window x:Class="WpfApplication.Window1"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    Title="Window1" Height="300" Width="300">    <Grid>        <ScrollViewer HorizontalScrollBarVisibility="Visible">            <Canvas Width="15000000">                <Line Canvas.Left="0" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="5" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="10" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="15" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="20" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="25" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="30" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="35" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="40" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="45" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999950" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999955" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999960" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999965" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999970" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999975" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999980" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999985" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999990" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />                <Line Canvas.Left="14999995" X1="0" X2="0" Y1="0" Y2="100" Stroke="Black" StrokeThickness="1" />            </Canvas>        </ScrollViewer>    </Grid></Window>


Thanks,

 

部分回复:

Solution 1

Instead of using a canvas that's THAT frickin' wide, I'd be owner drawing only what's visible. You're just asking for trouble trying to do it this way. 

Since a monitor normally isn't any wider than about 2000 pixels, there's no point in making an image that's 15,000,000 pixels wide.

Solution 2

In this page http://connect.microsoft.com/VisualStudio/feedback/details/731467/disappearing-path-wp[^] you can find the reason of why the lines disappear.
I had the same problem, then i split the lines in function of its length


========================================================================================================================

http://stackoverflow.com/questions/9138891/long-lines-dont-render-correctly

I have a project with a canvas that the user can zoom and pan using the mouse. The origin is marked with a blue cross running through the canvas.

 As the user zooms in the line width of the markers is reduced to keep the them about 1 pixel wide on screen. However, after zooming in about 10x 

the origin lines abruptly disappear. It seems like the rendering engine is deciding that the line is too small to be displayed before applying the 

scaling transform.

What is strange is that when I do the same operation to a rectangle instead of a line I get the expected behavior (see the ScaleBox rectangle 

object in the code below). Any ideas on what is causing the problem and how to fix it would be welcome.

Here is the relevant XAML:

  <Canvas x:Name="MouseCapture" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="WhiteSmoke" >    <Canvas x:Name="ZoomPan">        <Canvas.RenderTransform >            <MatrixTransform x:Name="_zoomPanTransform" />        </Canvas.RenderTransform>        <Rectangle x:Name="ScaleBox" Width="100" Height="100" Canvas.Left="-50" Canvas.Top="-50" Stroke="Black"/>        <Line x:Name="YOrigin" X1="-5000" X2="5000" Y1="0" Y2="0" Stroke="Blue" />        <Line x:Name="XOrigin" X1="0" X2="0" Y1="-5000" Y2="5000" Stroke="Blue" />    </Canvas></Canvas>

And the code behind:

Private Sub ZoomControl_PreviewMouseWheel(sender As Object, e As System.Windows.Input.MouseWheelEventArgs) Handles MouseCapture.PreviewMouseWheel    Dim scale As Double    If e.Delta > 0 Then        scale = 0.95    Else        scale = 1 / 0.95    End If    Dim center As Point = e.GetPosition(MouseCapture)    Dim zoom As New ScaleTransform(scale, scale, center.X, center.Y)    _zoomPanTransform.Matrix *= zoom.Value    UpdateLineWidth()End SubPrivate Sub UpdateLineWidth()    ScaleBox.StrokeThickness = 1 / _zoomPanTransform.Matrix.M11    XOrigin.StrokeThickness = 1 / _zoomPanTransform.Matrix.M11    YOrigin.StrokeThickness = 1 / _zoomPanTransform.Matrix.M11End Sub

Here is a screenshot when everything is working.

Here is a screenshot as 10x Zoom. The origin lines have disappeared abruptly, but the black box still shows up as expected. 

(Note that only one side of the black box is visible because the rest is outside the visible region because of the zoom.)


部分回复:

The problem was that the line was too long. If I reduce the length of the origin lines dynamically so that they are roughly the same length as the canvas, 

everything displays as expected. If the line gets to be 100x or so longer than the canvas they abruptly disappear. This is probably due to some rounding 

errors or optimization scheme.

=====================================================================================================================

从以上回复中我们可以找到一点信息:

http://connect.microsoft.com/VisualStudio/feedback/details/731467/disappearing-path-wp

问题:Path with linegeometry disappears

评论:

This is an interesting limit to the processing of WPF vector graphics - in both hardware and software. Empirically, it seems that horizontal or vertical lines 

are limited by some ratio related to their stroke thickness.

Here is a table I determined experimentally:

Stroke Thickness     Maximum Length (horizontal or vertical)
.07                 8750
.8                    100,000
.9                    112,500
1                     125,000
3                     375,000
5                     625,000
10                    1,250,000
100                 12,500,000
1000                 125,000,004
10000                 1,250,000,063
100000                12,500,000,255

This scenario seems to impact a very small number of customers, and there are a couple of workarounds:
1) Introduce a slight diagonal component dramatically increases the limit.
2) Break very long horizontal or vertical lines into pieces.
3) Tweak the thickness a bit.

We apologize for the inconvenience this issue has caused, and we hope you are still successful using WPF in your project.

============================================================================================================================

另外,我在MSDN上找到下面的资料,其中就提到了这一点注意事项:

MSDN: FrameworkElement. Width 属性

这是 FrameworkElement 上的三个用于指定宽度信息的属性之一。 另外两个是 MinWidth 和 MaxWidth。 如果这三个值之间存在冲突,则应用程序确定宽度的实际顺序是:首先必须采用 MinWidth;然后采用 MaxWidth;最后,如果这些值中的每个值都在限制之内,则采用 Width。 

此属性的返回值总是与为它设置的任何值相同。与之相反, ActualWidth 的值可能不同。 布局可能已经由于某个原因拒绝了建议的大小。另外,布局系统本身相对于属性系统的 Width 集以异步方式工作,因而可能尚未处理特定大小调整属性的更改。 

除了可接受的 Double 值以外,此属性还可以是 Double. NaN 。 此值可用来指定自动调整大小行为。在 XAML 中,可以将该值设置为字符串 "Auto"(不区分大小写)以启用自动调整大小行为。自动调整大小行为意味着元素将填满它可以利用的宽度。但请注意,特定控件通常通过它们的默认样式来提供默认值,以禁用自动调整大小行为,除非特地重新启用了该行为。

除了验证检查以外, Width 还有一个由布局系统实施的非确定性上限值(此值是一个非常大的数字,大于 Single. MaxValue ,但小于 Double. MaxValue )。 如果超出此上限值,元素将不会呈现,并且不会引发异常。不要将 Width 设置为一个远远大于任何可能的视觉显示的最大大小,否则有可能超出此非确定性上限。 

=============================================================================================================================

总的来说,问题出现的原因与WPF本身的机制有关,简单地分析就是因为line过长,超出了某个上限值,深层的原因还需要进一步了解。