Place existing XAML vector graphics in canvas - c#

I want to make a product configurator. I want to display the product in the main window with xaml vector graphics and then export a dxf file (as technical drawing.) The dxf export already works.
The main part of the product is drawed with lines, no problem here (drawed as a rectangle). But other installations are more complex, for example a 230V-outlet. The outlet is static, so I don't need to draw it with code. I created a outlet.xaml file with Inkscape. How can I place that xaml-file on a specific place (coordinates) in my canvas?
In dxf it was very easy - I created a block as external dxf file, and i could insert it in the drawing like this:
DxfDocument doc = new DxfDocument();
doc.DrawingVariables.InsUnits = DrawingUnits.Millimeters;
//Insert existing DXF
netDxf.Blocks.Block Steckdose = netDxf.Blocks.Block.Load("Steckdose.dxf");
Insert i = new Insert(Steckdose, new Vector2(200,200));
doc.AddEntity(i);
doc.Save("test.dxf");
Is there any way to do that with xaml? Please notice: the number and position of the outlets should be variable, so I wanted to draw them with c# code.
For testing, I made a window with two textboxes: one for the with of the rectangle, one for the x coordinate of the outlet.
Thats my code so far:
private void button_Click(object sender, RoutedEventArgs e)
{
int value1;
int value2;
if (int.TryParse(txt_laenge.Text, out value1) & int.TryParse(txt_laenge.Text, out value2))
{
Länge = value1;
int SD = value2;
var rechteck = new System.Windows.Shapes.Rectangle();
rechteck.Stroke = new SolidColorBrush(Colors.Black);
rechteck.Height = 136;
rechteck.Width = Länge;
Canvas.SetLeft(rechteck,0);
Canvas.SetTop(rechteck, 0);
IV.Children.Clear();
IV.Children.Add(rechteck);
//Place Steckdose.xaml at coordinates (SD, 68);
}
else
{
MessageBox.Show("Ungültige Eingabe!");
}
}
Edit: The Steckdose(outlet).xaml looks like that:
<?xml version="1.0" encoding="UTF-8"?>
<!--This file is NOT compatible with Silverlight-->
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Stretch="Uniform">
<Canvas Name="svg8" Width="44" Height="44">
<Canvas.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</Canvas.RenderTransform>
<Canvas.Resources/>
<!--Unknown tag: sodipodi:namedview-->
<!--Unknown tag: metadata-->
<Canvas Name="layer1">
<Canvas.RenderTransform>
<TranslateTransform X="0" Y="-253"/>
</Canvas.RenderTransform>
<Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="0.13150091" Canvas.Top="253.1315" Width="43.737" Height="43.737" RadiusX="4.4731021" RadiusY="4.4731021" Name="rect3680" Fill="#FF008000" StrokeThickness="0.26300183" Stroke="#FF000000"/>
<Ellipse xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="2.7" Width="38.6" Canvas.Top="255.7" Height="38.6" Name="path4487" Fill="#FF008000" StrokeThickness="0.35593221" Stroke="#FF000000"/>
<Ellipse xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="9.7" Width="4.6" Canvas.Top="272.7" Height="4.6" Name="path4491" Fill="#FF000000" StrokeThickness="0.36692113" Stroke="#FF000000"/>
<Ellipse xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="29.7" Width="4.6" Canvas.Top="272.7" Height="4.6" Name="path44915" Fill="#FF000000" StrokeThickness="0.36692113" Stroke="#FF000000"/>
</Canvas>
</Canvas>
</Viewbox>

This should work:
UIElement element;
using (var stream = new FileStream("Outlet.xaml", FileMode.Open, FileAccess.Read))
{
element = (UIElement)XamlReader.Load(stream);
}
Canvas.SetLeft(element, 100);
Canvas.SetLeft(element, 50);
canvas.Children.Add(element);

Related

Subclassing Path causes rendering issues

