implement while loop without starvation for redrawing an image in wpf

81 Views Asked by At

i have a wpf form and a canvas in it and an image in canvas. i want this image to move randomly to directions every n milliseconds. i used while loop but it stocked in starvation. so i had no way to implement this movement by one mouse event to see how good is my idea about this movement. this is my code below:

public void movebox()
        {
            Random rnd = new Random();
            int movex = rnd.Next(0, 2);
            int movey = rnd.Next(0, 2);
            Canvas.SetTop(image1, Canvas.GetTop(image1) + (movey == 1 ? 1 : -1));
            Canvas.SetLeft(image1, Canvas.GetLeft(image1) + (movex == 1 ? 1 : -1));
        }
private void Window_MouseMove(object sender, MouseEventArgs e)
        {
            movebox();
        }

i likes movement of image but now i have same problem yet. i need this object to move automatically forever every n milliseconds without starvation. this is my ideal code below:

while(true){
                Random rnd = new Random();
                int movex = rnd.Next(0, 2);
                int movey = rnd.Next(0, 2);
                Canvas.SetTop(image1, Canvas.GetTop(image1) + (movey == 1 ? 1 : -1));
                Canvas.SetLeft(image1, Canvas.GetLeft(image1) + (movex == 1 ? 1 : -1));
                Thread.Sleep(1000);
            }

what should i have do now?

1

There are 1 best solutions below

0
On BEST ANSWER

One thing you can do if you really want a loop is to start another thread and use that. This way your UI will stay responsive.

public void movebox()
{
    Task.Run(() => 
    {
        while(true)
        {
            Random rnd = new Random();
            int movex = rnd.Next(0, 2);
            int movey = rnd.Next(0, 2);
            Dispatcher.Invoke(() => {
                Canvas.SetTop(image1, Canvas.GetTop(image1) + (movey == 1 ? 1 : -1));
                Canvas.SetLeft(image1, Canvas.GetLeft(image1) + (movex == 1 ? 1 : -1));
            });
            Thread.Sleep(1000);
        }
    });
}

A better approach however is to use Timer like this:

System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0,0,1);
dispatcherTimer.Start();


private void dispatcherTimer_Tick(object sender, EventArgs e)
{
    Random rnd = new Random();
    int movex = rnd.Next(0, 2);
    int movey = rnd.Next(0, 2);
    Canvas.SetTop(image1, Canvas.GetTop(image1) + (movey == 1 ? 1 : -1));
    Canvas.SetLeft(image1, Canvas.GetLeft(image1) + (movex == 1 ? 1 : -1));
}

Disclaimer: I have written the code in browser.