Supahotfire420
Supahotfire420

Reputation: 441

WPF Application DispatcherTimer not working correctly (lag)

I have been trying to run a very simple application that moves a 20 by 20 pixel square 20 pixels to the right on a canvas every second. I am using a dispatchertimer to fire the event every second.

The problem is that the square doesn't move to the right unless I shake the application window (with my mouse), and it occasionally moves on its own (albeit not every second).

I have already tried reinstalling Visual Studio 2017 and installing it on my SSD and HDD, neither seem to fix the issue.

Here is the full code of the application's MainWindow.xaml.cs

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    DispatcherTimer timer = new DispatcherTimer();
    Rectangle s = new Rectangle();
    Point currentPosition = new Point(20, 20);

    public MainWindow()
    {
        InitializeComponent();
        timer.Tick += Timer_Tick;
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Start();

        s.Width = 20;
        s.Height = 20;
        s.Fill = new SolidColorBrush(Colors.Black);

        map.Children.Add(s);
    }

    public void Timer_Tick(object sender, EventArgs e)
    {
        RedrawSquare(); 
    }

    public void RedrawSquare()
    {
        map.Children.Clear();

        s.Width = 20;
        s.Height = 20;
        s.Fill = new SolidColorBrush(Colors.Black);

        Canvas.SetLeft(s, currentPosition.X += 20);

        map.Children.Add(s);
    }
}

On the MainWindow.xaml file there is an empty Canvas with the name "map"

Thank you in advance

Upvotes: 0

Views: 2194

Answers (2)

Shahin Dohan
Shahin Dohan

Reputation: 6907

You can try setting the DispatcherPriority to Normal.

Instantiate your timer like this:

DispatcherTimer timer = new DispatcherTimer(DispatcherPriority.Normal);

EDIT:

Although this somehow fixed the issue (square was moving without the need to move the window), it's apparently still the wrong answer. I don't know much about the DispatcherTimer, but I recall having changed the priority once but I don't remember why. In any case, it might be helpful to someone else.

Upvotes: 2

Clemens
Clemens

Reputation: 128013

You don't need to remove and add the Rectangle on each timer tick, or reset its properties each time.

Just increment the value of the Canvas.Left property:

public partial class MainWindow : Window
{
    private readonly DispatcherTimer timer = new DispatcherTimer();
    private readonly Rectangle s = new Rectangle();

    public MainWindow()
    {
        InitializeComponent();

        timer.Tick += Timer_Tick;
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Start();

        s.Width = 20;
        s.Height = 20;
        s.Fill = Brushes.Black;
        Canvas.SetLeft(s, 0);

        map.Children.Add(s);
    }

    public void Timer_Tick(object sender, EventArgs e)
    {
        Canvas.SetLeft(s, Canvas.GetLeft(s) + 20);
    }
}

The movement would however be much smoother with an animation:

public MainWindow()
{
    InitializeComponent();

    s.Width = 20;
    s.Height = 20;
    s.Fill = Brushes.Black;
    Canvas.SetLeft(s, 0);

    map.Children.Add(s);

    var animation = new DoubleAnimation
    {
        By = 20,
        Duration = TimeSpan.FromSeconds(1),
        IsCumulative = true,
        RepeatBehavior = RepeatBehavior.Forever
    };

    s.BeginAnimation(Canvas.LeftProperty, animation);
}

Upvotes: 2

Related Questions