Horizontal or vertical WPF Lines limited to 125,000 pixels? - wpf

Are horizontal or vertical WPF Lines limited to 125,000 pixels? Looking at the following code the Green line displays correctly but the Red one does not display at all despite being just 0.01 longer. Any idea why?
<Window x:Class="DCView.Window11"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window11" Height="300" Width="300">
<ScrollViewer>
<Grid Width="150000">
<Line X1="0" X2="125000.00" Y1="10" Y2="10" StrokeThickness="1" Stroke="Green"></Line>
<Line X1="0" X2="125000.01" Y1="20" Y2="20" StrokeThickness="1" Stroke="Red"></Line>
</Grid>
</ScrollViewer>
</Window>
Andrew

This seems to be a limitation in WPF's handling of vector graphics.
To make it more complicated, try changing the StrokeThickness - if you set the StrokeThickness of your red line from 1 to 2, it displays again... until you increase the length above 250000.. Then it vanishes again.
<Grid>
<Line X1="0" X2="125000.00" Y1="10" Y2="10" StrokeThickness="1" Stroke="Green"></Line>
<Line X1="0" X2="250000.00" Y1="20" Y2="20" StrokeThickness="2" Stroke="Red"></Line>
<Line X1="0" X2="250000.01" Y1="30" Y2="30" StrokeThickness="2" Stroke="Blue"></Line>
</Grid>
The max length goes up as you increase your stroke thickness.
Also Note that if the line wasn't perfectly horizontal or vertical, the length limit seems to vanish:
<Grid>
<Line X1="0" X2="125000.00" Y1="10" Y2="10" StrokeThickness="1" Stroke="Green" />
<Line X1="0" X2="125000.01" Y1="20" Y2="20.0001" StrokeThickness="1" Stroke="Red" />
</Grid>
You can find the bug written up on connect: Disappearing Path (WPF)

It definitely draws past 150,000 pixels, It is a bit strange that the line is not seen in this case, because for example if you do this
<Line X1="0" X2="125000.01" Y1="20" Y2="20" StrokeThickness="2" Stroke="Red"></Line>
or this
<Line X1="0" X2="125000.01" Y1="21" Y2="20" StrokeThickness="1" Stroke="Red"></Line>
all works fine, There is probably a answer somewhere as to why, but good find as this would cause significant flicker if you were animating the value of X2.

Related

How Can I Create A Fully Connected Line With Different Colored Segments In WPF?

Take a look at this picture:
Notice how the line to the left has a clean corner, and the one to the right does not. Here's the XAML I used to create each:
<Canvas Margin="10">
<Polyline Stroke="Green" StrokeThickness="10">
<Polyline.Points>
<Point X="0" Y="0"/>
<Point X="30" Y="50"/>
<Point X="60" Y="0"/>
</Polyline.Points>
</Polyline>
<Line X1="100" Y1="0" X2="130" Y2="50" Stroke="Red" StrokeThickness="10"/>
<Line X1="130" Y1="50" X2="160" Y2="0" Stroke="Blue" StrokeThickness="10"/>
</Canvas>
Obviously the Polyline handles the corners easily, but it doesn't support segments with different colors, which is what I need. Creating separate lines solves this problem, but I lose the clean corners. I need to be able to create a line with the corners of line 1, but the colors of line 2.
My actual application is a line graph, so these lines are created dynamically and could have dozens of segments each with an angle ranging from 0 to 180 degrees.
The only solution I have come across is to use a LinearGradientBrush with Polyline.Stroke, and put in gradient stops where the corners should be. But considering the length of the line and each segment are totally variable and the gradient stops seem to be measured in percentages (from 0 at one end to 1 at the other) it just seems like it would be a pain to calculate and comes off as an over-complicated solution. Is there any simpler way to do this?
Set the start and end caps of the Lines' stroke to Round:
<Line X1="100" Y1="0" X2="130" Y2="50" Stroke="Red" StrokeThickness="10"
StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
<Line X1="130" Y1="50" X2="160" Y2="0" Stroke="Blue" StrokeThickness="10"
StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>

Opacity Lines In Window store app

I have problem when draw lines have opacity.
Source i writing:
<Line X1="50" Y1="50" X2="100" Y2="100" Stroke="Red" StrokeThickness="10" Opacity="0.5" StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
<Line X1="100" Y1="100" X2="150" Y2="100" Stroke="Red" StrokeThickness="10" Opacity="0.5" StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
i would like picture as
you can help me?
thanks
There are many ways to achieve what you're after, but the basis of what you need to do is essentially to group each line inside one container then reduce the opacity of that container rather than the lines themselves.
For example, if you place the Line's inside a Canvas like so:
<Canvas Opacity="0.5">
<Line X1="50" Y1="50" X2="100" Y2="100" Stroke="Red" StrokeThickness="10" StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
<Line X1="100" Y1="100" X2="150" Y2="100" Stroke="Red" StrokeThickness="10" StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
</Canvas>
You can achieve what you're after:
The Canvas is a great tool for dealing with such things, but if really needed it can be substituted with just about any container that can deal with multiple children (such as a grid).
The key is to make the container control the opacity, not the children themselves.

