Skip to main content

WPF C#/VB
Shapes: Part 2 (Lines, Outlines & Exporting Shapes)



C#

// AZUL CODING ---------------------------------------
// WPF C#/VB - Shapes: Part 2 (Lines, Outlines & Exporting Shapes)
// https://youtu.be/efHcwDmzpjs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Drawing;

namespace Shapes
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private string CurrentShape = "Rectangle";

        public MainWindow()
        {
            InitializeComponent();
        }

        private void ShapeRadios_Click(object sender, RoutedEventArgs e)
        {
            RectangleShape.Visibility = Visibility.Collapsed;
            EllipseShape.Visibility = Visibility.Collapsed;
            TriangleShape.Visibility = Visibility.Collapsed;
            LineShape.Visibility = Visibility.Collapsed;
            HeightLbl.Visibility = Visibility.Visible;
            HeightSlider.Visibility = Visibility.Visible;
            FillColourLbl.Visibility = Visibility.Visible;
            FillColourPicker.Visibility = Visibility.Visible;

            switch (((RadioButton)sender).Name)
            {
                case "RectangleRadio":
                    RectangleShape.Visibility = Visibility.Visible;
                    CurrentShape = "Rectangle";
                    break;
                case "EllipseRadio":
                    EllipseShape.Visibility = Visibility.Visible;
                    CurrentShape = "Ellipse";
                    break;
                case "TriangleRadio":
                    TriangleShape.Visibility = Visibility.Visible;
                    CurrentShape = "Triangle";
                    break;
                case "LineRadio":
                    LineShape.Visibility = Visibility.Visible;
                    HeightLbl.Visibility = Visibility.Collapsed;
                    HeightSlider.Visibility = Visibility.Collapsed;
                    FillColourLbl.Visibility = Visibility.Collapsed;
                    FillColourPicker.Visibility = Visibility.Collapsed;
                    CurrentShape = "Line";
                    break;
                default:
                    break;
            }
        }

        private void WidthSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            RectangleShape.Width = WidthSlider.Value * 25;
            EllipseShape.Width = WidthSlider.Value * 25;

            //        100,0
            //          △
            //   0,200     200,200

            List<double> shapepoints = new List<double>() { };
            PointCollection newpoints = new PointCollection();

            foreach (System.Windows.Point pt in TriangleShape.Points)
            {
                shapepoints.Add(pt.X);
            }
            shapepoints = shapepoints.Distinct().ToList();

            foreach (System.Windows.Point pt in TriangleShape.Points)
            {
                if (pt.X == shapepoints.Max())
                {
                    newpoints.Add(new System.Windows.Point(WidthSlider.Value * 25, pt.Y));
                }
                else if (pt.X != shapepoints.Min())
                {
                    newpoints.Add(new System.Windows.Point(WidthSlider.Value * 25 / 2, pt.Y));
                }
                else
                {
                    newpoints.Add(new System.Windows.Point(pt.X, pt.Y));
                }
            }

            TriangleShape.Points = newpoints;
            LineShape.X2 = WidthSlider.Value * 25;
        }

        private void HeightSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            RectangleShape.Height = HeightSlider.Value * 25;
            EllipseShape.Height = HeightSlider.Value * 25;

            List<double> shapepoints = new List<double>() { };
            PointCollection newpoints = new PointCollection();

            foreach (System.Windows.Point pt in TriangleShape.Points)
            {
                shapepoints.Add(pt.Y);
            }
            shapepoints = shapepoints.Distinct().ToList();

            foreach (System.Windows.Point pt in TriangleShape.Points)
            {
                if (pt.Y == shapepoints.Max())
                {
                    newpoints.Add(new System.Windows.Point(pt.X, HeightSlider.Value * 25));
                }
                else if (pt.Y != shapepoints.Min())
                {
                    newpoints.Add(new System.Windows.Point(pt.X, HeightSlider.Value * 25 / 2));
                }
                else
                {
                    newpoints.Add(new System.Windows.Point(pt.X, pt.Y));
                }
            }

            TriangleShape.Points = newpoints;
        }

        private void FillColourPicker_SelectedColorChanged(object sender, RoutedPropertyChangedEventArgs<System.Windows.Media.Color?> e)
        {
            SolidColorBrush clr = new SolidColorBrush((System.Windows.Media.Color)FillColourPicker.SelectedColor);
            RectangleShape.Fill = clr;
            EllipseShape.Fill = clr;
            TriangleShape.Fill = clr;
        }

        private void LineColourPicker_SelectedColorChanged(object sender, RoutedPropertyChangedEventArgs<System.Windows.Media.Color?> e)
        {
            SolidColorBrush clr = new SolidColorBrush((System.Windows.Media.Color)LineColourPicker.SelectedColor);
            RectangleShape.Stroke = clr;
            EllipseShape.Stroke = clr;
            TriangleShape.Stroke = clr;
            LineShape.Stroke = clr;
        }

        private void ThicknessSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            RectangleShape.StrokeThickness = ThicknessSlider.Value;
            EllipseShape.StrokeThickness = ThicknessSlider.Value;
            TriangleShape.StrokeThickness = ThicknessSlider.Value;
            LineShape.StrokeThickness = ThicknessSlider.Value;
        }

        private void LineEffectRadios_Click(object sender, RoutedEventArgs e)
        {
            DoubleCollection arr = new DoubleCollection() { 1, 0 };

            if (DashedRadio.IsChecked == true)
            {
                arr = new DoubleCollection() { 4, 4 };
            }
            else if (DottedRadio.IsChecked == true)
            {
                arr = new DoubleCollection() { 2, 2 };
            }

            RectangleShape.StrokeDashArray = arr;
            EllipseShape.StrokeDashArray = arr;
            TriangleShape.StrokeDashArray = arr;
            LineShape.StrokeDashArray = arr;
        }

        private void ExportBtn_Click(object sender, RoutedEventArgs e)
        {
            int bmpheight, bmpwidth, r, g, b, thickness;
            Bitmap bmp = new Bitmap(1, 1);
            SolidBrush fill, outline;
            System.Drawing.Pen pen;
            System.Drawing.Rectangle rect;

            r = FillColourPicker.SelectedColor.Value.R;
            g = FillColourPicker.SelectedColor.Value.G;
            b = FillColourPicker.SelectedColor.Value.B;
            fill = new SolidBrush(System.Drawing.Color.FromArgb(r, g, b));

            r = LineColourPicker.SelectedColor.Value.R;
            g = LineColourPicker.SelectedColor.Value.G;
            b = LineColourPicker.SelectedColor.Value.B;
            outline = new SolidBrush(System.Drawing.Color.FromArgb(r, g, b));

            thickness = (int)ThicknessSlider.Value * 2;
            pen = new System.Drawing.Pen(outline)
            {
                Width = thickness
            };

            if (DashedRadio.IsChecked == true)
            {
                pen.DashPattern = new float[] { 2f, 2f };
            }
            else if (DottedRadio.IsChecked == true)
            {
                pen.DashPattern = new float[] { 1f, 1f };
            }

            switch (CurrentShape)
            {
                case "Rectangle":
                    bmpheight = (int)RectangleShape.ActualHeight;
                    bmpwidth = (int)RectangleShape.ActualWidth;
                    rect = new System.Drawing.Rectangle(thickness / 2, thickness / 2, bmpwidth - thickness, bmpheight - thickness);
                    bmp = new Bitmap(bmpwidth, bmpheight);

                    using (Graphics gr = Graphics.FromImage(bmp))
                    {
                        gr.DrawRectangle(pen, rect);
                        gr.FillRectangle(fill, rect);
                    }
                    break;

                case "Ellipse":
                    bmpheight = (int)EllipseShape.ActualHeight;
                    bmpwidth = (int)EllipseShape.ActualWidth;
                    rect = new System.Drawing.Rectangle(thickness / 2, thickness / 2, bmpwidth - thickness, bmpheight - thickness);
                    bmp = new Bitmap(bmpwidth, bmpheight);

                    using (Graphics gr = Graphics.FromImage(bmp))
                    {
                        gr.DrawEllipse(pen, rect);
                        gr.FillEllipse(fill, rect);
                    }
                    break;

                case "Triangle":
                    bmpheight = (int)TriangleShape.ActualHeight;
                    bmpwidth = (int)TriangleShape.ActualWidth;
                    bmp = new Bitmap(bmpwidth, bmpheight);

                    List<double> xpoints = new List<double>() { };
                    List<double> ypoints = new List<double>() { };
                    List<System.Drawing.Point> newpoints = new List<System.Drawing.Point>();

                    foreach (System.Windows.Point pt in TriangleShape.Points)
                    {
                        xpoints.Add(pt.X);
                        ypoints.Add(pt.Y);
                    }
                    xpoints = xpoints.Distinct().ToList();
                    ypoints = ypoints.Distinct().ToList();

                    int counter = 0;
                    foreach (System.Windows.Point pt in TriangleShape.Points)
                    {
                        if (pt.X == xpoints.Max())
                        {
                            newpoints.Add(new System.Drawing.Point((int)pt.X - thickness, (int)pt.Y));
                        }
                        else if (pt.X == xpoints.Min())
                        {
                            newpoints.Add(new System.Drawing.Point((int)pt.X + thickness, (int)pt.Y));
                        }
                        else
                        {
                            newpoints.Add(new System.Drawing.Point((int)pt.X, (int)pt.Y));
                        }

                        if (pt.Y == ypoints.Max())
                        {
                            newpoints[counter] = new System.Drawing.Point(newpoints[counter].X, (int)pt.Y - (thickness / 2));
                        }
                        else if (pt.Y == ypoints.Min())
                        {
                            newpoints[counter] = new System.Drawing.Point(newpoints[counter].X, (int)pt.Y + thickness);
                        }
                        counter++;
                    }

                    using (Graphics gr = Graphics.FromImage(bmp))
                    {
                        gr.DrawPolygon(pen, newpoints.ToArray());
                        gr.FillPolygon(fill, newpoints.ToArray());
                    }
                    break;

                case "Line":
                    bmpwidth = (int)LineShape.ActualWidth;
                    bmpheight = (int)LineShape.StrokeThickness;
                    bmp = new Bitmap(bmpwidth, bmpheight);

                    using (Graphics gr = Graphics.FromImage(bmp))
                    {
                        gr.DrawLine(pen, (int)LineShape.X1, (int)LineShape.Y1, (int)LineShape.X2, (int)LineShape.Y2);
                    }
                    break;

                default:
                    break;
            }

            pen.Dispose();
            fill.Dispose();
            outline.Dispose();

            bmp.Save(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) + "\\shape.png");
            MessageBox.Show("Shape exported as image.");
        }
    }
}

