-2

Basically WPF elements are rectangular in shape.
And it is very easy to get their outline through their Width and Height.
But in the general case, the contour of an element can be any line, including consisting of several contours that do not intersect with each other.
I expected that the VisualTreeHelper.GetClip () method would return the geometry of the contour. But in my attempts, it always returns null.
Perhaps I am using it incorrectly, or it is not suitable for this purpose at all.

My attempt at getting the outlines:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace CopyGeometryElements
{
    public partial class CopyGeometryElementsWindow : Window
    {
        public CopyGeometryElementsWindow()
        {
            InitializeComponent();
        }

        private void OnCopy(object sender, RoutedEventArgs e)
        {
            foreach (UIElement uie
                in source.Children)
            {
                // Always returns null
                var geometry = VisualTreeHelper.GetClip(uie);

                var offset = uie.TranslatePoint(new Point(), source);
                var copy = new Path()
                {
                    Data=geometry,
                    Stroke = Brushes.Red,
                    StrokeThickness=2
                };
                Canvas.SetLeft(copy, offset.X);
                Canvas.SetTop(copy, offset.Y);
                target.Children.Add(copy);
            }
        }
    }
}
<Window x:Class="CopyGeometryElements.CopyGeometryElementsWindow"
        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:CopyGeometryElements"
        mc:Ignorable="d"
        Title="CopyGeometryElementsWindow" Height="450" Width="800">
    <Grid Background="AliceBlue">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid x:Name="source"
              Margin="10" Background="White">
            <Border BorderBrush="Green" BorderThickness="2"
                    CornerRadius="15"
                    Width="40" Height="60" Margin="10"
                    HorizontalAlignment="Left" VerticalAlignment="Top"/>
            
            <Ellipse Stroke="Green" StrokeThickness="2"
                     Width="40" Height="60"
                     HorizontalAlignment="Left" VerticalAlignment="Top"
                     Margin="200,100,0,0"/>

            <Polygon Stroke="Green" StrokeThickness="2"
                      HorizontalAlignment="Left" VerticalAlignment="Top"
                      Margin="100,150,0,0" 
                      Points="0,0 100,100 0,200 50,100">
            </Polygon>
        </Grid>
        <Button Grid.Column="1" Padding="15 5"
                HorizontalAlignment="Center" VerticalAlignment="Center"
                Click="OnCopy">
            <TextBlock Text="Copy the geometry of all shapes from the left panel to the right"
                       Width="80"
                       TextWrapping="Wrap"
                       TextAlignment="Center"/>
        </Button>
        <Canvas x:Name="target" Grid.Column="2" Background="White"
                Margin="10"/>
    </Grid>
</Window>
EldHasp
  • 6,079
  • 2
  • 9
  • 24
  • "Basically WPF elements are rectangular in shape." - no, not really. In the majority of cases, yes - but it's not universally true. – Dai Jul 21 '21 at 07:38
  • 1
    `VisualTreeHelper.GetClip()` apparently returns the value of the [`VisualClip`](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.visual.visualclip?view=net-5.0) property, which is certainly only ever set when a derived UIElement's `Clip` property is set. Your expecation seems just wrong. – Clemens Jul 21 '21 at 08:29
  • You're right. But my expectations were different since Clip is a FarmeworkElement property, and GetClip is a method for Visual and this type does not have this property. Well, the main question remains: "How do I get the outline of a UI element?". – EldHasp Jul 21 '21 at 08:36

1 Answers1

1

As im sure this code just getting ur Clip. For Example:

<Button Height="35" Width="75">
    <Button.Clip>
        <GeometryGroup>
            <RectangleGeometry Rect="0, 0, 100, 100"/>
        </GeometryGroup>
    </Button.Clip>
</Button>

In this case you can get this Clip.

    var figure = VisualTreeHelper.GetClip(uie);

But your Clip is Empty, consequently your result will be null

limeniye
  • 31
  • 1
  • 6
  • You're right. But my expectations were different since Clip is a FarmeworkElement property, and GetClip is a method for Visual and this type does not have this property. Well, the main question remains: "How do I get the outline of a UI element?". – EldHasp Jul 21 '21 at 08:35
  • For example, when the MouseEnter and MouseLeave events are raised, this means that the cursor has crossed the border of the element. This means that the WPF infrastructure somehow defines the boundaries of the element and somewhere (most likely) stores this «knowledge». Therefore, presumably, somehow this knowledge can be extracted. Or can get them in a similar way. – EldHasp Jul 21 '21 at 11:20