I'm trying to draw Microsoft.UI.Xaml.Shapes.Path objects to a Microsoft.UI.Xaml.Controls.Canvas control. These objects are configured in their own coordinate system, and transformed to the pixel-space coordinate system using the Transform property of the Geometry objects.
However, I'm getting some odd behaviour that I'm struggling to make sense of. Here is code that replicates the issue:
XAML
<Window
x:Class="TransformRenderBug.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TransformRenderBug"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
SizeChanged="Window_SizeChanged">
<TabView >
<TabViewItem Header="Blank tab"/>
<TabViewItem Header="Drawing tab">
<local:NumberSpace x:Name="NumberSpace" >
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<EllipseGeometry RadiusX="1" RadiusY="1" Transform="{x:Bind Transform}"/>
</Path.Data>
</Path>
<Path Stroke="Green" StrokeThickness="1">
<Path.Data>
<EllipseGeometry RadiusX="0.9" RadiusY="0.9" Transform="{x:Bind NumberSpace.Transform}"/>
</Path.Data>
</Path>
<local:NumberSpacePath Stroke="Blue" StrokeThickness="1">
<local:NumberSpacePath.Data>
<EllipseGeometry RadiusX="0.8" RadiusY="0.8" Transform="{x:Bind Transform}"/>
</local:NumberSpacePath.Data>
</local:NumberSpacePath>
<local:NumberSpacePath Stroke="Black" StrokeThickness="1">
<local:NumberSpacePath.Data>
<EllipseGeometry RadiusX="0.7" RadiusY="0.7" Transform="{x:Bind NumberSpace.Transform}"/>
</local:NumberSpacePath.Data>
</local:NumberSpacePath>
</local:NumberSpace>
</TabViewItem>
</TabView>
</Window>
C#
public sealed partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private CompositeTransform Transform { get; } = new();
private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs args)
{
NumberSpace.SetTransform(Transform, args.Size.Width, args.Size.Height - 40);
NumberSpace.Width = args.Size.Width;
NumberSpace.Height = args.Size.Height - 40;
}
}
public class NumberSpace : Canvas
{
public CompositeTransform Transform { get; } = new();
public NumberSpace()
{
SizeChanged += (o, e) => SetTransform(Transform, ActualWidth, ActualHeight);
}
public static void SetTransform(CompositeTransform transform, double width, double height)
{
// Figure out the transform required for the shapes to fill the space
double pixelScaleX = width / 2;
double pixelScaleY = height / 2;
transform.ScaleX = pixelScaleX;
transform.ScaleY = pixelScaleY;
transform.TranslateX = pixelScaleX;
transform.TranslateY = pixelScaleY;
}
}
public class NumberSpacePath : Path
{
}
This code produces a window with two tabs. The first is blank. The second has four concentric ellipses drawn on it which take their transforms from either the Window or the Canvas. The ellipses are drawn as either Path objects or NumberSpacePath objects. NumberSpacePath inherits from Path but adds and changes nothing.
The two outer rings draw and resize without issue. However, when the second tab is first switched to, the innermost black ring is not rendered. Switching back to the first tab and again to the second tab causes it to be rendered. Additionally, enlarging the window causes the innermost two rings to be clipped, like on the image below. Again, switching and returning tabs causes them to be rendered correctly.
What is going on? Why does subclassing Path make a difference?

How do I get a Rectangle drawn on an adorner to scale with the Image element its bound to when the window size is changed?