Enjoying this tutorial?


VB.NET

' AZUL CODING ---------------------------------------
' WPF C#/VB - Shapes: Part 2 (Lines, Outlines & Exporting Shapes)
' https://youtu.be/efHcwDmzpjs


Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Drawing

Class MainWindow
    Private CurrentShape As String = "Rectangle"

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub ShapeRadios_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        RectangleShape.Visibility = Visibility.Collapsed
        EllipseShape.Visibility = Visibility.Collapsed
        TriangleShape.Visibility = Visibility.Collapsed
        LineShape.Visibility = Visibility.Collapsed
        HeightLbl.Visibility = Visibility.Visible
        HeightSlider.Visibility = Visibility.Visible
        FillColourLbl.Visibility = Visibility.Visible
        FillColourPicker.Visibility = Visibility.Visible

        Select Case (CType(sender, RadioButton)).Name
            Case "RectangleRadio"
                RectangleShape.Visibility = Visibility.Visible
                CurrentShape = "Rectangle"
            Case "EllipseRadio"
                EllipseShape.Visibility = Visibility.Visible
                CurrentShape = "Ellipse"
            Case "TriangleRadio"
                TriangleShape.Visibility = Visibility.Visible
                CurrentShape = "Triangle"
            Case "LineRadio"
                LineShape.Visibility = Visibility.Visible
                HeightLbl.Visibility = Visibility.Collapsed
                HeightSlider.Visibility = Visibility.Collapsed
                FillColourLbl.Visibility = Visibility.Collapsed
                FillColourPicker.Visibility = Visibility.Collapsed
                CurrentShape = "Line"
            Case Else
        End Select
    End Sub

    Private Sub WidthSlider_ValueChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of Double))
        RectangleShape.Width = WidthSlider.Value * 25
        EllipseShape.Width = WidthSlider.Value * 25

        '        100,0
        '          △
        '   0,200     200,200

        Dim shapepoints As List(Of Double) = New List(Of Double) From {}
        Dim newpoints As PointCollection = New PointCollection()

        For Each pt As System.Windows.Point In TriangleShape.Points
            shapepoints.Add(pt.X)
        Next

        shapepoints = shapepoints.Distinct().ToList()

        For Each pt As System.Windows.Point In TriangleShape.Points

            If pt.X = shapepoints.Max() Then
                newpoints.Add(New System.Windows.Point(WidthSlider.Value * 25, pt.Y))
            ElseIf pt.X <> shapepoints.Min() Then
                newpoints.Add(New System.Windows.Point(WidthSlider.Value * 25 / 2, pt.Y))
            Else
                newpoints.Add(New System.Windows.Point(pt.X, pt.Y))
            End If
        Next

        TriangleShape.Points = newpoints
        LineShape.X2 = WidthSlider.Value * 25
    End Sub

    Private Sub HeightSlider_ValueChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of Double))
        RectangleShape.Height = HeightSlider.Value * 25
        EllipseShape.Height = HeightSlider.Value * 25

        Dim shapepoints As List(Of Double) = New List(Of Double) From {}
        Dim newpoints As PointCollection = New PointCollection()

        For Each pt As System.Windows.Point In TriangleShape.Points
            shapepoints.Add(pt.Y)
        Next

        shapepoints = shapepoints.Distinct().ToList()

        For Each pt As System.Windows.Point In TriangleShape.Points

            If pt.Y = shapepoints.Max() Then
                newpoints.Add(New System.Windows.Point(pt.X, HeightSlider.Value * 25))
            ElseIf pt.Y <> shapepoints.Min() Then
                newpoints.Add(New System.Windows.Point(pt.X, HeightSlider.Value * 25 / 2))
            Else
                newpoints.Add(New System.Windows.Point(pt.X, pt.Y))
            End If
        Next

        TriangleShape.Points = newpoints
    End Sub

    Private Sub FillColourPicker_SelectedColorChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of System.Windows.Media.Color))
        Dim clr As SolidColorBrush = New SolidColorBrush(CType(FillColourPicker.SelectedColor, System.Windows.Media.Color))
        RectangleShape.Fill = clr
        EllipseShape.Fill = clr
        TriangleShape.Fill = clr
    End Sub

    Private Sub LineColourPicker_SelectedColorChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of System.Windows.Media.Color))
        Dim clr As SolidColorBrush = New SolidColorBrush(CType(LineColourPicker.SelectedColor, System.Windows.Media.Color))
        RectangleShape.Stroke = clr
        EllipseShape.Stroke = clr
        TriangleShape.Stroke = clr
        LineShape.Stroke = clr
    End Sub

    Private Sub ThicknessSlider_ValueChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of Double))
        RectangleShape.StrokeThickness = ThicknessSlider.Value
        EllipseShape.StrokeThickness = ThicknessSlider.Value
        TriangleShape.StrokeThickness = ThicknessSlider.Value
        LineShape.StrokeThickness = ThicknessSlider.Value
    End Sub

    Private Sub LineEffectRadios_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Dim arr As DoubleCollection = New DoubleCollection() From { 1, 0 }

        If DashedRadio.IsChecked = True Then
            arr = New DoubleCollection() From { 4, 4 }
        ElseIf DottedRadio.IsChecked = True Then
            arr = New DoubleCollection() From { 2, 2 }
        End If

        RectangleShape.StrokeDashArray = arr
        EllipseShape.StrokeDashArray = arr
        TriangleShape.StrokeDashArray = arr
        LineShape.StrokeDashArray = arr
    End Sub

    Private Sub ExportBtn_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Dim bmpheight, bmpwidth, r, g, b, thickness As Integer
        Dim bmp As Bitmap = New Bitmap(1, 1)
        Dim fill, outline As SolidBrush
        Dim pen As System.Drawing.Pen
        Dim rect As System.Drawing.Rectangle

        r = FillColourPicker.SelectedColor.Value.R
        g = FillColourPicker.SelectedColor.Value.G
        b = FillColourPicker.SelectedColor.Value.B
        fill = New SolidBrush(System.Drawing.Color.FromArgb(r, g, b))

        r = LineColourPicker.SelectedColor.Value.R
        g = LineColourPicker.SelectedColor.Value.G
        b = LineColourPicker.SelectedColor.Value.B
        outline = New SolidBrush(System.Drawing.Color.FromArgb(r, g, b))

        thickness = CInt(ThicknessSlider.Value) * 2
        pen = New System.Drawing.Pen(outline) With {
            .Width = thickness
        }

        If DashedRadio.IsChecked = True Then
            pen.DashPattern = New Single() {2F, 2F}
        ElseIf DottedRadio.IsChecked = True Then
            pen.DashPattern = New Single() {1F, 1F}
        End If

        Select Case CurrentShape
            Case "Rectangle"
                bmpheight = CInt(RectangleShape.ActualHeight)
                bmpwidth = CInt(RectangleShape.ActualWidth)
                rect = New System.Drawing.Rectangle(thickness / 2, thickness / 2, bmpwidth - thickness, bmpheight - thickness)
                bmp = New Bitmap(bmpwidth, bmpheight)

                Using gr As Graphics = Graphics.FromImage(bmp)
                    gr.DrawRectangle(pen, rect)
                    gr.FillRectangle(fill, rect)
                End Using

            Case "Ellipse"
                bmpheight = CInt(EllipseShape.ActualHeight)
                bmpwidth = CInt(EllipseShape.ActualWidth)
                rect = New System.Drawing.Rectangle(thickness / 2, thickness / 2, bmpwidth - thickness, bmpheight - thickness)
                bmp = New Bitmap(bmpwidth, bmpheight)

                Using gr As Graphics = Graphics.FromImage(bmp)
                    gr.DrawEllipse(pen, rect)
                    gr.FillEllipse(fill, rect)
                End Using

            Case "Triangle"
                bmpheight = CInt(TriangleShape.ActualHeight)
                bmpwidth = CInt(TriangleShape.ActualWidth)
                bmp = New Bitmap(bmpwidth, bmpheight)

                Dim xpoints As List(Of Double) = New List(Of Double) From {}
                Dim ypoints As List(Of Double) = New List(Of Double) From {}
                Dim newpoints As List(Of System.Drawing.Point) = New List(Of System.Drawing.Point)()

                For Each pt As System.Windows.Point In TriangleShape.Points
                    xpoints.Add(pt.X)
                    ypoints.Add(pt.Y)
                Next

                xpoints = xpoints.Distinct().ToList()
                ypoints = ypoints.Distinct().ToList()

                Dim counter As Integer = 0
                For Each pt As System.Windows.Point In TriangleShape.Points

                    If pt.X = xpoints.Max() Then
                        newpoints.Add(New System.Drawing.Point(CInt(pt.X) - thickness, CInt(pt.Y)))
                    ElseIf pt.X = xpoints.Min() Then
                        newpoints.Add(New System.Drawing.Point(CInt(pt.X) + thickness, CInt(pt.Y)))
                    Else
                        newpoints.Add(New System.Drawing.Point(CInt(pt.X), CInt(pt.Y)))
                    End If

                    If pt.Y = ypoints.Max() Then
                        newpoints(counter) = New System.Drawing.Point(newpoints(counter).X, CInt(pt.Y) - (thickness / 2))
                    ElseIf pt.Y = ypoints.Min() Then
                        newpoints(counter) = New System.Drawing.Point(newpoints(counter).X, CInt(pt.Y) + thickness)
                    End If

                    counter += 1
                Next

                Using gr As Graphics = Graphics.FromImage(bmp)
                    gr.DrawPolygon(pen, newpoints.ToArray())
                    gr.FillPolygon(fill, newpoints.ToArray())
                End Using

            Case "Line"
                bmpwidth = CInt(LineShape.ActualWidth)
                bmpheight = CInt(LineShape.StrokeThickness)
                bmp = New Bitmap(bmpwidth, bmpheight)

                Using gr As Graphics = Graphics.FromImage(bmp)
                    gr.DrawLine(pen, CInt(LineShape.X1), CInt(LineShape.Y1), CInt(LineShape.X2), CInt(LineShape.Y2))
                End Using

            Case Else
        End Select

        pen.Dispose()
        fill.Dispose()
        outline.Dispose()
        
        bmp.Save(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) & "\shape.png")
        MessageBox.Show("Shape exported as image.")
    End Sub
