I am new at using path in a wpf and I do not know how to convert a segment of xaml code to C# code. Could someone help me with this? I cite following the xaml code and then my attempt to convert it. What the C# code lacks of? One more thing I 'd like to ask is if a grid is enough so as a path to appear in the window.
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="10,100">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="200,200" Point2="300,100" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
My C# code:
Path myPath = new Path();
myPath.Stroke = Brushes.Black;
myPath.StrokeThickness = 1
PathGeometry myPathGeometry = new PathGeometry();
myPathGeometry.Figures = new PathFigureCollection();
PathFigure myPathFigure = new PathFigure();
myPathFigure.StartPoint = new Point(10, 100);
myPathFigure.Segments = new PathSegmentCollection();
QuadraticBezierSegment theSegment = new QuadraticBezierSegment();
theSegment.Point1 = new Point(200, 200);
theSegment.Point2 = new Point(100, 300);
myPathFigure.Segments.Add(theSegment);
myPathGeometry.Figures.Add(myPathFigure);
You have to add following line at the end,
myPath.Data = myPathGeometry;
And you should add x:Name to your <Grid> as <Grid x:Name='myGrid'>
And add one more line,
myGrid.Children.Add(myPath);
Your C# code could look a lot like the WPF markup. Just add the path to the control you wish to display it in.
var myPath = new Path
{
Stroke = Brushes.Black,
StrokeThickness = 1.0,
Data = new PathGeometry
{
Figures = new PathFigureCollection
{
new PathFigure
{
StartPoint = new Point(10, 100),
Segments = new PathSegmentCollection
{
new QuadraticBezierSegment
{
Point1 = new Point(200, 200),
Point2 = new Point(300, 100),
},
},
},
},
},
};
myGrid.Children.Add(myPath);
Related
so i have this Path and i need to place it rotated by its center in a coordinate. so i have this static Path in .xaml
<Path Stroke="Black" RenderTransformOrigin="0.379,0.494" Canvas.Left="30" Canvas.Top="0">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform Angle="-38.28"/>
<TranslateTransform X="-30" Y="-30"/>
</TransformGroup>
</Path.RenderTransform>
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="75,30">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="0,0"/>
<LineSegment Point="12,30"/>
<LineSegment Point="0, 60"/>
<LineSegment Point="75, 30"/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
but then i create it from code the same way and it just doesn't wanna center, it just starts rotating around the point
{
PathGeometry pathGeom = new PathGeometry();
Sprite = new Path
{
Data = pathGeom,
RenderTransformOrigin = new Point(0.379, 0.5),
Stroke = new SolidColorBrush(Color.FromArgb(120, 0, 0, 0)),
Fill = new SolidColorBrush(Color.FromArgb(120, 30, 200, 7))
};
var pf = new PathFigure { StartPoint = new Point(75, 30) };
pf.Segments.Add(new LineSegment { Point = new Point(0, 0) });
pf.Segments.Add(new LineSegment { Point = new Point(12, 30) });
pf.Segments.Add(new LineSegment { Point = new Point(0, 60) });
pf.Segments.Add(new LineSegment { Point = new Point(75, 30) });
pathGeom.Figures.Add(pf);
UpdateRotation();
canvas.Children.Add(Sprite);
}
private void UpdateRotation()
{
Sprite.RenderTransform = new TransformGroup
{
Children = new TransformCollection {
new RotateTransform(Road.Angle + (Direction == -1 ? 90 : 0), -30, -30) , <-- i tried doing this
new TranslateTransform(-30, -30), <-- and this separately, but they both didn't work
}
};
Canvas.SetLeft(Sprite, Loc.X);
Canvas.SetTop(Sprite, Loc.Y);
}
here's what the static path looks like:what it looks like
You may simplify your drawing by defining the pivot point as origin - with coordinates (0,0). There is no need for a TranslateTransform or a centered RotateTransform. You would also not have to create new transforms on each direction update. Just set the Angle property of the existing RotateTransform.
private Path Sprite { get; }
public MainWindow()
{
InitializeComponent();
Sprite = new Path
{
Data = Geometry.Parse("M0,0 L-12,-30 63,0 -12,30Z"),
// or Data = Geometry.Parse("M-13,0 L-25,-30 50,0 -25,30Z"),
// or whatever corresponds to the original RenderTransformOrigin
RenderTransform = new RotateTransform(),
Stroke = new SolidColorBrush(Color.FromArgb(120, 0, 0, 0)),
Fill = new SolidColorBrush(Color.FromArgb(120, 30, 200, 7))
};
canvas.Children.Add(Sprite);
UpdatePosition(100, 100, 45); // for example
}
private void UpdatePosition(double x, double y, double direction)
{
((RotateTransform)Sprite.RenderTransform).Angle = direction;
Canvas.SetLeft(Sprite, x);
Canvas.SetTop(Sprite, y);
}
I have arc in a canvas drawn from Path with the following details. I want to get Point(115,225). Please see screenshot to get more details. Please help me getting the formula to get to point (115,225).
startX=250
startY=250
ArcSegment Size (70,70)
ArcSegment Point (250,200)
Computation
var meanX=(startX+startX)/2-rX;//(250+250)/2-70=180
var meanY=(startY+ArcSegment.Point.Y)/2-rY;//(250+200)/2-70=225
//center Point (180,225)
//What is the formula if I want to get Point(115,225)
XAML
<Canvas Name="canvas" Background="White" Opacity="99">
<Path Stroke="Blue" MouseLeftButtonDown="Path_MouseLeftButtonDown" >
<Path.Data>
<PathGeometry>
<PathFigureCollection>
<PathFigure StartPoint="250,250" IsClosed="True">
<ArcSegment Size="70,70" IsLargeArc="True" SweepDirection="Clockwise" Point="250,200"/>
</PathFigure>
</PathFigureCollection>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
C#
private void Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var curve = sender as Path;
var geometry = curve.Data as PathGeometry;
var figure = geometry.Figures.FirstOrDefault();
var arcSegment = figure.Segments.FirstOrDefault() as ArcSegment;
var startX = figure.StartPoint.X;
var yStart = figure.StartPoint.Y;
var startAngle = arcSegment.Point.X;
var sweepAngle = arcSegment.Point.Y;
var rX = arcSegment.Size.Width;
var rY = arcSegment.Size.Height;
var endAngle = startAngle + sweepAngle;
var meanX = (startX + startAngle) / 2 - rX;
var meanY = (yStart + sweepAngle) / 2 - rY;
}
Screenshot
After hours of research, I found out everything is here.
var geometry = path.Data as PathGeometry;
var leftX=geometry.Bounds.Location.X;
var topY=geometry.Bounds.Location.Y;
I am practicing C# basic WPF/XAML drawing for an assignment and right off the bat I cannot figure out why my polygons are being drawn in the wrong place.
My window is of 1280x720 fixed, non-resizeable. I am trying to programmatically create my polygons by:
Creating points in the coordinates I want them to be:
`
[0,0]
[max height, 0],
[max height, max width],
[0, max width],
[max height/2, max width/2]
`
Creating polygons that consists of three points each, [0,0] and two edges. My screen is supposed to be split into four triangles.
I tried breaking down the code to something really explicit to see if I could figure out where the issue is, so this is what I have:
private void CreatePolygons()
{
List<Point> PointList = new List<Point>
{
new Point(MainUI.Height / 2, MainUI.Width / 2),
new Point(0, 0),
new Point(0, MainUI.Height),
new Point(MainUI.Width, MainUI.Height),
new Point(MainUI.Width, 0)
};
Polygon p1 = new Polygon();
Polygon p2 = new Polygon();
Polygon p3 = new Polygon();
Polygon p4 = new Polygon();
p1.Points.Add(PointList[0]);
p1.Points.Add(PointList[1]);
p1.Points.Add(PointList[2]);
p2.Points.Add(PointList[0]);
p2.Points.Add(PointList[2]);
p2.Points.Add(PointList[3]);
p3.Points.Add(PointList[0]);
p3.Points.Add(PointList[3]);
p3.Points.Add(PointList[4]);
p4.Points.Add(PointList[0]);
p4.Points.Add(PointList[4]);
p4.Points.Add(PointList[1]);
p1.Stroke = System.Windows.Media.Brushes.LightSkyBlue;
p2.Stroke = System.Windows.Media.Brushes.LightSkyBlue;
p3.Stroke = System.Windows.Media.Brushes.LightSkyBlue;
p4.Stroke = System.Windows.Media.Brushes.LightSkyBlue;
p1.StrokeThickness = 1;
p2.StrokeThickness = 1;
p3.StrokeThickness = 1;
p4.StrokeThickness = 1;
MainGrid.Children.Add(p1);
MainGrid.Children.Add(p2);
MainGrid.Children.Add(p3);
MainGrid.Children.Add(p4);
}
The end result is a completely misplaced grid and I can't understand what the coordinates it ended up creating refer to:
What am I missing?
You have accidentally swapped the Width and Height in the first point:
new Point(MainUI.Height / 2, MainUI.Width / 2),
Should be:
new Point(MainUI.Width / 2, MainUI.Height / 2),
Further, assuming MainUI is the app window itself, the points will still be a bit off, because the Height of the window includes its title bar height. You should better use MainGrid.ActualWidth and MainGrid.ActualHeight:
List<Point> PointList = new List<Point>
{
new Point(MainGrid.ActualWidth / 2, MainGrid.ActualHeight / 2),
new Point(0, 0),
new Point(0, MainGrid.ActualHeight),
new Point(MainGrid.ActualWidth, MainGrid.ActualHeight),
new Point(MainGrid.ActualWidth, 0)
};
As an alternative to all the Polygon point calcuations, you may use this simple Path element, which produces the same output and stretches automatically:
<Grid>
<Path Stretch="Fill" Stroke="LightSkyBlue" StrokeThickness="1"
Data="M0,0 L1,0 1,1 0,1Z M0,0 L1,1 M0,1 L1,0"/>
</Grid>
Besides that you have confused Width and Height of the first point, I'd suggest not to create UI elements like Polygons in code behind. Better use an ItemsControl like this:
<Grid SizeChanged="MainUISizeChanged">
<ItemsControl x:Name="polygons">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Polygon Stroke="LightSkyBlue" StrokeThickness="1"
Points="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
and assign its ItemsSource property to a collection of PointCollections, e.g. whenever the size of your MainUI element changes:
private void MainUISizeChanged(object sender, SizeChangedEventArgs e)
{
var points = new List<Point>
{
new Point(e.NewSize.Width / 2, e.NewSize.Height / 2),
new Point(0, 0),
new Point(0, e.NewSize.Height),
new Point(e.NewSize.Width, e.NewSize.Height),
new Point(e.NewSize.Width, 0)
};
polygons.ItemsSource = new List<PointCollection>
{
new PointCollection(new Point[] { points[0], points[1], points[2] }),
new PointCollection(new Point[] { points[0], points[2], points[3] }),
new PointCollection(new Point[] { points[0], points[3], points[4] }),
new PointCollection(new Point[] { points[0], points[4], points[1] }),
};
}
I am trying like this but I am not getting the rotation. I am getting following error:
Unable to cast object of type 'System.Windows.Media.TransformGroup' to
type 'System.Windows.Media.RotateTransform'.
TextBlock txt = new TextBlock();
txtb.Text="Sample";
var rotateAnimation = new DoubleAnimation(0, 270, TimeSpan.FromSeconds(5));
var rt = (RotateTransform)txt.RenderTransform;
rt.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation);
Try this one. You can use an animation on the RenderTransform:
var rotateAnimation = new DoubleAnimation(0, 270, TimeSpan.FromSeconds(5));
var rt = (RotateTransform) textblock2.RenderTransform;
rt.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation);
In your Xaml, you can add the RotateTransform:
<TextBlock>
<TextBlock.RenderTransform>
<RotateTransform Angle="0"/>
</TextBlock.RenderTransform>
</TextBlock>
if i understood you clearly what you want is to animate Textblock!
TextBlock txt = new TextBlock();
txt.Text = "Sample";
txt.HorizontalAlignment = HorizontalAlignment.Center;
txt.VerticalAlignment = VerticalAlignment.Center;
RotateTransform r1 = new RotateTransform();
txt.RenderTransform = r1;
MainGrid.Children.Add(txt); //MainGrid is the name of your main layout
var rotateAnimation = new DoubleAnimation(0, 270, TimeSpan.FromSeconds(5));
rotateAnimation.RepeatBehavior = RepeatBehavior.Forever;
var rt = (RotateTransform)txt.RenderTransform;
rt.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation);
I'm using the MS asp.net charting controls. And I'm using the radar chart to draw some values, but for some reason, the lines of the X-axis doesn't really meet in the middle.
I have set the LineWidth = 1, but the line still takes like 2 pixels and some of the markers are totally off, or maybe it's the line that's totally off.
Maybe my text is a little bit off as well, so please see picture and hopefully you'll understand my problem. =)
Code that generates the chart:
// Populate series data
Chart chart1 = new Chart();
chart1.ChartAreas.Add(new ChartArea("ChartArea1"));
chart1.Height = new Unit(380);
chart1.Width = new Unit(880);
//chart1.AntiAliasing = AntiAliasingStyles.Graphics;
//chart1.BackColor = Color.Transparent;
chart1.Customize += new EventHandler(Chart_Customize);
// Show as 3D
chart1.ChartAreas["ChartArea1"].Area3DStyle.Enable3D = false;
chart1.ChartAreas["ChartArea1"].AxisY.IntervalAutoMode
= IntervalAutoMode.FixedCount;
chart1.ChartAreas["ChartArea1"].AxisY.Interval = 10;
chart1.ChartAreas["ChartArea1"].AxisY.Maximum = 100;
chart1.ChartAreas["ChartArea1"].AxisY.IsReversed = true;
chart1.ChartAreas[0].AxisY.LineWidth = 1;
chart1.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.Gray;
chart1.ChartAreas[0].AxisY.LineColor = Color.Gray;
chart1.ChartAreas[0].AxisY.MajorTickMark.Enabled = false;
List<string> names = new List<string>();
int namecounter = 1;
foreach (var p in Model.Participants)
{
if (SessionHandle.ShowNamesInDiagrams)
names.Add(p.Person.Name);
else
names.Add(namecounter.ToString());
namecounter++;
}
#region firstresult
if (SessionHandle.ShowFirstResult)
{
chart1.Series.Add(new Series("FirstResult"));
List<double> firstresult = new List<double>();
foreach (var p in Model.Participants)
{
var resultSummary = from r in Model.ResultSummary
where r.userID == p.ParentID && Model
.Modules
.Where(x => x.hasResult)
.ToList()
.Exists(x => x.ID == r.moduleID)
select r;
firstresult.Add(resultSummary.Sum(x => x.scorePercent)
/ Model.Modules.Where(x => x.hasResult).Count());
}
chart1.Series["FirstResult"].Points.DataBindXY(names, firstresult);
// Set radar chart type
chart1.Series["FirstResult"].ChartType = SeriesChartType.Radar;
// Set radar chart style (Area, Line or Marker)
chart1.Series["FirstResult"]["RadarDrawingStyle"] = "Marker";
chart1.Series["FirstResult"].Color = Color.DarkBlue;
chart1.Series["FirstResult"].MarkerImage
= Url.Content("~/Content/Images/firstresult.png");
// Set circular area drawing style (Circle or Polygon)
chart1.Series["FirstResult"]["AreaDrawingStyle"] = "Circle";
// Set labels style (Auto, Horizontal, Circular or Radial)
chart1.Series["FirstResult"]["CircularLabelsStyle"] = "Horizontal";
}
#endregion
WPF coordinates refer to the center of the pixel, not the corners, so try adding 0.5 to all your coordinates. To show this is the case consider the following xaml:
<Canvas>
<Line X1="50" Y1="50" X2="100" Y2="50" Stroke="Black" StrokeThickness="1" />
<Line X1="50" Y1="50" X2="50" Y2="100" Stroke="Black" StrokeThickness="1" />
<Line X1="50" Y1="50" X2="100" Y2="100" Stroke="Black" StrokeThickness="1" />
</Canvas>
Here it is rendered normally and then with a 0.5 pixel offset applied to each coordinate: