Leo
Leo

Reputation: 5122

Display BitmapSource in WPF not working

The following code takes a snapshot of part of the screen (at the mouse coordinates) and should display it in an Image control.

public partial class MainWindow : Window
{
    Timer timer = new Timer(100);
    public MainWindow()
    {
        InitializeComponent();

        timer.Elapsed += Timer_Elapsed;
        timer.Start();
    }

    [System.Runtime.InteropServices.DllImport("gdi32.dll")]
    public static extern bool DeleteObject(IntPtr hObject);

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        viewerImage.Source = GetSnapAtMouseCoords((int)((Grid)viewerImage.Parent).ActualWidth, (int)((Grid)viewerImage.Parent).ActualHeight, System.Windows.Forms.Cursor.Position);
    }

    private BitmapSource GetSnapAtMouseCoords(int width, int height, System.Drawing.Point mousePosition)
    {
        IntPtr handle = IntPtr.Zero;

        try
        {

            using (var screenBmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
            {
                using (var bmpGraphics = Graphics.FromImage(screenBmp))
                {
                    bmpGraphics.CopyFromScreen(mousePosition.X, mousePosition.Y, 0, 0, screenBmp.Size);

                    handle = screenBmp.GetHbitmap();

                    var bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                     handle,
                     IntPtr.Zero,
                     Int32Rect.Empty,
                     BitmapSizeOptions.FromEmptyOptions());

                    return bs;
                }
            }
        }

        finally
        {
            DeleteObject(handle);
        }
    }
}

Everything works up to the point where I set the image source to the BitmapSource. Unfortunately, the image is never rendered on screen.

I think that maybe this is because I am creating the BitmapSource on the GUI thread... But I am not so sure.

Any suggestions or ideas welcome.

Upvotes: 2

Views: 1137

Answers (1)

Manfred Radlwimmer
Manfred Radlwimmer

Reputation: 13394

Actually it's because you are accessing your GUI on a different Thread. You can either wrap the initial call like this:

Dispatcher.BeginInvoke(new Action(() =>
{
    viewerImage.Source = GetSnapAtMouseCoords(
        (int)((Grid)viewerImage.Parent).ActualWidth, 
        (int)((Grid)viewerImage.Parent).ActualHeight, 
        System.Windows.Forms.Cursor.Position);
}));

Or do all the processing in a background thread an just return a Frozen (Thread safe) BitmapSource. You would hover need to pass (int)((Grid)viewerImage.Parent).ActualWidth differently, since that is owned by the UI thread too.

bs.Freeze();

Dispatcher.BeginInvoke(new Action(() =>
{
    viewerImage.Source = bs;
}));

Upvotes: 3

Related Questions