I'm using a rectangle drawn on an adorner to mark a region of interest on an image. The issue is that if I resize the window, the rectangle doesn't change size.
I'm new to WPF, so I've done a bunch of research, googling what I can with multiple different search terms. I actually just learned adorners that way, and I've gotten this far on that, but I've hit a wall on how to finish this last piece. I know that my problem is based in the size of the rectangle, but I don't know what to capture/look for to adjust it, since wpf resizes the actual image object on window resize, so there's no scale factor to look at.
Here's the XAML for the application I'm testing things in.
<Window x:Class="TestingAdorners.MainWindow"
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"
xmlns:local="clr-namespace:TestingAdorners"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid ClipToBounds="True">
<AdornerDecorator>
<Image Name="Btn" Source="nyan.png" Stretch="Uniform"/>
</AdornerDecorator>
</Grid>
</Window>
The adorner class:
class RoiAdorner : Adorner
{
public Rect rectangle = new Rect();
public RoiAdorner(UIElement adornedElement) : base(adornedElement)
{
rectangle.Height = 30;
rectangle.Width = 100;
IsHitTestVisible = false;
}
protected override void OnRender(DrawingContext drawingContext)
{
Pen pen = new Pen(Brushes.Green, 5);
drawingContext.DrawRectangle(null, pen, rectangle);
}
}
And the Xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
AdornerLayer.GetAdornerLayer(Btn).Add(new RoiAdorner(Btn));
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
}
The desired result is that the rectangle scales with the image object so that it always covers the same region of the image. The problem is I don't know how to capture a scale factor to scale it up and down as the window resizes.
Update: After thinking through Frenchy's suggestion I realized the answer is simply: "Normalize your coordinates"
you just adapt your render method like this:
class RoiAdorner : Adorner
{
public double factorX = 0d;
public double factorY = 0d;
public Rect rectangle = new Rect();
public RoiAdorner(UIElement adornedElement) : base(adornedElement)
{
rectangle.Height = 30;
rectangle.Width = 100;
IsHitTestVisible = false;
}
protected override void OnRender(DrawingContext drawingContext)
{
if (factorY == 0)
factorY = rectangle.Height / AdornedElement.DesiredSize.Height;
if (factorX == 0)
factorX = rectangle.Width / AdornedElement.DesiredSize.Width;
var r = new Rect(new Size(AdornedElement.DesiredSize.Width * factorX, AdornedElement.DesiredSize.Height * factorY));
//Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
drawingContext.DrawRectangle(null, new Pen(Brushes.Red, 5), r);
}
this.AdornedElement.DesiredSize gives you the size of image.
The approach I would use is to render the picture and rectangle to the same thing. Then that one thing is stretched, scaled or whatever.
One way to do this would be to use a DrawingImage. Drawing methods are extremely efficient if rather low level.
<Grid ClipToBounds="True">
<AdornerDecorator>
<Image Name="img" Stretch="Uniform">
<Image.Source>
<DrawingImage PresentationOptions:Freeze="True">
<DrawingImage.Drawing>
<DrawingGroup>
<ImageDrawing Rect="0,0,595,446" ImageSource="DSC00025.jpg"/>
<GeometryDrawing Brush="Green">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,100,30" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</AdornerDecorator>
</Grid>
Another is with a visualbrush. Controls inherit from visual - this is somewhat higher level coding.
<Grid ClipToBounds="True">
<AdornerDecorator>
<Rectangle Name="rec">
<Rectangle.Fill>
<VisualBrush Stretch="Uniform">
<VisualBrush.Visual>
<Grid Height="446" Width="595">
<Image Source="DSC00025.jpg" Stretch="Fill"/>
<Rectangle Height="30" Width="100" Fill="Green"
VerticalAlignment="Top" HorizontalAlignment="Left"/>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
</AdornerDecorator>
</Grid>
Note that both of these are quick and dirty illustrations to give you the idea. The image I picked at random off my hard drive is sized 446 * 595. You could calculate sizes or bind or stretch as suits your requirement best.

how to check if an element is going out of its parent in c# wpf

I am creating shapes at run time on canvas in my app and except all the shapes, ellipse is going out of canvas. How do I restrict it to canvas? All other shapes are contained in canvas because of the control points at their vertices. How do I keep a check as to not let ellipse go out of canvas without clipping. I have used ClipToBounds and it doesn't meet my needs.
Also, an alternate solution is if I can add a controlpoint at the left side of ellipse of radiusX property. I can't add a controlpoint to left side of radiusX on ellipse. If you could help me with either of that?
radiusXcp = new ControlPoint(this, EllipseGeom, EllipseGeometry.RadiusYProperty, 1, true, false);
radiusXcp.RelativeTo = EllipseGeometry.CenterProperty;
shape_ControlPoints.Add(radiusXcp);
radiusXcp = new ControlPoint(this, EllipseGeom, EllipseGeometry.RadiusXProperty, 0, true, false);
radiusXcp.RelativeTo = EllipseGeometry.CenterProperty;
shape_ControlPoints.Add(radiusXcp);
//EllipseGeom.RadiusX = -EllipseGeom.RadiusX;
//radiusXcp = new ControlPoint(this, EllipseGeom, EllipseGeometry.RadiusXProperty, 0, true, false);
//radiusXcp.RelativeTo = EllipseGeometry.CenterProperty;
//shape_ControlPoints.Add(radiusXcp);
//EllipseGeom.RadiusX = -EllipseGeom.RadiusX;
Here is a quick example of what i would do. It could be improved on and the code is mainly written to be easy to read and follow. It also does not handle the possibility to if the shape's size is bigger than the Canvas (not sure if that is a use case in your project).
For the example I used the "Loaded" event on the Canvas, to reset the position before drawing. You would want this check before you draw the Ellipse object.
private void TestCanvas_Loaded(object sender, RoutedEventArgs e)
{
//canvas = 450 x 800
Ellipse test_ellipse = new Ellipse();
test_ellipse.Width = 100;
test_ellipse.Height = 100;
test_ellipse.Fill = Brushes.Red;
Canvas.SetLeft(test_ellipse, 700);
Canvas.SetTop(test_ellipse, -500);
Reset_Ellipse_Bounds(TestCanvas, ref test_ellipse);
TestCanvas.Children.Add(test_ellipse);
}
private void Reset_Ellipse_Bounds(Canvas myCanvas, ref Ellipse myEllipse)
{
var left = Canvas.GetLeft(myEllipse);
var top = Canvas.GetTop(myEllipse);
//handle too far right
if (left + myEllipse.Width > myCanvas.ActualWidth)
Canvas.SetLeft(myEllipse, myCanvas.ActualWidth - myEllipse.Width);
//handle too far left
if(left < 0)
Canvas.SetLeft(myEllipse, 0);
//handle too far up
if (top < 0)
Canvas.SetTop(myEllipse, 0);
//handle too far down
if (top + myEllipse.Height > myCanvas.ActualHeight)
Canvas.SetTop(myEllipse, myCanvas.ActualHeight - myEllipse.Height);
}
For Completeness the XAML:
<Grid>
<Canvas x:Name="TestCanvas" Loaded="TestCanvas_Loaded" />
</Grid>
The idea is to check the bounding box against the Canvas edges. There are ways to improve this, but i figured the simplest solution is easier to follow.
Within each if statement you could add more logic or a method to do further processing, but this should answer the general question of knowing if it is outside the parent.
Just set ClipToBounds="true" to its father control, it avoids the canvas to be drawn outside of it.
In my case I set it to Grid as followed :
<Grid x:Name="MainGrid" Background="WhiteSmoke" ClipToBounds="true">
<Canvas Margin="10" Background="Transparent"
SizeChanged="ViewportSizeChanged"
MouseLeftButtonDown="ViewportMouseLeftButtonDown"
MouseLeftButtonUp="ViewportMouseLeftButtonUp"
MouseMove="ViewportMouseMove"
MouseWheel="ViewportMouseWheel">
<Canvas x:Name="canvas" Width="1000" Height="600"
HorizontalAlignment="Left" VerticalAlignment="Top">
<Canvas.RenderTransform>
<MatrixTransform x:Name="transform"/>
</Canvas.RenderTransform>
</Canvas>
<Canvas x:Name="canvas2" Width="1000" Height="600"
HorizontalAlignment="Left" VerticalAlignment="Top">
<Canvas.RenderTransform>
<MatrixTransform x:Name="transform2"/>
</Canvas.RenderTransform>
</Canvas>
</Canvas>
</Grid>

WPF: how to detect geometry intersection on canvas?

I need to determine the intersection of objects moving on the canvas (not necessarily on the canvas, any other panel).
I'm trying to determine the intersection with FillContainsWithDetail.
It seems that the intersection ignores the relative location of objects.
XAML:
<Window x:Class="WpfCollisionTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCollisionTest"
Title="Collisions" Height="400" Width="500">
<Window.DataContext>
<local:CProvider x:Name="Provider"/>
</Window.DataContext>
<Window.Resources>
<PathGeometry x:Key="geoPoly">
<PathGeometry.Figures>
<PathFigure StartPoint="0,0" IsClosed="True">
<PolyLineSegment Points="0,0 50,0 50,50 0,50"/>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Window.Resources>
<Grid>
<Canvas Background="White" MouseMove="Canvas_OnMouseMove">
<Path Name="rectangle1" Data="{StaticResource geoPoly}" Stroke="Black"
Canvas.Left="175" Canvas.Top="100"/>
<Path Name="rectangle2" Data="{StaticResource geoPoly}" Stroke="Black"
Canvas.Left="{Binding rectLeft}" Canvas.Top="{Binding rectTop}"/>
</Canvas>
<TextBlock Text="{Binding intersectionDetail}" VerticalAlignment="Bottom"/>
</Grid>
CS:
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace WpfCollisionTest
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void Canvas_OnMouseMove(object sender, MouseEventArgs e)
{
var pos = e.GetPosition(sender as FrameworkElement);
Provider.rectLeft = pos.X;
Provider.rectTop = pos.Y;
var g1 = rectangle1.RenderedGeometry.GetFlattenedPathGeometry();
var g2 = rectangle2.RenderedGeometry.GetFlattenedPathGeometry();
var intersect = g1.FillContainsWithDetail(g2);
Provider.intersectionDetail = intersect.ToString();
}
}
}
In this example result is always: Intersects.
What am I missing?
Recently I have had to deal with the same problem. So,
We need a method that extracts all transformations from the source object. In my application, I use only RenderTransform in Canvas. Also, make sure that this transform is applied before TranslateTransform with Canvas.Top and Canvas.Left parameters:
private static Transform GetFullTransform(UIElement e)
{
// The order in which transforms are applied is important!
var transforms = new TransformGroup();
if(e.RenderTransform != null)
transforms.Children.Add(e.RenderTransform);
var xTranslate = (double)e.GetValue(Canvas.LeftProperty);
if (double.IsNaN(xTranslate))
xTranslate = 0D;
var yTranslate = (double)e.GetValue(Canvas.TopProperty);
if (double.IsNaN(yTranslate))
yTranslate = 0D;
var translateTransform = new TranslateTransform(xTranslate, yTranslate);
transforms.Children.Add(translateTransform);
return transforms;
}
Introduce a method that converts a given object to a Geometry. Here for demonstration purpose, I convert a Shape object:
public Geometry GetGeometry(Shape s)
{
var g = s.RenderedGeometry.Clone();
g.Transform = GetFullTransform(s);
return g;
}
And finally, use FillContainsWithDetail method. The condition below returns True in 2 cases: when there is an intersection, or when one of the geometries is completely inside another:
private static bool HasIntersection(Geometry g1, Geometry g2) =>
g1.FillContainsWithDetail(g2) != IntersectionDetail.Empty;

