EllipseGeometry is not rendering in Silverlight - silverlight

I'm trying to draw a circle in WP7 Silverlight using EllipseGeometry instead of Ellipse. The sample XAML in MSDN does not display anything on the canvas in Visual Studio. If I run the app, it does display in the emulator.
<Canvas>
<Path Fill="Gold" Stroke="Black" StrokeThickness="1">
<Path.Data>
<EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50" />
</Path.Data>
</Path>
</Canvas>
Any ideas what is happening?

For some unclear reasons, you should assign Width and Height.
<Canvas>
<Path Width="100" Height="100" Fill="Gold" Stroke="Black" StrokeThickness="1">
<Path.Data>
<EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50" />
</Path.Data>
</Path>
</Canvas>
In blend, you will not have this issue.

Related

Why does this polyline not fit inside the ViewBox in WPF?

What I am trying to achieve is to fit the Polyline inside a Viewbox. I tried the Stretch options, however it does not seem to work with negative values. Can someone guide how to fit the content inside the ViewBox?
Following is my sample code:
<Viewbox Stretch="Uniform">
<Grid>
<Polyline Margin="10" Fill="Tan" HorizontalAlignment="Center"
VerticalAlignment="Center" Points="0,0 14,0 14,-38"
StrokeThickness="1" Stroke="Black"
RenderTransformOrigin="0.5,0.5">
<Polyline.RenderTransform>
<TransformGroup>
<RotateTransform Angle="180"/>
<ScaleTransform>
<ScaleTransform.ScaleX>-1</ScaleTransform.ScaleX>
</ScaleTransform>
</TransformGroup>
</Polyline.RenderTransform>
</Polyline>
</Grid>
</Viewbox>
The bounds go beyond the Viewbox, hence unable to get it to "fit" the view.
You shouldn't set the RenderTransform of an element in a Viewbox.
Instead of a Polyline you may use a Path with a polyline geometry, where you can set the Transform property of the Geometry object in the Path's Data:
<Viewbox Stretch="Uniform">
<Path Margin="10" Fill="Tan" StrokeThickness="1" Stroke="Black"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Path.Data>
<PathGeometry Figures="M0,0 L14,0 14,-38">
<PathGeometry.Transform>
<TransformGroup>
<RotateTransform Angle="180"/>
<ScaleTransform>
<ScaleTransform.ScaleX>-1</ScaleTransform.ScaleX>
</ScaleTransform>
</TransformGroup>
</PathGeometry.Transform>
</PathGeometry>
</Path.Data>
</Path>
</Viewbox>
Edit: An alternative might be to set the LayoutTransform instead of RenderTransform. You would also have to set the Polyline's Stretch property:
<Viewbox>
<Polyline Margin="10" Fill="Tan" StrokeThickness="1" Stroke="Black"
Points="0,0 14,0 14,-38" Stretch="Uniform">
<Polyline.LayoutTransform>
<TransformGroup>
<RotateTransform Angle="180"/>
<ScaleTransform>
<ScaleTransform.ScaleX>-1</ScaleTransform.ScaleX>
</ScaleTransform>
</TransformGroup>
</Polyline.LayoutTransform>
</Polyline>
</Viewbox>

VisualBrush of geometry DrawingImage is blurry and cut off

I would like to draw circular geometry in VisualBrush (in order to create an OpacityMask), the result however are of rather low quality:
This image is 500% zoomed in but the cut off of the circle is apparent (especially on top and bottom) and even at original size the mask is rather blurry. The image was generated with following code:
<Border Background="Blue">
<Border.OpacityMask>
<VisualBrush TileMode="None" Stretch="Uniform" AlignmentX="Center" AlignmentY="Center">
<VisualBrush.Visual>
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Brush="Black">
<GeometryDrawing.Geometry>
<EllipseGeometry Center="0,0" RadiusX="1" RadiusY="1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</VisualBrush.Visual>
</VisualBrush>
</Border.OpacityMask>
</Border>
How can I fix the mask so that is neither blurry nor cut off?
This may be better. At least it is simpler.
<Border Background="Blue">
<Border.OpacityMask>
<DrawingBrush Stretch="Uniform" AlignmentX="Center" AlignmentY="Center">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="Black">
<GeometryDrawing.Geometry>
<EllipseGeometry RadiusX="1" RadiusY="1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Border.OpacityMask>
</Border>