End Class

XAML

<!-- AZUL CODING --------------------------------------- -->
<!-- WPF C#/VB - Shapes: Part 2 (Lines, Outlines & Exporting Shapes) -->
<!-- https://youtu.be/efHcwDmzpjs -->


<Window x:Class="Shapes.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:Shapes" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
        mc:Ignorable="d"
        Title="Shapes - Azul Coding" Width="875" MinHeight="475" ResizeMode="CanMinimize" SizeToContent="Height">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition MinWidth="500"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid Margin="20,20,0,20" Grid.Column="0">
            <Rectangle x:Name="RectangleShape" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Height="200" Fill="#108beb" Stroke="#0c3c62" StrokeThickness="2"/>
            <Ellipse x:Name="EllipseShape" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Height="200" Fill="#108beb" Stroke="#0c3c62" StrokeThickness="2" Visibility="Collapsed"/>
            <Polygon x:Name="TriangleShape" HorizontalAlignment="Center" VerticalAlignment="Center" Points="0,200 100,0 200,200" Fill="#108beb" Stroke="#0c3c62" StrokeThickness="2" Visibility="Collapsed"/>
            <Line x:Name="LineShape" HorizontalAlignment="Center" VerticalAlignment="Center" Stroke="#0c3c62" StrokeThickness="2" X1="0" X2="200" Visibility="Collapsed"/>
        </Grid>
        <StackPanel Grid.Column="1" Margin="20">
            <Label x:Name="ShapeLbl" Content="Choose a shape" FontSize="14"/>
            <StackPanel Orientation="Horizontal">
                <RadioButton Name="RectangleRadio" Content="Rectangle" GroupName="ShapeRadios" Margin="10,5,0,0" IsChecked="True" Click="ShapeRadios_Click"/>
                <RadioButton Name="EllipseRadio" Content="Ellipse" GroupName="ShapeRadios" Margin="20,5,0,0" Click="ShapeRadios_Click"/>
                <RadioButton Name="TriangleRadio" Content="Triangle" GroupName="ShapeRadios" Margin="20,5,0,0" Click="ShapeRadios_Click"/>
                <RadioButton Name="LineRadio" Content="Line" GroupName="ShapeRadios" Margin="20,5,0,0" Click="ShapeRadios_Click"/>
            </StackPanel>
            <Label x:Name="WidthLbl" Content="Width" FontSize="14" Margin="0,20,0,0"/>
            <Slider x:Name="WidthSlider" Orientation="Horizontal" Margin="10,5,10,0" Value="8" IsSnapToTickEnabled="True" Minimum="1" Maximum="16" ValueChanged="WidthSlider_ValueChanged"/>
            <Label x:Name="HeightLbl" Content="Height" FontSize="14" Margin="0,20,0,0"/>
            <Slider x:Name="HeightSlider" Orientation="Horizontal" Margin="10,5,10,0" Value="8" IsSnapToTickEnabled="True" Minimum="1" Maximum="16" ValueChanged="HeightSlider_ValueChanged"/>
            <Label x:Name="FillColourLbl" Content="Fill colour" FontSize="14" Margin="0,20,0,0"/>
            <xctk:ColorPicker x:Name="FillColourPicker" Height="26" ColorMode="ColorCanvas" UsingAlphaChannel="False" Margin="10,5,10,0" SelectedColor="#108beb" SelectedColorChanged="FillColourPicker_SelectedColorChanged"/>
            <Label x:Name="LineColourLbl" Content="Line colour" FontSize="14" Margin="0,20,0,0" Visibility="Visible"/>
            <xctk:ColorPicker x:Name="LineColourPicker" Height="26" ColorMode="ColorCanvas" UsingAlphaChannel="False" Margin="10,5,10,0" SelectedColor="#0c3c62" SelectedColorChanged="LineColourPicker_SelectedColorChanged" Visibility="Visible"/>
            <Label x:Name="ThicknessLbl" Content="Line thickness" FontSize="14" Margin="0,20,0,0" Visibility="Visible"/>
            <Slider x:Name="ThicknessSlider" Orientation="Horizontal" Margin="10,5,10,0" Value="2" IsSnapToTickEnabled="True" Minimum="1" Maximum="5" ValueChanged="ThicknessSlider_ValueChanged" Visibility="Visible"/>
            <Label x:Name="DashLbl" Content="Line effects" FontSize="14" Margin="0,20,0,0" Visibility="Visible"/>
            <StackPanel Orientation="Horizontal" Visibility="Visible">
                <RadioButton Name="NoEffectRadio" Content="None" GroupName="LineEffectRadios" Margin="10,5,0,0" IsChecked="True" Click="LineEffectRadios_Click"/>
                <RadioButton Name="DashedRadio" Content="Dashes" GroupName="LineEffectRadios" Margin="20,5,0,0" Click="LineEffectRadios_Click"/>
                <RadioButton Name="DottedRadio" Content="Dots" GroupName="LineEffectRadios" Margin="20,5,0,0" Click="LineEffectRadios_Click"/>
            </StackPanel>
            <Button Name="ExportBtn" Content="Export image" HorizontalAlignment="Right" Padding="15,5" Margin="10,25,10,0" Click="ExportBtn_Click" Visibility="Visible"/>
        </StackPanel>
    </Grid>
</Window>