I am trying to create a polygon using points in xaml and as per my understanding the output with the given points should be the triangle with black fill, but it return the triangle with pink fill. I am not getting how this is happening. Kindly let me know.
Tha xaml for this is
<Polygon Width="237"
Height="214"
Fill="White"
Stroke="Black"
StrokeThickness="2">
<Polygon.Points>
<Point X="50" Y="50" />
<Point X="150" Y="150" />
<Point X="50" Y="150" />
</Polygon.Points>
</Polygon>
The Point X=0 and Y=0 is in the upper left corner, not in the lower left corner. So the drawing is correct.
To get what you want is to change your xaml as follows:
<Polygon Width="237"
Height="214"
Fill="Black"
Stroke="White"
StrokeThickness="2">
<Polygon.Points>
<Point X="50" Y="150" />
<Point X="150" Y="150" />
<Point X="150" Y="50" />
</Polygon.Points>
<Polygon>
The point system is the same one used in a Canvas, where 0,0 is the top left corner
For example, the point 50,50 is like saying Canvas.Left="50" and Canvas.Top="50"
To get the shape you want, you need to adjust the points so they read from the top-left instead of the bottom-left.
<Polygon Width="237"
Height="214"
Fill="White"
Stroke="Black"
StrokeThickness="2">
<Polygon.Points>
<Point X="50" Y="50" />
<Point X="150" Y="50" />
<Point X="150" Y="150" />
</Polygon.Points>
</Polygon>
<Point X="50" Y="150" /> is wrong location - that's all.
should be: <Point X="150" Y="50" />
Simple X Y interchange mistake, there is nothing wrong with your understanding.
Related
If I had to create a collection of points as XAML resource, I'd do this:
<Window.Resources>
<PointCollection x:Key="points">
<Point>0,30</Point>
<Point>20,50</Point>
<Point>40,10</Point>
</PointCollection>
</Window.Resources>
In my case the points are already resources:
<Window.Resources>
<Point x:Key="a" X="100" Y="100"/>
<Point x:Key="b" X="200" Y="100"/>
<Point x:Key="b1a" X="100" Y="0"/>
<Point x:Key="b1b" X="200" Y="0"/>
</Window.Resources>
and this way (which is probably already over-killing) doesn't work, as X/Y are not dependency properties:
<Window.Resources>
<PointCollection x:Key="b1points">
<Point X="{Binding Source={StaticResource b1a}, Path=X}"
Y="{Binding Source={StaticResource b1a}, Path=Y}"/>
<Point X="{Binding Source={StaticResource b1b}, Path=X}"
Y="{Binding Source={StaticResource b1b}, Path=Y}"/>
<Point X="{Binding Source={StaticResource b}, Path=X}"
Y="{Binding Source={StaticResource b}, Path=Y}"/>
</Window.Resources>
The collection is used in a Bezier segment later:
<PolyBezierSegment Points="{StaticResource b1points}"/>
but the points must be declared individually, so that they can be used like:
<Ellipse Canvas.Left="{Binding Source={StaticResource a}, Path=X}"
Canvas.Top="{Binding Source={StaticResource a}, Path=Y}"
Width="3" Height="3" Fill="Red"/>
Is someone able to suggest a mean in XAML? and even more difficult, without a converter?
This should work:
<Window.Resources>
<Point x:Key="a" X="100" Y="100"/>
<Point x:Key="b" X="200" Y="100"/>
<Point x:Key="b1a" X="100" Y="0"/>
<Point x:Key="b1b" X="200" Y="0"/>
<PointCollection x:Key="b1points">
<StaticResource ResourceKey="b1a"/>
<StaticResource ResourceKey="b1b"/>
<StaticResource ResourceKey="a"/>
<StaticResource ResourceKey="b"/>
</PointCollection>
</Window.Resources>
...
<PolyBezierSegment Points="{StaticResource b1points}"/>
...
<Path Fill="Red">
<Path.Data>
<EllipseGeometry Center="{StaticResource a}" RadiusX="1.5" RadiusY="1.5"/>
</Path.Data>
</Path>
Trying to make exact animation from FloatingMusicActionButton
My code till now:
<Grid Width="128" Height="128" Panel.ZIndex="1">
<Ellipse Fill="Aqua"></Ellipse>
<Polygon Fill="LightBlue" Stroke="Black" Name="TriOne" >
<Polygon.Points>
<Point X="44" Y="32"></Point>
<Point X="44" Y="64"></Point>
<Point X="100" Y="64"></Point>
<Point X="100" Y="64"></Point>
</Polygon.Points>
<Polygon.Triggers>
<EventTrigger RoutedEvent="Polygon.MouseUp">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="{Binding ElementName=TriOne, Path=Points[0]}"
Storyboard.TargetProperty="X"
From="44" To="32"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Polygon.Triggers>
</Polygon>
<Polygon Fill="LightBlue" Stroke="Black" Name="TriTwo" >
<Polygon.Points>
<Point X="44" Y="96"></Point>
<Point X="44" Y="64"></Point>
<Point X="100" Y="64"></Point>
</Polygon.Points>
</Polygon>
</Grid>
Application goes into break mode after clicking the polygon throwing:
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll
'44,32' name cannot be found in the name scope of 'System.Windows.Shapes.Polygon'.
I'm new to WPF, if you know a better method of animating polygons please share a link.
Your animation cannot work because the X property of Point is not a dependency property.
Use a Path instead of a Polygon and animate the PathFigures:
<Grid Width="128" Height="128" Panel.ZIndex="1">
<Ellipse Fill="Aqua"></Ellipse>
<Path Fill="LightBlue" Stroke="Black" Name="TriOne">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="fig" StartPoint="44, 32" IsClosed="True">
<LineSegment Point="44, 64"/>
<LineSegment x:Name="middle" Point="100, 64"/>
<LineSegment Point="100, 64"/>
</PathFigure>
</PathGeometry>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Polygon.MouseUp">
<BeginStoryboard>
<Storyboard>
<PointAnimation
Storyboard.TargetName="fig"
Storyboard.TargetProperty="StartPoint"
From="44,32" To="32,32"
/>
<PointAnimation
Storyboard.TargetName="middle"
Storyboard.TargetProperty="Point"
From="100, 64" To="90, 54"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
<Polygon Fill="LightBlue" Stroke="Black" Name="TriTwo" >
<Polygon.Points>
<Point X="44" Y="96"></Point>
<Point X="44" Y="64"></Point>
<Point X="100" Y="64"></Point>
</Polygon.Points>
</Polygon>
</Grid>
Scratching my head. Why in the world do these controls appear at different locations? Here's my XAML:
First (black) rectangle is the reference rectangle.
Second (red) rectangle appears correctly centered on top of the reference rect.
The image control (gray) while having the same size and transform, appears slightly drifted.
<Canvas Width="800" Height="500">
<Rectangle Width="100" Height="100" Canvas.Left="300" Canvas.Top="200" Stroke="Black" />
<Rectangle Width="100" Height="100" Canvas.Left="300" Canvas.Top="200" Stroke="Red">
<Rectangle.RenderTransform>
<RotateTransform Angle="30" CenterX="50" CenterY="50" />
</Rectangle.RenderTransform>
</Rectangle>
<Image Width="100" Height="100" Canvas.Left="300" Canvas.Top="200">
<Image.RenderTransform>
<RotateTransform Angle="30" CenterX="50" CenterY="50" />
</Image.RenderTransform>
</Image>
</Canvas>
Appears like this in WPF designer:
As far as I'm concerned,the shape classed (like Rectangle) and Image may have diffrent behaviors for renderorigin,if you edit both values of Image rotatetransform centerX/Y to 0,they may behave the same
<Canvas Width="800" Height="500">
<Rectangle Width="100" Height="100" Canvas.Left="300" Canvas.Top="200 Stroke="Black" />
<Rectangle Width="100" Height="100" Canvas.Left="300" Canvas.Top="200" Stroke="Red">
<Rectangle.RenderTransform>
<RotateTransform Angle="30" CenterX="50" CenterY="50" />
</Rectangle.RenderTransform>
<Image Width="100" Height="100" Canvas.Left="300" Canvas.Top="200">
<Image.RenderTransform>
<RotateTransform Angle="30" CenterX="0" CenterY="0" />
</Image.RenderTransform>
</Image>
I have a list of line segments and each line segment contains a list of points. Being contained on the same canvas, I want to display each line segment and simultaneously mark each point location (ie w/ an ellipse). I can use an ItemsControl to display the segments but I'm stuck at how to display the points. I began implementing a custom control derived from Shape, but there must be an easier way. Thanks in advance for the help.
public class VesselAnatomy : IEnumerable, INotifyCollectionChanged
{
...
List<BaseVessel> _Segments;
...
}
public class BaseVessel : INotifyPropertyChanged
{
...
ObservableCollection<Point> _VesselPoints;
public ObservableCollection<Point> VesselPoints
{
get
{
return _VesselPoints;
}
}
...
}
public MainWindow()
{
...
VesselAnatomy Vessels = new VesselAnatomy();
...
MasterContainer.DataContext = Vessels;
...
}
<ItemsControl x:Name="VesselDisplay"
Height="750"
Width="750"
ItemsSource="{Binding}">
<Polyline Points="{Binding VesselPoints, Converter={StaticResource ObsListPointConverter}}"
Stroke="Red"
StrokeThickness="7">
<Polyline.ToolTip>
<ToolTip>
<TextBlock Text="{Binding Name}"/>
</ToolTip>
</Polyline.ToolTip>
</Polyline>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can use an ItemsControl for the points aswell just change the ItemsPanel and bind the elements positions.
<Window ... >
<Window.Resources>
<PointCollection x:Key="points">
<Point X="20" Y="20" />
<Point X="40" Y="35" />
<Point X="60" Y="40" />
<Point X="80" Y="60" />
<Point X="100" Y="40" />
<Point X="120" Y="30" />
<Point X="140" Y="40" />
<Point X="160" Y="20" />
</PointCollection>
<DataTemplate DataType="{x:Type Point}">
<Ellipse Width="9" Height="9" Fill="White" Stroke="DodgerBlue" StrokeThickness="1" x:Name="e">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform X="-4" Y="-4" />
<TranslateTransform X="{Binding X}" Y="{Binding Y}" />
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</DataTemplate>
</Window.Resources>
<Grid>
<Polyline x:Name="line" Stroke="LightBlue" StrokeThickness="2" Points="{StaticResource points}" />
<ItemsControl x:Name="ptsdisplay" ItemsSource="{StaticResource points}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Window>
If you have lots of points and this method is too slow try http://msdn.microsoft.com/en-us/magazine/dd483292.aspx
Take this Window as an example:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" ResizeMode="NoResize" SizeToContent="WidthAndHeight" SnapsToDevicePixels="True">
<Grid Width="17" Margin="1">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<RepeatButton Grid.Row="0" SnapsToDevicePixels="True">
<Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="1" Fill="Red">
<Polyline.Points>
<Point X="0" Y="3" />
<Point X="3" Y="0" />
<Point X="6" Y="3" />
</Polyline.Points>
</Polyline>
</RepeatButton>
<RepeatButton Grid.Row="1" SnapsToDevicePixels="True">
<Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="1" Fill="Red">
<Polyline.Points>
<Point X="0" Y="3" />
<Point X="3" Y="0" />
<Point X="6" Y="3" />
</Polyline.Points>
</Polyline>
</RepeatButton>
</Grid>
</Window>
Once the application has been ran, the topmost RepeatButton is taller than the bottom one (consequently the top triangle is also bigger than the bottom one). Why?
If I create 4 rows of identical RepeatButtons, then the 1-st and 3-rd RepeatButtons are of equal size and are bigger than the 2-nd and 4-th RepeatButton?!?
I'm thinking this must be a bug in the WPF layout system, but how to work around this problem? I can't use fixed heights (which does solve the problem), because I need the RepeatButtons and triangles to strecth as the container gets bigger (the example I provided is simplifed just to show the issue, I know I can't resize the example window...).
Edit:
In reply to Ben's comments:
Yes, with the added style the triangles do come out as 9px and 8px tall (I could just as well through out the RepeatButtons alltogether and leave only the polylines as the grids children, that would give the same result). Because the triangles are equal sided, then giving the grid a width of 17 will indeed cause the height to become 17 as well, which of course is not enough for two equal height triangles..
What I'm actually trying to do is create a NumericUpDown control. I've found that by default a spinner width of 17 and a UserControl MinHeight of 24 looks very good. The only problem is, that if I drop this UserControl into a Grid, then the top triangle always pushes itself 1px to tall, ruining the look. No matter how I've tried to mingle with the internal Margins and Paddings, the top triangle always makes itself 1px taller than necessary. So in essence what I want is to have a NumericUpDown, that when put into a Grid, doesn't distort itself. By default it should look perfect from the get go (no Grid RowHeight="Auto") and scale properly (no fixed heights). It must be possible, because by looking at the pixels physically then everything can fit into the given dimensions nicely.
Here is my NumericUpDown, I've stripped out all the non essential things to make it more compact:
<UserControl x:Class="HRS.NumericUpDown"
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"
MinWidth="40" MinHeight="24" Name="ucNUPD" Background="White" SnapsToDevicePixels="True">
<UserControl.Resources>
<Style TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Name="borderOuter" BorderThickness="1" BorderBrush="Red">
<Border Name="borderInner" BorderThickness="1" BorderBrush="Blue">
<ContentPresenter Margin="2,1" />
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="triangleStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Polyline HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Green" RenderOptions.EdgeMode="Aliased" Stretch="Uniform">
<Polyline.Points>
<Point X="0" Y="3" />
<Point X="3" Y="0" />
<Point X="6" Y="3" />
</Polyline.Points>
</Polyline>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Border BorderThickness="1" BorderBrush="#ABADB3">
<DockPanel>
<UniformGrid Margin="1" DockPanel.Dock="Right" Rows="2" MinWidth="17" Width="17">
<RepeatButton Name="repeatButtonUp" Grid.Row="0">
<ContentControl Style="{StaticResource triangleStyle}" />
</RepeatButton>
<RepeatButton Name="repeatButtonDown" Grid.Row="1">
<ContentControl Style="{StaticResource triangleStyle}" RenderTransformOrigin="0.5, 0.5">
<ContentControl.RenderTransform>
<ScaleTransform ScaleY="-1" />
</ContentControl.RenderTransform>
</ContentControl>
</RepeatButton>
</UniformGrid>
<TextBox BorderThickness="0" VerticalContentAlignment="Center" Text="0" />
</DockPanel>
</Border>
</UserControl>
Here is a picture of what the end result looks like:
(The image doesn't fit a 100%, but you can still see all the relevant details).
On the right side you can see a zoom-in of the NumericUpDowns. The bottom one looks correct, but only because the grid's row Height is set to Auto. The top one is distorted, but by default I want it to look exactly like the bottom one.
Hmmm...
I might just have found a workable solution:
It seems that by setting the Margin of the ContentPresenter in my NumericUpDown to "3,1", everything looks perfect. Preliminary testing is very promising as everything seems to be exactly the way it should be...
I'll test it some more tommorow and if all goes good will mark Ben's answer as correct :)
With SizeToContent="WidthAndHeight" the height will be 17 as you you set the Grid's Width to 17. But with 17/2=8.5 one row will be 9 (rounding occurs becouse of SnapsToDevicePixels="True") but the other will be 8 pixel tall. If you set the Width to 18 they will be equal.
Proof of my theory:
<Grid Width="17" Margin="0">
<Grid.Resources>
<Style TargetType="{x:Type RepeatButton}">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<ContentPresenter Margin="0"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<RepeatButton Grid.Row="0" SnapsToDevicePixels="True">
<Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="0" Fill="Red">
<Polyline.Points>
<Point X="0" Y="3" />
<Point X="3" Y="0" />
<Point X="6" Y="3" />
</Polyline.Points>
</Polyline>
</RepeatButton>
<RepeatButton Grid.Row="1" SnapsToDevicePixels="True">
<Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="0" Fill="Red">
<Polyline.Points>
<Point X="0" Y="3" />
<Point X="3" Y="0" />
<Point X="6" Y="3" />
</Polyline.Points>
</Polyline>
</RepeatButton>
With this snippet you gain a Triangle that has 9 pixel height, and one with 8 pixels.
But if you want for a solution try this:
<RepeatButton Grid.Row="1" SnapsToDevicePixels="True" Height="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth}" >
<Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="0" Fill="Red">
<Polyline.Points>
<Point X="0" Y="3" />
<Point X="3" Y="0" />
<Point X="6" Y="3" />
</Polyline.Points>
</Polyline>
</RepeatButton>
This way the width and the height of the buttons will be equal.
If think you can write a little converter too, that will can do some nasty things:
<RepeatButton Grid.Row="1" SnapsToDevicePixels="True" Height="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource TriangleWidthConverter}}" >
<Polyline RenderOptions.EdgeMode="Aliased" Stretch="Uniform" Margin="0" Fill="Red">
<Polyline.Points>
<Point X="0" Y="3" />
<Point X="3" Y="0" />
<Point X="6" Y="3" />
</Polyline.Points>
</Polyline>
</RepeatButton>
public class TriangleWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int width = 0;
if (int.TryParse(value.ToString(), out width))
return width + 1; // Do some fun here.
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I hope these will help.
No idea why you are seeing this behavior, but this might work to fix it: try setting the height on each of your your rows to .5* if you have 2 rows or .25* if you have 4 rows (or .1* if you have 10 rows, etc.).