wpf ClipToBounds right and bottom

How to clip path stroke? With ClipToBounds="True" there are unwanted pieces at rigth and bottom side.
<Grid Background="Yellow" ClipToBounds="True">
<Viewbox Stretch="Fill">
<Path Data="M30,0 L0,10 L0,40 L30,50 L30,0" Stroke="Red" StrokeThickness="5" />
</Viewbox>
</Grid>
EDIT
I figured out that I just need not to scale border thickness, so solution will be:
<Grid x:Name="grid" Grid.Row="2" Background="Yellow" >
<Grid.Resources>
<ScaleTransform x:Key="transform"
ScaleX="{Binding ActualWidth, ElementName=grid}"
ScaleY="{Binding ActualHeight, ElementName=grid}" />
</Grid.Resources>
<Path Stroke="Red" StrokeThickness="15" Stretch="Fill">
<Path.Data>
<PathGeometry Transform="{StaticResource transform}">
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure IsClosed="True" StartPoint="0,0.7">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="1,1" />
<LineSegment Point="1,0" />
<LineSegment Point="0,0.3" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
If it's ok not to scale the stroke thickness, you might drop the Viewbox and set Stretch="Fill" directly at the Path:
<Grid Background="Yellow" ClipToBounds="True" Margin="20">
<Path Stretch="Fill" Data="M30,0 L0,10 L0,40 L30,50 L30,0 Z"
Stroke="Red" StrokeThickness="20" />
</Grid>
Otherwise you might use the Path in a VisualBrush in e.g. a Rectangle (which needs to have some size set explicitly):
<Grid Background="Yellow" ClipToBounds="True" Margin="20">
<Viewbox Stretch="Fill">
<Rectangle Width="1" Height="1">
<Rectangle.Fill>
<VisualBrush>
<VisualBrush.Visual>
<Path Data="M30,0 L0,10 L0,40 L30,50 L30,0 Z"
Stroke="R*emphasized text*ed" StrokeThickness="5" />
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
</Grid>
Please also note that the path geometry is closed by a trailing Z.

WPF Multiple CombinedGeometry

I wish to bind a collection of viewmodels with X,Y,Radius properties to a CombinedGeometry of circles using Union. However it seems that CombinedGeometry only supports 2 Geometries.
Is there anyway around this limitation?
Example of what I'm aiming for
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Union" ItemsSource="{Binding Circles}">
<CombinedGeometry.Template>
<EllipseGeometry RadiusX="{Binding Radius}" RadiusY="{Binding Radius}" CenterX="{Binding X}" CenterY="{Binding Y}"/>
</CombinedGeometry.Template>
</CombinedGeometry>
</Path.Data>
</Path>
It is indeed possible to have CombinedGeometries within CombinedGeometry as seen below. However, I don't know how to set it up so that it is easily bindable.
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<!-- Combines two geometries using the union combine mode. -->
<CombinedGeometry GeometryCombineMode="Union">
<CombinedGeometry.Geometry1>
<CombinedGeometry GeometryCombineMode="Union">
<CombinedGeometry.Geometry1>
<EllipseGeometry RadiusX="50" RadiusY="50" Center="200,200" />
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry RadiusX="50" RadiusY="50" Center="125,200" />
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<CombinedGeometry GeometryCombineMode="Union">
<CombinedGeometry.Geometry1>
<EllipseGeometry RadiusX="50" RadiusY="50" Center="100,100" />
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry RadiusX="50" RadiusY="50" Center="150,120" />
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
Are you looking for GeometryGroup ?
MSDN Code Sample :
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<!-- Creates a composite shape from three geometries. -->
<GeometryGroup FillRule="EvenOdd">
<LineGeometry StartPoint="10,10" EndPoint="50,30" />
<EllipseGeometry Center="40,70" RadiusX="30" RadiusY="30" />
<RectangleGeometry Rect="30,55 100 30" />
</GeometryGroup>
</Path.Data>
</Path>
This code produces the same result as the second code by the OP:
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Union">
<CombinedGeometry.Geometry1>
<!-- any geometry here -->
<GeometryGroup/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<GeometryGroup FillRule="Nonzero">
<EllipseGeometry RadiusX="50" RadiusY="50" Center="200,200" />
<EllipseGeometry RadiusX="50" RadiusY="50" Center="125,200" />
<EllipseGeometry RadiusX="50" RadiusY="50" Center="100,100" />
<EllipseGeometry RadiusX="50" RadiusY="50" Center="150,120" />
</GeometryGroup>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
And instead of all the <EllipseGeometry>, you can bind to a collection via Children="{Binding Circles}" in <GeometryGroup>.
I have kind of a similar problem and found a hepfull post here:
How to make the border trim the child elements?
You could also try to create a converter that receives the collection in that binding and builds up the combined geometries as desired.
I'll do exactly that now :)

