private void SaveTriangleAsPicture()
{
if (triangle == null)
{
MessageBox.Show("No triangle to save!");
return;
}
try
{
SaveFileDialog dialog = new SaveFileDialog()
{
Filter = "PNG Image|*.png|Jpeg Image|*.jpg|BMP Image|*.bmp",
Title = "Save Triangle as Picture",
FileName = $"Triangle_{DateTime.Now:yyyyMMddHHmmssffff}.png"
};
if (dialog.ShowDialog() == true)
{
BitmapEncoder bmpEncoder = System.IO.Path.GetExtension(dialog.FileName).ToLower() switch
{
".jpg" or ".jpeg" => new JpegBitmapEncoder(),
".bmp" => new BmpBitmapEncoder(),
_ => new PngBitmapEncoder()
};
// Calculate the bounds of the triangle
Rect bounds = GetTriangleBounds(triangle);
// Add some padding around the triangle
double padding = 10;
bounds = new Rect(
bounds.X - padding,
bounds.Y - padding,
bounds.Width + padding * 2,
bounds.Height + padding * 2);
// Create a visual for the triangle only
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
// Draw white background
drawingContext.DrawRectangle(Brushes.White, null, bounds);
// Draw the triangle
DrawTriangleGeometry(drawingContext, triangle, bounds);
}
var dpi=VisualTreeHelper.GetDpi(this);
// Render the visual to bitmap
RenderTargetBitmap rtb = new RenderTargetBitmap(
(int)(bounds.Width*dpi.DpiScaleX),
(int)(bounds.Height*dpi.DpiScaleY),
dpi.PixelsPerInchX,
dpi.PixelsPerInchY,
PixelFormats.Pbgra32);
rtb.Render(drawingVisual);
// Save to file
using (FileStream fileStream = new FileStream(dialog.FileName, FileMode.Create))
{
bmpEncoder.Frames.Add(BitmapFrame.Create(rtb));
bmpEncoder.Save(fileStream);
}
MessageBox.Show($"Triangle saved as {dialog.FileName} successfully!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private Rect GetTriangleBounds(Polygon triangle)
{
if (triangle.Points.Count == 0)
{
return new Rect(0, 0, sideLength, sideLength);
}
double minX = triangle.Points[0].X;
double maxX = triangle.Points[0].X;
double minY = triangle.Points[0].Y;
double maxY = triangle.Points[0].Y;
foreach (Point point in triangle.Points)
{
if (point.X < minX)
{
minX = point.X;
}
if (point.X > maxX)
{
maxX = point.X;
}
if (point.Y < minY)
{
minY = point.Y;
}
if (point.Y > maxY)
{
maxY = point.Y;
}
}
return new Rect(minX, minY, maxX - minX, maxY - minY);
}
private void DrawTriangleGeometry(DrawingContext drawingContext,
Polygon triangle, Rect bounds)
{
// Create a stream geometry for the triangle
StreamGeometry geometry = new StreamGeometry();
using (StreamGeometryContext streamGeoContext = geometry.Open())
{
streamGeoContext.BeginFigure(triangle.Points[0], true, true);
streamGeoContext.PolyLineTo(new List<Point>(triangle.Points), true, true);
}
// Apply translation to position the triangle correctly
TransformGroup transformGroup = new TransformGroup();
transformGroup.Children.Add(new TranslateTransform(-bounds.X, -bounds.Y));
geometry.Transform = transformGroup;
geometry.Freeze();
// Draw the triangle with the same properties as the original
drawingContext.DrawGeometry(triangle.Fill, new Pen(triangle.Stroke,
triangle.StrokeThickness), geometry);
}
![image]()
![image]()
![image]()
![image]()
//xaml
<Window x:Class="WpfApp15.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:WpfApp15"
mc:Ignorable="d"
WindowState="Maximized"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Canvas x:Name="cvs"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Transparent"/>
</Grid>
</Window>
//cs
using Microsoft.Win32;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp15
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private double sideLength = 100.0d;
private Polygon triangle = null;
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
DrawTriangle();
}
private void DrawTriangle()
{
try
{
cvs.Children.Clear();
double centerX = cvs.ActualWidth / 2;
double centerY = cvs.ActualHeight / 2;
double height = (Math.Sqrt(3) / 2) * sideLength;
Point topPt = new Point(centerX, centerY - height / 2);
Point leftPt = new Point(centerX - sideLength / 2, centerY + height / 2);
Point rightPt = new Point(centerX + sideLength / 2, centerY + height / 2);
triangle = new Polygon()
{
Stroke = Brushes.Black,
StrokeThickness = 2,
Fill = Brushes.Red
};
triangle.Points.Add(topPt);
triangle.Points.Add(leftPt);
triangle.Points.Add(rightPt);
CreateTriagnleWithContextMenu(triangle);
cvs.Children.Add(triangle);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void CreateTriagnleWithContextMenu(Polygon triangle)
{
ContextMenu contextMenu = new ContextMenu();
//Save As Picture menu item.
MenuItem saveMenuItem = new MenuItem();
saveMenuItem.Header = "Save As Picture";
saveMenuItem.Click += (s, e) => SaveTriangleAsPicture();
//Remove
MenuItem removeItem = new MenuItem();
removeItem.Header = "Remove Triangle";
removeItem.Click += (s, e) => RemoveTriangle();
contextMenu.Items.Add(saveMenuItem);
contextMenu.Items.Add(removeItem);
triangle.ContextMenu = contextMenu;
triangle.MouseRightButtonDown += (s, e) =>
{
triangle.ContextMenu.IsOpen = true;
e.Handled = true;
};
}
private void RemoveTriangle()
{
try
{
if(triangle!=null)
{
cvs.Children.Remove(triangle);
triangle = null;
MessageBox.Show("Triangle has been removed!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void SaveTriangleAsPicture()
{
if (triangle == null)
{
MessageBox.Show("No triangle to save!");
return;
}
try
{
SaveFileDialog dialog = new SaveFileDialog()
{
Filter = "PNG Image|*.png|Jpeg Image|*.jpg|BMP Image|*.bmp",
Title = "Save Triangle as Picture",
FileName = $"Triangle_{DateTime.Now:yyyyMMddHHmmssffff}.png"
};
if (dialog.ShowDialog() == true)
{
BitmapEncoder bmpEncoder = System.IO.Path.GetExtension(dialog.FileName).ToLower() switch
{
".jpg" or ".jpeg" => new JpegBitmapEncoder(),
".bmp" => new BmpBitmapEncoder(),
_ => new PngBitmapEncoder()
};
// Calculate the bounds of the triangle
Rect bounds = GetTriangleBounds(triangle);
// Add some padding around the triangle
double padding = 10;
bounds = new Rect(
bounds.X - padding,
bounds.Y - padding,
bounds.Width + padding * 2,
bounds.Height + padding * 2);
// Create a visual for the triangle only
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
// Draw white background
drawingContext.DrawRectangle(Brushes.White, null, bounds);
// Draw the triangle
DrawTriangleGeometry(drawingContext, triangle, bounds);
}
var dpi=VisualTreeHelper.GetDpi(this);
// Render the visual to bitmap
RenderTargetBitmap rtb = new RenderTargetBitmap(
(int)(bounds.Width*dpi.DpiScaleX),
(int)(bounds.Height*dpi.DpiScaleY),
dpi.PixelsPerInchX,
dpi.PixelsPerInchY,
PixelFormats.Pbgra32);
rtb.Render(drawingVisual);
// Save to file
using (FileStream fileStream = new FileStream(dialog.FileName, FileMode.Create))
{
bmpEncoder.Frames.Add(BitmapFrame.Create(rtb));
bmpEncoder.Save(fileStream);
}
MessageBox.Show($"Triangle saved as {dialog.FileName} successfully!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private Rect GetTriangleBounds(Polygon triangle)
{
if (triangle.Points.Count == 0)
{
return new Rect(0, 0, sideLength, sideLength);
}
double minX = triangle.Points[0].X;
double maxX = triangle.Points[0].X;
double minY = triangle.Points[0].Y;
double maxY = triangle.Points[0].Y;
foreach (Point point in triangle.Points)
{
if (point.X < minX)
{
minX = point.X;
}
if (point.X > maxX)
{
maxX = point.X;
}
if (point.Y < minY)
{
minY = point.Y;
}
if (point.Y > maxY)
{
maxY = point.Y;
}
}
return new Rect(minX, minY, maxX - minX, maxY - minY);
}
private void DrawTriangleGeometry(DrawingContext drawingContext,
Polygon triangle, Rect bounds)
{
// Create a stream geometry for the triangle
StreamGeometry geometry = new StreamGeometry();
using (StreamGeometryContext streamGeoContext = geometry.Open())
{
streamGeoContext.BeginFigure(triangle.Points[0], true, true);
streamGeoContext.PolyLineTo(new List<Point>(triangle.Points), true, true);
}
// Apply translation to position the triangle correctly
TransformGroup transformGroup = new TransformGroup();
transformGroup.Children.Add(new TranslateTransform(-bounds.X, -bounds.Y));
geometry.Transform = transformGroup;
geometry.Freeze();
// Draw the triangle with the same properties as the original
drawingContext.DrawGeometry(triangle.Fill, new Pen(triangle.Stroke,
triangle.StrokeThickness), geometry);
}
}
}