WPF / Xaml, vertical aligment of LineGeomtry inside grid not working properly

I try to get into creation of custom controls with for WPF. I found many good
tutorials and advises on the web so I started width a really simple example to get
my hands dirty and get some practice. I figured out that the issue stumbled across
is not really related to the subject of custom controls. So I extracted the xaml code to a simple wpf form.
<Window x:Class="WpfVerticalAigmentTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="200">
<Grid>
<Grid Height="40" Background="LightCyan" VerticalAlignment="Center">
<Path Stroke="Red"
StrokeThickness="20" VerticalAlignment="Center" >
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="100,0"></LineGeometry>
</Path.Data>
</Path>
</Grid>
</Grid>
My expectation was to get a line centered in the grid and claiming the half of the stroke thickness on each side from the center. But as the linked image shows differs from my expectation.
"Resulting visualization"
So it look like I missed a detail about the line shape or linegeomtry. How do I get the the line displayed as shown in the following image?
"Expected result"
You need to match the Width and Height of the LineGeometry to the Width and Height of the Path and set the VerticalAlignment property to Bottom:
<Grid Height="20" Width="200" Background="LightCyan" VerticalAlignment="Center">
<Path Stroke="Red" StrokeThickness="20" VerticalAlignment="Bottom">
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="200,0"></LineGeometry>
</Path.Data>
</Path>
</Grid>
If your goal is your the expectaions, and not the way how u have reached this, I could prefer to you this:
<Grid>
<Grid Height="40" Background="LightCyan" VerticalAlignment="Center">
<Border BorderThickness="10" VerticalAlignment="Center" BorderBrush="Red" />
</Grid>
</Grid>
The problem here is that the starting point of the XY Coordinates of the Path starts on the top left, and the stroke expands in both directions but thereby only makes the Path bigger to the bottom (I can't really tell you why, but that's just what seems to happen).
You can see this pretty good in the Design View:
To work around this simply move your Y Coordinates down half of the stroke size.
<Grid Height="40"
VerticalAlignment="Center"
Background="LightCyan">
<Path VerticalAlignment="Center"
Stroke="Red"
StrokeThickness="20">
<Path.Data>
<LineGeometry StartPoint="0,10" EndPoint="100,10" />
</Path.Data>
</Path>
</Grid>
Or wrap it in another control (Canvas is the commonly used controls for Paths) with the desired height:
<Grid Height="40"
VerticalAlignment="Center"
Background="LightCyan">
<Canvas Height="20" VerticalAlignment="Center">
<Path Stroke="Red"
StrokeThickness="20">
<Path.Data>
<LineGeometry StartPoint="0,10" EndPoint="100,10" />
</Path.Data>
</Path>
</Canvas>
</Grid>
And you are good to go:

Custom control sizing/placement issue

I'm trying to create a custom control with C#/WPF. See below for the XAML of my control, and a window I'm trying to put it into.
The problem: When I set the HorizontalAlignment or vertical alignment properties to Center, the upper-left corner of the control is centered, but extends down and to the right. The bounding box of the control as shown in the designer is very small (zero width/heigh I think).
It seems like I have a problem with my control not reporting its size properly when the layout is doing its thing. Also, it doesn't seem to resize when Height and Width are adjusted. I have nothing in the code-behind (yet) that alters the appearance of the control (e.g. no Measure overrides).
This is my first attempt at a custom control - probably better ways of doing it (TextBlock comes to mind), but hey, this is how I learn! :D
The XAML defining my control:
<UserControl x:Class="LCD.LiquidCrystalDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignWidth="300" d:DesignHeight="122">
<Canvas>
<Rectangle Fill="#FFD1D1D1" Width="300" Height="122" />
<Rectangle Fill="#FF345534" Margin="12,8,12,8" Width="276" Height="106" />
<Rectangle Fill="#FF293E29" Margin="15,11,15,11" Width="270" Height="100" />
<Line X1="32" X2="32" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="50" X2="50" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="67" X2="67" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="84" X2="84" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="101" X2="101" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="117" X2="117" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="134" X2="134" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="151" X2="151" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="168" X2="168" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="184" X2="184" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="201" X2="201" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="218" X2="218" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="235" X2="235" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="251" X2="251" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="268" X2="268" Y2="111" Y1="11" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="15" X2="285" Y1="36" Y2="36" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="15" X2="285" Y1="61" Y2="61" StrokeThickness="1" Stroke="#FF345534" />
<Line X1="15" X2="285" Y1="86" Y2="86" StrokeThickness="1" Stroke="#FF345534" />
</Canvas>
</UserControl>
And the XAML including it in a window:
<Window x:Class="TestJunk.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:LCD;assembly=LCD"
Title="MainWindow" Height="341" Width="544">
<Grid Name="MainGrid">
<my:LiquidCrystalDisplay Name="lcd" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Window>
This is the behaviour of a Canvas. Here is what MSDN has to say:
Canvas is the only panel element that has no inherent layout
characteristics. A Canvas has default Height and Width properties of
zero, unless it is the child of an element that automatically sizes
its child elements. Child elements of a Canvas are never resized, they
are just positioned at their designated coordinates. This provides
flexibility for situations in which inherent sizing constraints or
alignment are not needed or wanted. For cases in which you want child
content to be automatically resized and aligned, it is usually best to
use a Grid element.
If you want to have the UserControl resize, wrap it around a Viewbox and set a Height and Width to the Canvas.

