Sign in to follow this  

Drawing on Timer tick

This topic is 735 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm getting frustrated because I can't proceed with my project development without getting this (seemingly simple) problem out of the way, so I need help.

 

The below WPF will simply put a dot on the screen at the click of a mouse. However, I want a timer to run (say every two seconds), and call the OnTimedEvent() to carry out the vital task of plotting a dot at the top-left of the image. This is of course a rather slimmed-down example of my project.

 

If I uncomment the SetTimer() line, then the code will throw the "The calling thread cannot access this object because a different thread owns it" exception. I kind of understand that the main app thread owns the WriteableBitmap, and I kind of understand that the timer is a separate thread. But I don't understand how to just get it to work and do as it's told. I've spent all evening googling and read all about async/await and DispatchTimer and all sorts but I just can't work it out.

 

Could someone kindly put me on the right track.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Input;
using System.Timers;

namespace MyFail
{
    class Program
    {
        private static System.Timers.Timer aTimer;
        static WriteableBitmap writeableBitmap = BitmapFactory.New(1024, 768);
        static Window w;
        static Image i;

        [STAThread]
        static void Main(string[] args)
        {
            i = new Image();
            w = new Window();
            w.Content = i;
            w.Width = 1024;
            w.Height = 768;
            w.Show();

            writeableBitmap = new WriteableBitmap(
                (int)w.ActualWidth,
                (int)w.ActualHeight,
                96,
                96,
                PixelFormats.Bgr32,
                null);

            i.Source = writeableBitmap;
            i.Stretch = Stretch.None;
            i.HorizontalAlignment = HorizontalAlignment.Left;
            i.VerticalAlignment = VerticalAlignment.Top;
            i.MouseLeftButtonDown += new MouseButtonEventHandler(i_MouseLeftButtonDown);

            //SetTimer();

            Application app = new Application();
            app.Run();
        }

        static void DrawPixel(int x, int y)
        {
            byte[] ColorData = { 255, 255, 255, 0 }; // B G R
            Int32Rect rect = new Int32Rect(x, y, 1, 1);
            writeableBitmap.WritePixels(rect, ColorData, 4, 0);
        }

        static void i_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DrawPixel((int)e.GetPosition(i).X, (int)e.GetPosition(i).Y);
        }

        private static void SetTimer()
        {
            aTimer = new System.Timers.Timer(2000);
            aTimer.Elapsed += OnTimedEvent;
            aTimer.AutoReset = true;
            aTimer.Enabled = true;
        }

        private static void OnTimedEvent(Object source, ElapsedEventArgs e)
        {
            DrawPixel(0, 0);
        }

    }
}

aegeg

Share this post


Link to post
Share on other sites
Good point; The DispatcherTimer class looks like a combination of Timer and Dispatcher.Invoke.

It's extremely important to know how Dispatcher.Invoke works all by itself, in case you want to do cross-thread stuff without a timer.

Share this post


Link to post
Share on other sites
Sign in to follow this