Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
342 views
in Technique[技术] by (71.8m points)

c# - Saving image (screenshot) of control in WPF - MVVM Pattern

I'm trying to take a screenshot of user control (viewport) in WPF application. My problem is that I don't know how to get the position of window or viewport while staying in accord with MVVM pattern.

Here is the method, but it takes all the screen instead of my viewport, since I don't know how to bind window/viewport properties to it.

    private void saveScreenshot()
        {
            double screenLeft = SystemParameters.VirtualScreenLeft;
            double screenTop = SystemParameters.VirtualScreenTop;
            double screenWidth = SystemParameters.VirtualScreenWidth;
            double screenHeight = SystemParameters.VirtualScreenHeight;


            using (Bitmap bmp = new Bitmap((int)screenWidth, (int)screenHeight))
            {
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    string fileName = "ScreenCapture -" + DateTime.Now.ToString("ddMMyyyy-hhmmss") + ".png";    
                    
                    g.CopyFromScreen((int)screenLeft, (int)screenTop, 0, 0, bmp.Size);

                    SaveFileDialog saveFile = new SaveFileDialog();                    ;
                    saveFile.Filter = "JPEG|*.jpeg|Bitmap|*.bmp|Gif|*.gif|Png|*.png";                    

                    if (saveFile.ShowDialog() == true)
                    {
                        bmp.Save(saveFile.FileName);
                    }                   
                    
                }
            }

        }

I was trying to bind some window properties to ViewModel, to get access to window position on screen, but it didn't work.

XAML:

<Window
    x:Class="SimpleDemo.MainView"
    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:hx="http://helix-toolkit.org/wpf/SharpDX"
    xmlns:hw="http://helix-toolkit.org/wpf" 
    xmlns:local="clr-namespace:SimpleDemo"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
    Title="Point cloud visualization"
    Width="1280"
    Height="720"    
    Left="{Binding LeftScreenPosition, Mode=TwoWay}"
    Top="{Binding TopScreenPosition, Mode=TwoWay}"
    mc:Ignorable="d" Background="#FF465065" Foreground="#FFFFFEFE">

And here is the ViewModel (SetValue contains PropertyChanged event things)

 private double leftScreenPosition;
        private double topScreenPosition;

        public double LeftScreenPosition
        {
            get { return leftScreenPosition; }
            set { SetValue(ref leftScreenPosition, value); }
        }

        public double TopScreenPosition
        {
            get { return leftScreenPosition; }
            set { SetValue(ref leftScreenPosition, value); }
        }

I would be really grateful if someone could explain to me where is the mistake, or show me another way to deal with it (Please consider that i'm a total beginner, thank you).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Trick with CommandParameter can let you pass some FrameworkElement to your command placed in your ViewModel. My example

xaml (you can refine if you need only your control in CommandParameter)

<Window x:Class="WpfTestApp.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:WpfTestApp"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800"
    d:DataContext="{d:DesignInstance Type=local:YourViewModel, IsDesignTimeCreatable=True}">
<Grid>
    <Button Content="Make screenShot" Command="{Binding MakeScreenShotCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
</Grid>

ViewModel

public class YourViewModel
{
    private ICommand _makeScreenShotCommand;
    public ICommand MakeScreenShotCommand => _makeScreenShotCommand ?? (_makeScreenShotCommand = new ActionCommand(TakeScreenShot));

    private void TakeScreenShot(object control)
    {
        FrameworkElement element = control as FrameworkElement;
        if (element == null)
            throw new Exception("Invalid parameter");

        RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)element.ActualWidth, (int)element.ActualHeight, 96, 96, PixelFormats.Pbgra32);
        renderTargetBitmap.Render(element);
        PngBitmapEncoder pngImage = new PngBitmapEncoder();
        pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
        using (Stream fileStream = File.Create("filePath"))
        {
            pngImage.Save(fileStream);
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...