WPF drawing that stretches without stretching the Pen

I need to draw some simple lines within a Border control (or similar) that always stretch to the bounds of the Border. Is there a way to stretch the lines only but not its pen? Without involving lots of C#?
In this version the lines stretch:
<Border>
<Border.Background>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Red">
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="0,0 100,1000" />
<LineGeometry StartPoint="0,0" EndPoint="100,1000"/>
<LineGeometry StartPoint="100,0" EndPoint="0,1000"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Thickness="20" Brush="Black"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Border.Background>
</Border>
The best solution I have come up with is this:
<Border>
<Grid>
<Path Stretch="Fill" Fill="Red" Stroke="Black" StrokeThickness="4" Data="M0,0 L100,0 100,1000 0,1000 z" />
<Path Stretch="Fill" Stroke="Black" StrokeThickness="4" Data="M 0,0 L0,0 100,1000" />
<Path Stretch="Fill" Stroke="Black" StrokeThickness="4" Data="M 100,0 L100,0 0,1000" />
</Grid>
</Border>
But isn't there a better solution? That doesn't involve extra Grid?
I've done this by scaling a Path's Data, not the visual component.
Place a Path in a Canvas.
Set path.Data to a Geometry representing your data as percentages of the logical range.
Set path.Data.Transform to a ScaleTransform with ScaleX and ScaleY bound to the actual width and height.
Within a line, you can bind the width (or height, depending on which way you are drawing the line) to that of the parent container to achieve what you want.
<Grid x:Name="Grid" Margin="10">
<Border BorderBrush="Black" BorderThickness="1" />
<Line X1="0" X2="{Binding ElementName=Grid, Path=ActualWidth}" Y1="1" Y2="1" Stroke="Red" Margin="0,10,0,0" />
<Line X1="0" X2="{Binding ElementName=Grid, Path=ActualWidth}" Y1="1" Y2="1" Stroke="Green" Margin="0,30,0,0" />
<Line X1="0" X2="{Binding ElementName=Grid, Path=ActualWidth}" Y1="1" Y2="1" Stroke="Blue" Margin="0,50,0,0" />
</Grid>
Edit: Here is another way without using binding
<Border BorderBrush="Black" BorderThickness="1" >
<Path Stroke="Red" StrokeThickness="1" Data="M0,0 1,0Z" Stretch="Fill" />
</Border>
None that I know of. But unless you're doing something really extravagant, it really isn't a lot of effort to override OnRender and draw it yourself:
public class CustomBorder : Border
{
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
dc.DrawLine(new Pen(BorderBrush, BorderThickness.Top), new Point(0, 0), new Point(ActualWidth, ActualHeight));
}
}
Result:

Resources