I try to add a line on top of an image. So far it works when I add a line in a new project where I use only a grid and an image.
On the other hand the added line is not shown when I use the same code in another project where I also use a grid and an image with other elements. I suppose the line is added but hidden from the image itself or behind another control, grid or border. So my question is, how can I put my line as the topmost in front of the image?
grid2.Children.Add(myLine);
The outline looks like this:
Window -> Grid1-> Border-> Grid2-> Image (On this image I want to add a line)
The line element:
// Add a Line Element
static Line myLine = new Line
{
Stroke = Brushes.GreenYellow,
StrokeThickness = 2,
Visibility = Visibility.Visible
};
Here I read both points for the line:
private void image_zoom0_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (_firstPoint)
{
grid2.Children.Remove(myLine); // remove line first
System.Windows.Point position = Mouse.GetPosition(image_zoom0);
myLine.X1 = position.X;
myLine.Y1 = position.Y;
_firstPoint = false;
}
else
{
System.Windows.Point position = Mouse.GetPosition(image_zoom0);
myLine.X2 = position.X;
myLine.Y2 = position.Y;
_firstPoint = true;
grid2.Children.Add(myLine); // draw line
Canvas.SetZIndex(myLine,99);
}
}
}
I am not sure what kind of behavior you are expecting from this code. However, I created a sample wpf app and copied image_zoom0_MouseLeftButtonDown method as is.
Note-
I have added Stretch="UniformToFill" for the Image, so that it
occupy whole screen.
I have initialized _firstPoint to "false".
XAML
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" WindowState="Maximized">
<Grid x:Name="grid1">
<Border>
<Grid x:Name="grid2">
<Image x:Name="image_zoom0" Source="Background3.jpg" MouseLeftButtonDown="image_zoom0_MouseLeftButtonDown" Stretch="UniformToFill"/>
</Grid>
</Border>
</Grid>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
static Line myLine = new Line
{
Stroke = Brushes.GreenYellow,
StrokeThickness = 2,
Visibility = Visibility.Visible
};
bool _firstPoint;
private void image_zoom0_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (_firstPoint)
{
grid2.Children.Remove(myLine); // remove line first
System.Windows.Point position = Mouse.GetPosition(image_zoom0);
myLine.X1 = position.X;
myLine.Y1 = position.Y;
_firstPoint = false;
}
else
{
System.Windows.Point position = Mouse.GetPosition(image_zoom0);
myLine.X2 = position.X;
myLine.Y2 = position.Y;
_firstPoint = true;
grid2.Children.Add(myLine); // draw line
//Canvas.SetZIndex(myLine, 99);
}
}
}
}
Now according to the logic written inside the MouseLeftButtonDown, when you first click on the image a Line is drawn from TopLeft of the Window to the current mouseposition.
Second click will simply remove the line. Third click will again draw the line from your previous mouse position to current mouse position and fourth click will again remove it and so on.
Related
I post this before and it was remove for being a duplicate. It is not. My problem is different then what that other people is doing. He is not doing zoom nor pan, and does not have a boarder.
I am using Stretch="Fill" to place my entire picture in the borders of an Image box. I am using a Border so that I can do Zoom and Pan. I am using the Canvas to draw rectangles around giving click areas. I want to map the left mouse click coordinates of the Canvas with zoom and pan back to the original image. here is my XAML code :
`
<Border x:Name="VideoPlayerBorder" ClipToBounds="True" Background="Gray" >
<Canvas x:Name="CanvasGridScreen" MouseLeftButtonDown="VideoPlayerSource_OnMouseLeftButtonDown" >
<Image x:Name="VideoPlayerSource" Opacity="1" RenderTransformOrigin="0.5,0.5" MouseLeftButtonUp="VideoPlayerSource_OnMouseLeftButtonUp" MouseWheel="VideoPlayerSource_OnMouseWheel" MouseMove="VideoPlayerSource_OnMouseMove" Width="{Binding Path=ActualWidth, ElementName=CanvasGridScreen}" Height="{Binding Path=ActualHeight, ElementName=CanvasGridScreen}" Stretch="Fill" >
</Image>
</Canvas>
`
here is my C# code:
`private void VideoPlayerSource_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
VideoPlayerSource.CaptureMouse();
var tt = (TranslateTransform)((TransformGroup)VideoPlayerSource.RenderTransform).Children.First(tr => tr is TranslateTransform);
start = e.GetPosition(VideoPlayerBorder);
origin = new Point(tt.X, tt.Y);
_stIR = start;
_stIR2 = start;
addRemoveItems(sender, e);
}
private void addRemoveItems(object sender, MouseButtonEventArgs e)
{
// this is the event that will check if we clicked on a rectangle or if we clicked on the canvas
// if we clicked on a rectangle then it will do the following
if (e.OriginalSource is Rectangle)
{
// if the click source is a rectangle then we will create a new rectangle
// and link it to the rectangle that sent the click event
Rectangle activeRec = (Rectangle)e.OriginalSource; // create the link between the sender rectangle
CanvasGridScreen.Children.Remove(activeRec); // find the rectangle and remove it from the canvas
}
// if we clicked on the canvas then we do the following
else
{
// generate a random colour and save it inside the custom brush variable
Custombrush = new SolidColorBrush(Color.FromRgb((byte)r.Next(1, 255),
(byte)r.Next(1, 255), (byte)r.Next(1, 233)));
// create a re rectangle and give it the following properties
// height and width 50 pixels
// border thickness 3 pixels, fill colour set to the custom brush created above
// border colour set to black
Rectangle newRec = new Rectangle
{
Width = 50,
Height = 50,
StrokeThickness = 3,
Fill = Custombrush,
Stroke = Brushes.Black
};
// once the rectangle is set we need to give a X and Y position for the new object
// we will calculate the mouse click location and add it there
Canvas.SetLeft(newRec, Mouse.GetPosition(CanvasGridScreen).X); // set the left position of rectangle to mouse X
Canvas.SetTop(newRec, Mouse.GetPosition(CanvasGridScreen).Y); // set the top position of rectangle to mouse Y
CanvasGridScreen.Children.Add(newRec); // add the new rectangle to the canvas
}
}
private void VideoPlayerSource_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
TransformGroup transformGroup = (TransformGroup)VideoPlayerSource.RenderTransform;
ScaleTransform transform = (ScaleTransform)transformGroup.Children[0];
double zoom = e.Delta > 0 ? .2 : -.2;
double transformScaleX = Math.Round((transform.ScaleX + zoom), 2);
double transformScaleY = Math.Round((transform.ScaleY + zoom), 2);
if (transformScaleX <= 8.2 && transformScaleX >= 1)
{
transform.ScaleX = Math.Round(transform.ScaleX + zoom, 2);
transform.ScaleY = Math.Round(transform.ScaleY + zoom, 2);
zoomFactor2 = zoomFactor2 + zoom;
zoomFactor = zoomFactor2;
}
}
void PanMethod(MouseEventArgs e)
{
var tt = (TranslateTransform)((TransformGroup)VideoPlayerSource.RenderTransform).Children.First(tr => tr is TranslateTransform);
Vector v = start - e.GetPosition(VideoPlayerBorder);
if (zoomFactor > 1.0)
{
tt.X = origin.X - v.X;
tt.Y = origin.Y - v.Y;
}
}
is there a function that would give me this information ? is there a way of using TransformGroup or ScaleTransform to return the actual location in the picture that was clicked? again the Image with possible zoom and/or pan
Check out: https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.visual.transformtovisual
The right way to translate coordinates back to the original pre-transforms control is to use the TransformToVisual helper. It's probably a good idea to do that regardless since transforms could be applied higher up in the stack.
In your case you want to call:
GeneralTransform transform = CanvasGridScreen.TransformToVisual(VideoPlayerSource);
Point normalizedPoint = transform.Transform(new Point(0, 0));
I have a button that opens a New Window.
I want to fit the New Window to the dynamic content inside.
Then position it Center, relative to Main Window. So it follows the Main Window's location.
Not WindowStartupLocation.CenterScreen.
This is what I'm using. It doesn't quite work right.
XAML
The New Window is originally set to 900x500, but is overridden by SizeToContent.
<Window x:Class="MyProgram.NewWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="New Window"
Width="900"
Height="500">
C#
This Button is on Main Window.
I use SizeToContent.Width.
newWindow.Width does not use the SizeToContent's width, but instead detects the XAML width 900.
This causes the New Window to always be off center.
I tried setting the XAML width to Auto or 1, it still goes off center a different direction.
I tried using double width = Convert.ToInt32(SizeToContent.Width); but it says the width is 1.
I ran newWindow.UpdateLayout() but it didn't work. https://stackoverflow.com/a/2149676/6806643
public static NewWindow newWindow;
private Boolean IsNewWindowOpened = false;
private void btnNeWindow_Click(object sender, RoutedEventArgs e)
{
// Check if Window is already open
if (IsNewWindowOpened) return;
newWindow = new NewWindow(this);
// Only allow 1 Window instance
newWindow.ContentRendered += delegate { IsNewWindowOpened = true; };
newWindow.Closed += delegate { IsNewWindowOpened = false; };
// Keep Window on Top
newWindow.Owner = Window.GetWindow(this);
// Fit Window to Content
newWindow.SizeToContent = SizeToContent.Width;
// Update Layout
newWindow.UpdateLayout()
// Detect which screen we're on
var allScreens = System.Windows.Forms.Screen.AllScreens.ToList();
var thisScreen = allScreens.SingleOrDefault(s => this.Left >= s.WorkingArea.Left && this.Left < s.WorkingArea.Right);
if (thisScreen == null) thisScreen = allScreens.First();
// Position Relative to MainWindow
newWindow.Left = Math.Max((this.Left + (this.Width - newWindow.Width) / 2), thisScreen.WorkingArea.Left);
newWindow.Top = Math.Max((this.Top + (this.Height - newWindow.Height) / 2), thisScreen.WorkingArea.Top);
// Open Window
newWindow.Show();
}
Examples
Off Center
Correctly Centered
Here is what I've done. Let me know if you have any improvements.
Main Window
Open New Window Button
public static NewWindow newWindow;
private Boolean IsNewWindowOpened = false;
private void btnNeWindow_Click(object sender, RoutedEventArgs e)
{
if (IsPreviewWindowOpened) return;
// Open Preview Window
previewWindow = new Preview(this);
// Only allow 1 Window instance
previewWindow.ContentRendered += delegate { IsPreviewWindowOpened = true; };
previewWindow.Closed += delegate { IsPreviewWindowOpened = false; };
// Keep Window on Top
previewWindow.Owner = Window.GetWindow(this);
// Size to Content
previewWindow.SizeToContent = SizeToContent.Width;
// Open Window
previewWindow.Show();
}
New Window
XAML
Window_Loaded
<Window x:Class="MyProgram.NewWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="New Window"
Width="900"
Height="500"
Loaded="Window_Loaded">
C#
Size Window to fit dynamic content.
Position Center, relative to Main Window.
Also nudges window back on screen if going off.
private void Window_Loaded(object sender, EventArgs e)
{
// Detect which screen we're on
var allScreens = System.Windows.Forms.Screen.AllScreens.ToList();
var thisScreen = allScreens.SingleOrDefault(s => this.Left >= s.WorkingArea.Left && this.Left < s.WorkingArea.Right);
if (thisScreen == null) thisScreen = allScreens.First();
// Position Relative to MainWindow
this.Left = Math.Max((mainwindow.Left + (mainwindow.Width - this.Width) / 2), thisScreen.WorkingArea.Left);
this.Top = Math.Max((mainwindow.Top + (mainwindow.Height - this.Height) / 2), thisScreen.WorkingArea.Top);
}
I have to draw a circle in a grid. That grid has to adapt proportionally to height and width defined by the Column/Row definition of its parent grid.
Now if I put stretch it will fill all the space and become an ellipsis while I want it to be a circle.
Ok in short the parent grid adapts proportionally like that
then in a routine I add the following code:
public void RadialPercentage(Grid grd )
{
Ellipse elpExt = new Ellipse();
elpExt.Stroke = Brushes.Green;
elpExt.StrokeThickness = 4;
//elpExt.Margin = new Thickness(0);
//elpExt.HorizontalAlignment = HorizontalAlignment.Center;
elpExt.VerticalAlignment = VerticalAlignment.Stretch;
grd.Children.Add(elpExt);
Ellipse elpInt = new Ellipse();
elpInt.Stroke = Brushes.Blue;
elpInt.StrokeThickness = 4;
elpInt.Margin = new Thickness(20);
//elpInt.Width = elpInt.Height = dim-20;
//elpInt.HorizontalAlignment = HorizontalAlignment.Center;
elpInt.VerticalAlignment = VerticalAlignment.Stretch;
grd.Children.Add(elpInt);
return;
}
but the effect is the following:
so it stretches both vertically and horizontally even if I only put the vertical and not the horizontal constraint. If I set it to center the ellipse collapses.
To solve the problem even I am not sure that this is the right thing to do I tried to take a look of the weight/heigth of the parent grid but obviously both those values and the actual values are set to zero.
thanks for helping
Patrick
What about setting Width's binding to ActualHeight of the ellipse and set HorizontalAlignment to Center? Something like this:
var ellipse = new Ellipse();
var binding = new Binding(Ellipse.ActualHeightProperty.Name)
{
RelativeSource = new RelativeSource(RelativeSourceMode.Self),
Mode = BindingMode.OneWay
};
ellipse.VerticalAlignment = VerticalAlignment.Stretch;
ellipse.HorizontalAlignment = HorizontalAlignment.Center;
BindingOperations.SetBinding(ellipse, Ellipse.WidthProperty, binding);
You can update the size of your Ellipse each time the parent Grid is resized.
You should add to your Grid the SizeChanged Event. XAML example:
<Grid Name = "MyGrid"
SizeChanged = "MyGridSizeChanged">
<!-- rows and columns definitions -->
<Ellipse Name = "MyEllipse"
Grid.Row = "i"
Grid.Column = "j" />
</Grid>
Now, each time the Grid is resized the function MyGridSizeChanged will executed. You should add into it code, which set sizes of your Ellipse equal to smallest side of contained cell. C# example:
void MyGridSizeChanged(object sender, SizeChangedEventArgs e) {
if (sender is Grid myGrid) {
var cellHeight = myGrid.RowDefinitions[Grid.GetRow(MyEllipse)].ActualHeight;
var cellWidth = myGrid.ColumnDefinitions[Grid.GetColumn(MyEllipse)].ActualWidth;
var newSize = Math.Min(cellHeight, cellWidth);
MyEllipse.Height = newSize;
MyEllipse.Width = newSize;
}
}
I can not animate height and width of window together with top and left property.
(If you want to run this, link to download example is at the end of this question.)
Always when I run this animation, my window firstly smooth move to new location (change smoothly top and left) and also smoothly animate width property during window move.. but window height not responds.. then window height jumps from one value (old height) to the new height.
My WPF application is easy - only for testing this (4 properties, 1 button and 1 function):
Firstly I added this properties to my window (file: MainWindow.xaml.cs):
/// <summary>
/// Position to lock for change size in horizontal way (x)
/// </summary>
public static readonly DependencyProperty LocationLockHorizontalProperty = DependencyProperty.Register("LocationLockHorizontal", typeof(AlignmentX), typeof(Window));
/// <summary>
/// Position to lock for change size in vertical way (y)
/// </summary>
public static readonly DependencyProperty LocationLockVerticalProperty = DependencyProperty.Register("LocationLockVertical", typeof(AlignmentY), typeof(Window));
/// <summary>
/// Location to lock for change size.
/// </summary>
public AlignmentX LocationLockHorizontal
{
get { return (AlignmentX)GetValue(LocationLockHorizontalProperty); }
set { SetValue(LocationLockHorizontalProperty, value); }
}
/// <summary>
/// Location to lock for change size.
/// </summary>
public AlignmentY LocationLockVertical
{
get { return (AlignmentY)GetValue(LocationLockVerticalProperty); }
set { SetValue(LocationLockVerticalProperty, value); }
}
Then I added to the same file one new procedure for create and start animation:
public void AnimateResize(double changeWidth = 0d, double changeHeight = 0d, double durationMilisec = 200.0)
{
Storyboard sb = new Storyboard();
DoubleAnimation daw;
DoubleAnimation dah;
// animate window width
if (changeWidth != 0.0)
{
daw = new DoubleAnimation();
daw.From = this.ActualWidth;
daw.To = this.ActualWidth + changeWidth;
daw.Duration = new Duration(TimeSpan.FromMilliseconds(durationMilisec));
daw.AccelerationRatio = 0.4;
daw.DecelerationRatio = 0.6;
// this.BeginAnimation(Window.WidthProperty, daw);
Storyboard.SetTarget(daw, this);
Storyboard.SetTargetProperty(daw, new PropertyPath(Window.WidthProperty));
sb.Children.Add(daw);
}
// animate window height
if (changeHeight != 0.0)
{
dah = new DoubleAnimation();
dah.From = this.ActualHeight;
dah.To = this.ActualHeight + changeHeight;
dah.Duration = new Duration(TimeSpan.FromMilliseconds(durationMilisec));
dah.AccelerationRatio = 0.4;
dah.DecelerationRatio = 0.6;
Storyboard.SetTarget(dah, this);
Storyboard.SetTargetProperty(dah, new PropertyPath(Window.HeightProperty));
sb.Children.Add(dah); // this.BeginAnimation(Window.HeightProperty, dah);
}
DoubleAnimation dax;
DoubleAnimation day;
// animate window move in horizontal way
if (LocationLockHorizontal == AlignmentX.Center || LocationLockHorizontal == AlignmentX.Right)
{
dax = new DoubleAnimation();
dax.From = this.Left;
switch (LocationLockHorizontal)
{
case AlignmentX.Center:
dax.To = this.Left - changeWidth / 2.0;
break;
case AlignmentX.Right:
dax.To = this.Left - changeWidth;
break;
}
dax.Duration = new Duration(TimeSpan.FromMilliseconds(durationMilisec));
dax.AccelerationRatio = 0.4; dax.DecelerationRatio = 0.6;
Storyboard.SetTarget(dax, this);
Storyboard.SetTargetProperty(dax, new PropertyPath(Window.LeftProperty));
sb.Children.Add(dax); // this.BeginAnimation(Window.LeftProperty, dax);
}
// animate window move vertical
if (LocationLockVertical == AlignmentY.Center || LocationLockVertical == AlignmentY.Bottom)
{
day = new DoubleAnimation();
day.From = this.Top;
switch (LocationLockVertical)
{
case AlignmentY.Center:
day.To = this.Top - changeHeight / 2.0;
break;
case AlignmentY.Bottom:
day.To = this.Top - changeHeight;
break;
}
day.Duration = new Duration(TimeSpan.FromMilliseconds(durationMilisec));
day.AccelerationRatio = 0.4; day.DecelerationRatio = 0.6;
Storyboard.SetTarget(day, this);
Storyboard.SetTargetProperty(day, new PropertyPath(Window.TopProperty));
sb.Children.Add(day); // this.BeginAnimation(Window.TopProperty, day);
}
sb.Begin();
}
In MyWindow initialization in the same file MainWindow.xaml.cs, properties are set to this values (to fix animation to bottom point vertically and center horizontally):
public MainWindow()
{
InitializeComponent();
LocationLockHorizontal = AlignmentX.Center; // fix center point when animate resizing
LocationLockVertical = AlignmentY.Bottom; // lock bottom corner of application
}
My application has 1 button and for it I set click event for random call of previous procedure:
private void Button_Click(object sender, RoutedEventArgs e)
{
this.AnimateResize(new Random().NextDouble() * 400.0 - 200.0, new Random().NextDouble() * 500.0 - 250.0, 1000.0);
}
For complete example here is my xaml MainWindow.xaml:
<Window x:Class="Test_HeightAndTopAnimation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="300" WindowStartupLocation="CenterScreen">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
I read several articles (Wpf - Animate height from bottom up - I don`t have a grid, or WPF: Animation is not smooth) but nothing looks related to this problem.
Link to zip file with example: Application code on Google Drive
Only last note: I use Windows7 64bit and .NET 4.5
I am trying to write a WPF application where you can draw circles on a window by double clicking it. So far I have this code:
public class ShapeAdorner : Adorner
{
private readonly Ellipse _circle;
public ShapeAdorner(UIElement adornedElement, Point circleCenter)
: base(adornedElement)
{
_circle = new Ellipse
{
Width = 10,
Height = 10,
Stroke = Brushes.Black,
StrokeThickness = 1.5
};
_circle.Margin =
new Thickness(left: circleCenter.X, top: circleCenter.Y, right: 0, bottom: 0);
base.AddVisualChild(_circle);
}
protected override Size ArrangeOverride(Size finalSize)
{
_circle.Arrange(new Rect(finalSize));
return finalSize;
}
protected override Size MeasureOverride(Size constraint)
{
_circle.Measure(constraint);
return constraint;
}
protected override Visual GetVisualChild(int index)
{
return _circle;
}
protected override int VisualChildrenCount
{
get { return 1; }
}
}
Here's the client code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(myLabel);
adornerLayer.Add(new ShapeAdorner(adornedElement: myLabel, circleCenter: e.GetPosition(myLabel)));
}
}
The circles are supposed to be centered at the point where you double click the window; however, the circles drawn by the code above are centered below and to the right of "the double click point". How can this be fixed?
EDIT: myLabel has Height=350 and Width=525. Let's say that I double click the point (X,Y); then the circle gets plotted at ((350+X)/2,(525+Y)/2).
EDIT 2: Just for completeness, here's the .xaml file:
<Window x:Class="Adorners.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Adorners project" Height="350" Width="525" MouseDoubleClick="Window_MouseDoubleClick">
<Grid>
<Label Name="myLabel" Content="my label" Background="Red"></Label>
</Grid>
</Window>
Where you set the margin you have to subtract the radius from the top and left properties to offset the circle.
You'll need to offset by half the width/height of the circle. Hard-coded here to make it easy to follow:
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(myLabel);
var point = e.GetPosition(myLabel);
point.X -= 5;
point.Y -= 5;
adornerLayer.Add(new ShapeAdorner(myLabel, point));
You need to take the witdth and height into conserderation when you're setting the margin. the top should be the centerposition minus half of the height, and the same for the left:
new Thickness(
left: circleCenter.X + (_circle.Width/2), //farther to the right
top: circleCenter.Y - (_circle.Height/2), //higher up
right: 0, bottom: 0);
The previous answers are correct. However, the main problem was that I had omitted these two lines:
_circle.HorizontalAlignment = HorizontalAlignment.Left;
_circle.VerticalAlignment = VerticalAlignment.Top;
The default value Stretch caused a huge offset error.