//xaml
<Window x:Class="WpfApp27.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:WpfApp27"
WindowState="Maximized"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Canvas x:Name="cvs" Background="White">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Ellipse x:Name="elp"
Grid.Row="0"
Grid.Column="0"
Stroke="Red"
StrokeThickness="20"
Width="500"
Height="500"
Fill="Cyan"/>
<Rectangle x:Name="rect"
Grid.Row="0"
Grid.Column="1"
Width="500"
Height="500"
Stroke="Red"
StrokeThickness="30"
HorizontalAlignment="Stretch"/>
<Rectangle x:Name="rect2"
Grid.Row="0"
Grid.Column="2"
Width="500"
Height="500"
Stroke="Blue"
StrokeThickness="30"
HorizontalAlignment="Stretch"/>
</Grid>
<Canvas.ContextMenu>
<ContextMenu>
<MenuItem Header="Save As Picture"
Command="{Binding SaveAsPictureCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ContextMenu}},Path=PlacementTarget}"/>
<MenuItem Header="Save Canvas As Image"
Command="{Binding SaveCanvasAsImageCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ContextMenu}},Path=PlacementTarget}"/>
</ContextMenu>
</Canvas.ContextMenu>
</Canvas>
</Grid>
</Window>
//cs
using Microsoft.Win32;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
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 WpfApp27
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new MainVM(this, cvs);
this.DataContext=vm;
}
}
public class MainVM : INotifyPropertyChanged
{
private Window win;
private Canvas cvs;
private int dpiFactor = 2;
public MainVM(Window winValue, Canvas cvsValue)
{
this.win=winValue;
this.cvs=cvsValue;
}
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propName = "")
{
var handler = PropertyChanged;
if (handler!=null)
{
handler?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
private DelCommand saveAsPictureCommand;
public DelCommand SaveAsPictureCommand
{
get
{
if (saveAsPictureCommand==null)
{
saveAsPictureCommand=new DelCommand(SaveAsPictureCommandExecuted);
}
return saveAsPictureCommand;
}
}
private void SaveAsPictureCommandExecuted(object? obj)
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.Filter="Jpg Files|*.jpg|All Files|*.*";
dialog.FileName=$"Canvas_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}";
if (dialog.ShowDialog()==true && cvs!=null)
{
SaveCanvasAsPicture(cvs, dialog.FileName);
MessageBox.Show($"Saved in {dialog.FileName}", "Save Canvas As Picture");
OpenPicture(dialog.FileName);
}
}
private void SaveCanvasAsPicture(Canvas cvs, string fileName)
{
Size size = new Size(cvs.ActualWidth, cvs.ActualHeight);
cvs.Measure(size);
cvs.Arrange(new Rect(size));
RenderTargetBitmap renderBmp = new RenderTargetBitmap((int)size.Width*dpiFactor,
(int)size.Height*dpiFactor, 96*dpiFactor, 96*dpiFactor, PixelFormats.Pbgra32);
renderBmp.Render(cvs);
using (FileStream fs = new FileStream(fileName, FileMode.Create))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBmp));
encoder.Save(fs);
}
}
private void OpenPicture(string fileName)
{
try
{
Process.Start(new ProcessStartInfo
{
FileName = fileName,
UseShellExecute=true
});
}
catch (Exception ex)
{
MessageBox.Show($"Error opening image:{ex.Message}");
}
}
private DelCommand saveCanvasAsImageCommand;
public DelCommand SaveCanvasAsImageCommand
{
get
{
if (saveCanvasAsImageCommand==null)
{
saveCanvasAsImageCommand=new DelCommand(SaveCanvasAsImageCommandExecuted);
}
return saveCanvasAsImageCommand;
}
}
private void SaveCanvasAsImageCommandExecuted(object? obj)
{
SaveFileDialog dialog = new SaveFileDialog()
{
Filter="PNG Image|*.png|JPEG Image|*.jpg|Bitmap Image|*.bmp",
Title="Save Canvas As Image",
FileName = $"Image_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}"
};
if (dialog.ShowDialog()==true)
{
SaveCanvasToImage(cvs, dialog.FileName);
MessageBox.Show($"Save canvas in {dialog.FileName}");
OpenPicture(dialog.FileName);
}
}
private void SaveCanvasToImage(Canvas cvs, string fileName)
{
string ext = System.IO.Path.GetExtension(fileName).ToLower();
Rect bounds = VisualTreeHelper.GetDescendantBounds(cvs);
RenderTargetBitmap rtb = new RenderTargetBitmap(
(int)bounds.Width*dpiFactor, (int)bounds.Height*dpiFactor,
96*dpiFactor, 96*dpiFactor, PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(cvs);
dc.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv);
BitmapEncoder encoder = null;
switch (ext)
{
case ".jpg":
encoder = new JpegBitmapEncoder();
break;
case ".bmp":
encoder=new BmpBitmapEncoder();
break;
case ".png":
encoder=new PngBitmapEncoder();
break;
}
encoder.Frames.Add(BitmapFrame.Create(rtb));
using (FileStream fs = File.Open(fileName, FileMode.Create))
{
encoder.Save(fs);
}
}
}
public class DelCommand : ICommand
{
private Action<object?> execute;
private Predicate<object?> canExecute;
public DelCommand(Action<object?> executeValue, Predicate<object?> canExecuteValue = null)
{
execute=executeValue;
canExecute=canExecuteValue;
}
public event EventHandler? CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public bool CanExecute(object? parameter)
{
return canExecute==null ? true : canExecute(parameter);
}
public void Execute(object? parameter)
{
execute(parameter);
}
}
}
![image]()
![image]()
![image]()