How can i find the location of the 'SomeRectangle' ?
This Rectangle is the location and the size that i need to crop from the 'somepicture' that is actually the picture that appear in the background of the main grid.
<Rectangle x:Name="SomeRectangle" Height="50" Width="50" Stroke="Red" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="5" MinHeight="5" />
GeneralTransform gt =
SomeRectangle.TransformToVisual(Application.Current.RootVisual as UIElement);
Point offset = gt.Transform(new Point(0, 0));
double controlTop = offset.Y;
double controlLeft = offset.X;
Source: Silverlight Forum
Related
I have a polygon with points. I need to draw a circle in specified point inside a polygon. I tried Clip Property of ellipse but unable to get points of polygon.
XAML
<Border x:Name="boardDiagramBorder" BorderThickness="2.5" Margin="5" Background="Gray" >
<Grid x:Name="boardCanvas">
<Polygon x:Name="polyOutLine" ClipToBounds="True" Fill="Black"
Stroke="White"
StrokeThickness="2">
</Polygon>
</Grid>
</Border>
Code to draw Polygon
polyOutLine.Points.Add(new System.Windows.Point() { X = 0, Y = 0 });
polyOutLine.Points.Add(new System.Windows.Point() { X = 118900, Y = 0 });
polyOutLine.Points.Add(new System.Windows.Point() { X = 118900, Y = 62993 });
polyOutLine.Points.Add(new System.Windows.Point() { X = 0, Y = 62993 });
I need to draw a circle in the point 21004,-57874.
You can't draw with precise coordinates within a Grid. You have to use Canvas to draw shapes, including rectangles, circles, and polygons using coordinates.
UPDATE: I extend my answer based on your question in your comment and I put in here.
Depends on the location of your canvas, because the circle will always have the relative coordinates based on your canvas.
For example, if your canvas is located at coordinate of 0,0 from the top left, then your circle will be located in coordinate relative to your Canvas with no further offset. If the Canvas is not positioned at 0,0 then your drawing will be located with the offset from the location of your Canvas.
You can use Canvas.Top and Canvas.Left properties to set the circle center, Or you can use margin property
<Grid>
<Canvas>
<Ellipse x:Name="innerCircle" Width="100"
Height="100"
Fill="#FFF4F4F5"
Stroke="Black"
Canvas.Left="50"
Canvas.Top="0"
/>
<Polygon x:Name="polyOutLine"
Stroke="Purple"
StrokeThickness="2">
<Polygon.Fill>
<SolidColorBrush Opacity="0.4" Color="Blue" />
</Polygon.Fill>
</Polygon>
</Canvas>
</Grid>
To set circle center from code use follwing function
private void SetCircleCenter(int x,int y)
{
double radius = innerCircle.Width / 2;
innerCircle.Margin = new Thickness(x-radius, y-radius, 0, 0);
}
I'd like to get the on-screen position and visibility of a TextBlock which is embedded in a PivotItem - e.g. the on-screen position and visibility of TB2 in:
<phone:Pivot>
<phone:PivotItem Header="first">
<TextBlock x:Name="TB1" Text="Hello 1"></TextBlock>
</phone:PivotItem>
<phone:PivotItem Header="second" >
<TextBlock x:Name="TB2" Text="Hello 2"></TextBlock>
</phone:PivotItem>
<phone:PivotItem Header="three" >
<TextBlock x:Name="TB3" Text="Hello 3"></TextBlock>
</phone:PivotItem>
</phone:Pivot>
For other Xaml controls I have achieved this using code like:
public static Rect Position(this FrameworkElement element)
{
if (element.Visibility == Visibility.Collapsed)
return Rect.Empty;
if (element.Opacity < 0.01)
return Rect.Empty;
// Obtain transform information based off root element
GeneralTransform gt = element.TransformToVisual(Application.Current.RootVisual);
// Find the four corners of the element
Point topLeft = gt.Transform(new Point(0, 0));
Point topRight = gt.Transform(new Point(element.RenderSize.Width, 0));
Point bottomLeft = gt.Transform(new Point(0, element.RenderSize.Height));
Point bottomRight = gt.Transform(new Point(element.RenderSize.Width, element.RenderSize.Height));
var left = Math.Min(Math.Min(Math.Min(topLeft.X, topRight.X), bottomLeft.X), bottomRight.X);
var top = Math.Min(Math.Min(Math.Min(topLeft.Y, topRight.Y), bottomLeft.Y), bottomRight.Y);
var position = new Rect(left, top, element.ActualWidth, element.ActualHeight);
return position;
}
However, for PivotItem children this calculation doesn't provide the expected answers when the PivotItem is off-screen. Instead it provides the answer of the position the item will take on-screen when the PivotItem is swiped back on-screen. During a transition, I can see that the position is correctly calculated using the above method - e.g. during the transition I will see the position correctly swipe in from the left/right of the screen.
I've looked through other properties like Visible and Opacity to see if there is some other mechanism being used here to hide the off-screen PivotItem or one of its Parent, GrandParent, etc - but all of those seem to yield Visible and Opacity == 1.0 results.
I've also tried iterating the VisualTree to see if any element with a solid background is masking the "off-screen" PivotItems - but I can't see any in the tree.
Is there some other property to consider here? How are the PivotItem contents hidden when they are "off-screen"? If I really have to, I know that I can use the SelectedIndex property of the Pivot to try to help with the PivotItem position calculations, but I'm hoping to avoid SelectedIndex if I can - I'd prefer to get the position using general Xaml and VisualTree methods if at all possible.
I looked into it, but I can't find how they are hiding the PivotItems. I guess the position is correct, but the item is just not drawn for unknown (to me) reasons. I'll look into it again, later, but for now I wanted to mention a few other potential issues I noticed.
Shouldn't you be using Math.Max for the bottom right corner? Reason being - ActualHeight and ActualWidth are not rotation-aware so to speak.
RenderSize.Width/Height and ActualWidth/Height are different. I'm not sure it's a good idea to use both of them for the calculation.
Don't you need to check everything in the visual tree above the element to see if it's actually visible?
Edit: I looked at Microsoft.Phone.dll's decompiled source (that's the dll with the Pivot control), and I couldn't find anything about how the PivotItems are hidden. There are some native method calls though.
I have made some Changes to Your code and its giving UIElement's true position
XAML:
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Pivot Control-->
<phone:Pivot x:Name="MyPivot">
<phone:PivotItem Header="first" x:Name="first">
<TextBlock x:Name="TB1" FontSize="30" Text="Hello 1" Tap="TB1_Tap"></TextBlock>
</phone:PivotItem>
<phone:PivotItem Header="second" x:Name="second">
<TextBlock x:Name="TB2" FontSize="50" Height="66" Width="155" Margin="20" Text="Hello 2" Tap="TB2_Tap"></TextBlock>
</phone:PivotItem>
<phone:PivotItem Header="three" x:Name="three">
<TextBlock x:Name="TB3" Text="Hello 3"></TextBlock>
</phone:PivotItem>
</phone:Pivot>
</Grid>
CS:
public partial class PivotPage1 : PhoneApplicationPage
{
public PivotPage1()
{
InitializeComponent();
}
private void TB1_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
Rect r = Pos.MyPosition(TB1,first);
string str = "Left" + r.Left.ToString() + "\nTop:" + r.Top.ToString() + "\nRight:" + r.Right.ToString() + "\nBottom:" + r.Bottom.ToString() + "\nHeight:" + r.Height.ToString() + "\nWidth" + r.Width.ToString();
MessageBox.Show(str);
}
private void TB2_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
Rect r = Pos.MyPosition(TB2,second);
string str = "Left" + r.Left.ToString() + "\nTop:" + r.Top.ToString() + "\nRight:" + r.Right.ToString() + "\nBottom:" + r.Bottom.ToString() + "\nHeight:" + r.Height.ToString() + "\nWidth" + r.Width.ToString();
MessageBox.Show(str);
}
}
public static class Pos
{
public static Rect MyPosition(FrameworkElement child,FrameworkElement parent)
{
if (child.Visibility == Visibility.Collapsed)
return Rect.Empty;
if (child.Opacity < 0.01)
return Rect.Empty;
// Obtain transform information based off root child
GeneralTransform gt = child.TransformToVisual(parent);
// Find the four corners of the child
Point topLeft = gt.Transform(new Point(0, 0));
Point topRight = gt.Transform(new Point(child.RenderSize.Width, 0));
Point bottomLeft = gt.Transform(new Point(0, child.RenderSize.Height));
Point bottomRight = gt.Transform(new Point(child.RenderSize.Width, child.RenderSize.Height));
var left = Math.Min(Math.Min(Math.Min(topLeft.X, topRight.X), bottomLeft.X), bottomRight.X);
var top = Math.Min(Math.Min(Math.Min(topLeft.Y, topRight.Y), bottomLeft.Y), bottomRight.Y);
var position = new Rect(left, top, child.ActualWidth, child.ActualHeight);
return position;
}
}
I'm using WPF and having trouble dynamically/programatically adding ellipses to my grid.
I'm dynamically allocating and placing ellipses inside myGrid. Trouble is the position on the ellipses don't change. I'm using Canvas.SetLeft and SetTop, but the ellipses still seem stuck.
Here is the code for dynamic allocation :
{
...
Ellipse el = new Ellipse();
RadialGradientBrush b = new RadialGradientBrush();
b.RadiusX = r * 10.0f;
b.RadiusY = r * 10.0f;
b.GradientOrigin = new Point(0.5f, 0.5f);
b.GradientOrigin = new Point(0.5f, 0.5f);
b.GradientStops.Add(new GradientStop(Colors.Green, 0.0));
b.GradientStops.Add(new GradientStop(Colors.Blue, 1.0));
el.Width = 5.0f + r * 20.0f;
el.Height = 5.0f + r * 20.0f;
el.Stroke = b;
SetEllipsePosition(el, p);
this.myGrid.Children.Add(el);
...
}
private void SetEllipsePosition(FrameworkElement ellipse, Point j)
{
Canvas.SetLeft(ellipse, j.X);
Canvas.SetTop(ellipse, j.Y);
}
<Grid Height="480" Name="myGrid" Width="640">
<GroupBox Header="Pattern" Height="117" HorizontalAlignment="Left" Margin="10,564,0,0" Name="groupBox1" VerticalAlignment="Top" Width="238"></GroupBox>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="33,30,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click_1" />
<Grid Margin="6,507,408,-121">
<RadioButton Content="Lines" Height="16" HorizontalAlignment="Left" Margin="15,18,0,0" Name="rbLines" VerticalAlignment="Top" GroupName="RenderStyles" />
<RadioButton Content="Circles" Height="16" HorizontalAlignment="Left" Margin="15,49,0,0" Name="rbCircles" VerticalAlignment="Top" GroupName="RenderStyles" />
</Grid>
</Grid>
The problem is that you are using a Grid but setting Canvas properties, you could add a Canvas into the Grid and draw you ellipses on the Canvas ( add them to the Canvases children), and then it would work.
Or you could use the Margin property of your ellipse to set it's position on the Grid
Canvas.Left and Canvas.Top are attached properties: you set them only if your UI element is going to be contained in a Canvas; and only when it is on a Canvas will those properties be used (by the Canvas layout manager). Same with attached properties from Grid (such as Grid.Column to tell the Grid parent in what column the UI elements "wants" to be), Panel (Panel.ZIndex to tell the Panel parent at what z index the UI element should be put), etc.
I am new to graphics in C#/WPF application.
I am having a WPF application and using Canvas for drawing various object at the runtime with the help of mouse. I am facing problem in drawing a line with arrow (like below):
(A) ------------>---- (B)
In this arrow sign should be at the 3rd part of the line (and should always point towards the moving mouse). For example if I click mouse at point "A" and move towards point "B" then arrow sign should point towards "B" as shown above.
Any help will be highly appreciated.
Best Regards,
Moon
Thanks for all your help and support. I have resolved my problem as below::
private static Shape DrawLinkArrow(Point p1, Point p2)
{
GeometryGroup lineGroup = new GeometryGroup();
double theta = Math.Atan2((p2.Y - p1.Y), (p2.X - p1.X)) * 180 / Math.PI;
PathGeometry pathGeometry = new PathGeometry();
PathFigure pathFigure = new PathFigure();
Point p = new Point(p1.X + ((p2.X - p1.X) / 1.35), p1.Y + ((p2.Y - p1.Y) / 1.35));
pathFigure.StartPoint = p;
Point lpoint = new Point(p.X + 6, p.Y + 15);
Point rpoint = new Point(p.X - 6, p.Y + 15);
LineSegment seg1 = new LineSegment();
seg1.Point = lpoint;
pathFigure.Segments.Add(seg1);
LineSegment seg2 = new LineSegment();
seg2.Point = rpoint;
pathFigure.Segments.Add(seg2);
LineSegment seg3 = new LineSegment();
seg3.Point = p;
pathFigure.Segments.Add(seg3);
pathGeometry.Figures.Add(pathFigure);
RotateTransform transform = new RotateTransform();
transform.Angle = theta + 90;
transform.CenterX = p.X;
transform.CenterY = p.Y;
pathGeometry.Transform = transform;
lineGroup.Children.Add(pathGeometry);
LineGeometry connectorGeometry = new LineGeometry();
connectorGeometry.StartPoint = p1;
connectorGeometry.EndPoint = p2;
lineGroup.Children.Add(connectorGeometry);
System.Windows.Shapes.Path path = new System.Windows.Shapes.Path();
path.Data = lineGroup;
path.StrokeThickness = 2;
path.Stroke = path.Fill = Brushes.Black;
return path;
}
Thanks,
Moon
I just drew two with Expression Blend 4's arrow shapes which created this:
<Window
...
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing" ... />
<ed:BlockArrow Height="8" Margin="119,181,169,0" Orientation="Left" Stroke="Black" VerticalAlignment="Top" />
<ed:LineArrow Fill="#FFF4F4F5" Height="1" Margin="119,117,169,0" Stroke="#FF027602" VerticalAlignment="Top" BendAmount="0" StartCorner="TopRight" StrokeThickness="2"/>
You can use the Canvas control to represent the arrow,
<Canvas Margin="5" Width="60" Height="20">
<Line X1="10" Y1="10" X2="50" Y2="10" Stroke="Black"
StrokeThickness="2" StrokeDashCap="Round" StrokeEndLineCap="Round" StrokeStartLineCap="Round"/>
<Line X1="35" Y1="10" X2="30" Y2="5" Stroke="Black"
StrokeThickness="2" StrokeDashCap="Round" StrokeEndLineCap="Round" StrokeStartLineCap="Round"/>
<Line X1="35" Y1="10" X2="30" Y2="15" Stroke="Black"
StrokeThickness="2" StrokeDashCap="Round" StrokeEndLineCap="Round" StrokeStartLineCap="Round"/>
</Canvas>
If you want to create this at runtime, you can create the Canvas in the code behind class.
Note that the above sample, does not actually follow arrow sign should be at the 3rd part of the line rule, you may have to modify the coordinates of the line accordingly.
I would suggest you use Path geometry. Have a look at this sample (maybe you already have) but it has similar requirements as yours, http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part4.aspx
I would do this by using an image of the arrow you want. Make a quick photoshop .jpg or .png to use for the default arrow image and then just scale it based on the distance between points A and B. Rotation is a little more complicated, but if you've taken a basic trig course it should still be pretty easy.
The other way you could go about this is by drawing pixels. This is typically much more difficult, and the code for determining the direction of the arrow in this scenario is even more difficult. Again, I suggest the method above.
You can use the Line class to draw the line segments that compose your arrow. For example, you could draw one long line from A to B and two smaller, angled lines to draw the head pointing towards B.
The maths involved to find the appropriate line positions should not be too difficult. For the head, just settle on a size for the two segments and draw them near B angled by 30 degrees or so. Let me know if you have any issue.
The problem with the image technique is that the head will stretch with the length of the arrow. You would have to divide the bitmap between the head and the rest.
I have just started to play around with Silverlight and I decided to do a small app in Visual Studio 2010. I am trying to find the current position of a usercontrol in a Canvas. Here is the XAML layout:
<Grid x:Name="LayoutRoot" Background="#FF141313">
<Grid.RowDefinitions>
<RowDefinition Height="39"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Opacity="0.5" Background="{x:Null}" BorderThickness="1" FontFamily="Courier New" Content="Align Images" Cursor="Hand" Name="buttonAlignImages" Click="buttonAlignImages_Click" Margin="45,8,0,11" HorizontalAlignment="Left" Width="84" />
<Button HorizontalAlignment="Left" Width="33" Opacity="0.5" Background="{x:Null}" BorderThickness="1" FontFamily="Courier New" Content="Home" Cursor="Hand" Margin="8,8,0,11"/>
<Canvas x:Name="ImageContainer" Margin="8" Grid.Row="1" Background="Black"/>
</Grid>
My usercontrol is added to the "ImageContainer" Canvas. One of the buttons in XAML is called "buttonAlignImages". When the user clicks this I basically want the images to be aligned in a specific manner. Anyways to do this I want to first get the position of the usercontrol embedded in the "ImageContainer". So here is the code when the button is clicked:
private void buttonAlignImages_Click(object sender, RoutedEventArgs e)
{
double margin = 5.0;
Point top_left = new Point(margin, margin);
Point top_right = new Point(ActualWidth - margin, margin);
Point bottom_left = new Point(5.0, ActualHeight - margin);
Point bottom_right = new Point(ActualWidth - margin, ActualHeight - margin);
foreach (UIElement element in ImageContainer.Children)
{
Photo singlePhoto = element as Photo;
if (singlePhoto != null)
{
// get the transform for the current photo as applicable to basically this visual
GeneralTransform gt = singlePhoto.TransformToVisual(ImageContainer);
// get the position on the root visual by applying the transform to the singlePhoto
Point singlePhotoTopLeft = gt.Transform(new Point(0, 0));
// now translate the position of the singlePhoto
singlePhoto.Translate(singlePhotoTopLeft.X - top_left.X, singlePhotoTopLeft.Y - top_left.Y);
}
}
}
public void Translate(double deltaX, double deltaY)
{
translateTransform.X += deltaX;
translateTransform.Y += deltaY;
}
The embedded photo usercontrol does move around but when I call gt.Transform(new Point(0,0)) it always gives me (0,0), so the resulting translation is only by 5 pixels. Why does this happen? Am I not using TransformToVisual() correctly?
It s been a while but if u cannot live on without the answer :) will u try
Point singlePhotoTopLeft = gt.Transform(new Point());
instead ?