Change the parent of a WPF element after a rotation (setting new coordinates issue)

I need to change the parent of elements. (for group/ungroup shapes)
But I cant set the new position for an element if it has a rotation.
I saw this ,this , this and this pages and many other ways, but none worked correctly.
Please see my sample project and the following image:
The parent of Rect1 is ChildCanvas1 and The parent of Rect2 is ChildCanvas2, I want to move the Rect1 and Rect2 to the MainCanvas. (and remove the ChildCanvas and ChildCanvas2)
I don't have any problem to do that for the Rect1 because it has not any rotation.
But the Rect2 has a rotation (-20 degree) and I cant set the new coordinates for it correctly.
Please see this image:
How to change the parent of an element after a rotation and setting new coordinates correctly?
UPDATE:
Note I need a general way (for the group/ungroup elements in a big app that each element (maybe) has TranslateTransform and SkewTransform and RotateTransform and ScaleTransform)
XAML:
<Canvas x:Name="MainCanvas">
<Canvas x:Name="ChildCanvas1" Width="500" Height="250" Background="Bisque" Canvas.Top="54">
<Rectangle x:Name="Rect1" Width="200" Height="100" Fill="Red" Canvas.Left="150" Canvas.Top="100"/>
</Canvas>
<Canvas Name="ChildCanvas2" Width="500" Height="250" Background="Bisque" Canvas.Left="516" Canvas.Top="54">
<Rectangle Name="Rect2" Width="200" Height="100" Fill="Red" Canvas.Left="150" Canvas.Top="100">
<Rectangle.RenderTransform>
<TransformGroup>
<SkewTransform AngleX="-40"/>
<RotateTransform Angle="-20"/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
<Button Name="btn1" Click="btn1_Click" Content="Move Rect1 to MainCanvas and Remove ChildCanvas1" Width="356" Height="30" Canvas.Left="59" Canvas.Top="310"/>
<Button Name="btn2" Click="btn2_Click" Content="Move Rect2 to MainCanvas and Remove ChildCanvas2" Width="350" Height="30" Canvas.Left="590" Canvas.Top="310"/>
C# code :
GeneralTransform transform = Rect2.TransformToVisual(MainCanvas);
Rect rect = transform.TransformBounds(new Rect(0, 0, Rect2.Width, Rect2.Height));
double ChildCanvas2Left = Canvas.GetLeft(ChildCanvas2);
double ChildCanvas2Top = Canvas.GetLeft(ChildCanvas2);
ChildCanvas2.Children.Remove(Rect2);
MainCanvas.Children.Add(Rect2);
Canvas.SetLeft(Rect2, rect.Left);
Canvas.SetTop(Rect2, rect.Top);
MainCanvas.Children.Remove(ChildCanvas2);
You need to recalculate the Rect2 after moving the Rect2 to the MainCanvas. Like this:
Canvas.SetTop(Rect2, Canvas.GetTop(Rect2) + Canvas.GetTop(ChildCanvas2));
The complete code:
private void btn2_Click(object sender, RoutedEventArgs e)
{
GeneralTransform transform = Rect2.TransformToVisual(MainCanvas);
Rect rect = transform.TransformBounds(new Rect(0, 0, Rect2.Width, Rect2.Height));
ChildCanvas2.Children.Remove(Rect2);
MainCanvas.Children.Remove(ChildCanvas2);
Canvas.SetLeft(Rect2, rect.Left);
Canvas.SetTop(Rect2, Canvas.GetTop(Rect2) + Canvas.GetTop(ChildCanvas2));
MainCanvas.Children.Add(Rect2);
}
However Rect2.TransformToVisual and transform.TransformBounds are not necessary in your case and you can do it more cleaner and easier without them and get same result. Like this:
ChildCanvas2.Children.Remove(Rect2);
MainCanvas.Children.Remove(ChildCanvas2);
Canvas.SetLeft(Rect2, Canvas.GetLeft(Rect2) + Canvas.GetLeft(ChildCanvas2));
Canvas.SetTop(Rect2, Canvas.GetTop(Rect2) + Canvas.GetTop(ChildCanvas2));
MainCanvas.Children.Add(Rect2);
EDIT: A general way:
ChildCanvas2.Children.Remove(Rect2);
MainCanvas.Children.Remove(ChildCanvas2);
Canvas.SetLeft(Rect2, Canvas.GetLeft(Rect2) + Canvas.GetLeft(ChildCanvas2));
Canvas.SetTop(Rect2, Canvas.GetTop(Rect2) + Canvas.GetTop(ChildCanvas2));
Canvas.SetRight(Rect2, Canvas.GetRight(Rect2) + Canvas.GetRight(ChildCanvas2));
Canvas.SetBottom(Rect2, Canvas.GetBottom(Rect2) + Canvas.GetBottom(ChildCanvas2));
MainCanvas.Children.Add(Rect2);
I have changed RenderTransform to LayoutTransform of Rect2:
<Rectangle Name="Rect2" Width="200" Height="100" Fill="Red" Canvas.Left="150" Canvas.Top="100">
<Rectangle.LayoutTransform>
<RotateTransform Angle="-20"/>
</Rectangle.LayoutTransform>
</Rectangle>
Now Rect2 looks like below:
When I press the second button I see this result:
So, Rect2 stays at the original position.

Categories