How can I avoid anti aliasing with WPF?

One of the big problems with WPF is anti aliasing.
In fact, that's why UseLayoutRending was introduced in WPF 4.0.
However, it does not work for me in the following sample:
<StackPanel UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Line X1="0" Y1="0" X2="200" Y2="0" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
<Line X1="0" Y1="1.5" X2="200" Y2="1.5" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
<Line X1="0" Y1="3.5" X2="200" Y2="3.5" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
<Line X1="0" Y1="7" X2="200" Y2="7" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
<Line X1="0" Y1="9" X2="200" Y2="9" StrokeThickness="1" Stroke="Black" SnapsToDevicePixels="True" UseLayoutRounding="True"></Line>
</StackPanel>
The last two lines are still blurry.
(I am using Windows 7)
Any solution?
Or is it a bug in the beta of WPF 4.0?
Floele's answer showed the right direction, but the answer was not complete. Just set the y-values to half a pixel, e.g. Y1="7" -> Y1="7.5"
That's the reason the second and third lines are not blurred.
Getting lines to look sharp in WPF can be quite hard! And some times ... it seems like it takes a bit of black magic too!
I think that floele and Kimke's answers are pointing in correct direction. That is, often times you will want to put single pixel lines on a 0.5 pixel boundary ... given the way that it draws the line (half on one side and half on another).
However, it isn't always that simple either. For example, it also depends on the surrounding xaml. For example, try this code out and resize when you do:
<Canvas HorizontalAlignment="Center" VerticalAlignment="Center">
<Line X1="0" Y1="5" X2="200" Y2="5" StrokeThickness="1" Stroke="Black" UseLayoutRounding="True"/>
<Line X1="0" Y1="15" X2="200" Y2="15" StrokeThickness="1" Stroke="Black" UseLayoutRounding="True"/>
</Canvas>
Then, try this code out (again, resize when you do):
<Canvas HorizontalAlignment="Center" VerticalAlignment="Center" UseLayoutRounding="True">
<Line X1="0" Y1="5" X2="200" Y2="5" StrokeThickness="1" Stroke="Black"/>
<Line X1="0" Y1="15" X2="200" Y2="15" StrokeThickness="1" Stroke="Black"/>
</Canvas>
The only difference between the two snippets is that the first uses UseLayoutRounding on the Lines while the second uses UseLayoutRounding on the Canvas container (which then also property inherit to the Lines).
However, that difference yields some interesting results. When UseLayoutRounding is used on the container the single pixel lines consistently stay spread out over 2 pixels and they don't move around. When UseLayoutRounding is used on the Lines directly, and you resize, the lines will sometimes be 1 pixel sharp ... and other times will be spead over 2 pixels.
And that brings me to the sample xaml in the original question. A few comments on it:
First off, you should realize that both UseLayoutRounding and SnapsToDevicePixels property inherit. That is, if you use it on the layout container it will inherit to the items in the layout container.
UseLayoutRounding and SnapsToDevicePixels shouldn't necessarily be used together. They can be ... but I would normally try using them separately ... either one or the other. More info here: When should I use SnapsToDevicePixels in WPF 4.0?
TextOptions.TextFormattingMode options affect text, not lines.
That StackPanel that you are using as the layout container could also affect how the lines are being laid out. Canvas allows you more precise positioning control of your lines. StackPanel will just layout one line after the other line ... and might yield some unexpected results.
More info than what the original poster was wanting. However, I personally know how tricky it is to get lines sharp in WPF. Hope this info helps someone!
The reason is apparently simpler. I only found an explanation in "Pro WPF in VB 2010" and not on MSDN though: http://books.google.de/books?id=F-gMZkAlUDUC&pg=PA334&lpg=PA334
In short, the StrokeThickness will be divided for both sides of a shape, so a StrokeThickness of 1 equals a thickness of 0.5 for each side, and since the line only has one side, it will be 0.5 units thick and thus appear blurry even when using SnapsToDevicePixels=True. So simply use "2" as StrokeThickness.
You can verify this by using a StrokeThickness of 4, the line will have a thickness of 2 then, which is more than an "accidential" single pixel deviation.
Have you tried to change the TextOptions.TextFormattingMode property to Display ? See this post from Lester Lobo for details

Resources