Tain
Tain

Reputation: 229

DispatcherTimer and Button c# conflict

I'm very new to WP8 dev and c#. I'm trying to make a loop that counts up by n on an interval. I want to press a button to increment n.

Here is my code right now:

namespace Petsounds {
    public partial class MainPage : PhoneApplicationPage {
        float clicks = 0;
        float clickers = 0;
        float clickerBuyers = 0;
        float clickerCost = 5;
        float clickerBuyerCost = 500;
        long savedTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;

        bool buyClickerButtonFlag = false;
        bool clickButtonFlag = false;



        // Constructor
        public MainPage() {
            InitializeComponent();

            //
            DispatcherTimer t = new DispatcherTimer();
            t.Interval = TimeSpan.FromMilliseconds(10);
            t.Tick += (s, e) => startLoop();
            t.Start();

        }

        private void clickButtonOnClick(object sender, RoutedEventArgs e) {
            clickButtonFlag = true;
            System.Diagnostics.Debug.WriteLine("clicked!" + clicks);
        }

        private void buyClickerButtonOnClick(object sender, RoutedEventArgs e) {
            buyClickerButtonFlag = true;
        }

        private void startLoop() {
            if (true) {
                long nowTime = savedTime;
                long timePassed = nowTime - savedTime;

                //user input
                if (clickButtonFlag) {
                    clickButtonFlag = false;
                    clicks++;
                    System.Diagnostics.Debug.WriteLine("clicked!" + clicks);
                }
                if (buyClickerButtonFlag) {
                    buyClickerButtonFlag = false;
                    if (clicks > clickerCost) {
                        clickers++;
                        clicks -= clickerCost;
                        clickerCost *= 1.6F;
                    }
                    System.Diagnostics.Debug.WriteLine("clicker bought!" + clickers);
                }
                //update vars
                if (timePassed > TimeSpan.TicksPerSecond) {
                    savedTime = nowTime;
                    nowTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;

                    clicks += clickers;
                }

                //update display
                clickCount.Text = clicks.ToString();
                buyClickerButtonCost.Text = "Cossst " + clickerCost.ToString();
            }
        }
    }
}

My button's are inconsistent, and if I remove the thread, the buttons are responsive (but of course the counter doesn't work.)

EDIT:

I've changed

DispatcherTimer t = new DispatcherTimer();
t.Interval = TimeSpan.FromMilliseconds(10);
t.Tick += (s, e) => startLoop();
t.Start();

to

Timer myTimer = new Timer(startLoop);
myTimer.Change(1000, 10);

And now get an error:

A first chance exception of type 'System.UnauthorizedAccessException' occurred in System.Windows.ni.dll

on line

clickCount.Text = clicks.ToString();

Upvotes: 0

Views: 616

Answers (3)

Romasz
Romasz

Reputation: 29790

It's like @Andrew said - DispatcherTimer works on UI thread and with so small intervall you are blocking it.
If you want such a small interval you can use Timer on different Thread:

public MainPage()
{
   InitializeComponent();

   System.Threading.Timer myTimer = new Timer(MyTimerCallback);
   myTimer.Change(1000, 10);
}
private static int value = 0;

private static void MyTimerCallback(object state)
{
   value++;
}

But you must remember that you use it on different Thread - this Timer has no access to your UI elements (buttons and so on).

EDIT

You convinced me to check it:

    static float clicks = 0;
    static float clickers = 0;
    static float clickerCost = 5;
    static long savedTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;

    static bool buyClickerButtonFlag = false;
    static bool clickButtonFlag = false;

    public MainPage()
    {
        InitializeComponent();

        first.Click += ShowCounter;

        DispatcherTimer t = new DispatcherTimer();
        t.Interval = TimeSpan.FromSeconds(5);
        t.Tick += ShowCounter;
        t.Start();

        System.Threading.Timer myTimer = new Timer(MyTimerCallback);
        myTimer.Change(10, 10);
    }

    private void ShowCounter(object sender, EventArgs e)
    {
        textBlck.Text = clicks.ToString();
    }

    private static void MyTimerCallback(object state)
    {
        clicks++; // added to check running
        if (true)
        {
            long nowTime = savedTime;
            long timePassed = nowTime - savedTime;

            //user input
            if (clickButtonFlag)
            {
                clickButtonFlag = false;
                clicks++;
                System.Diagnostics.Debug.WriteLine("clicked!" + clicks);
            }
            if (buyClickerButtonFlag)
            {
                buyClickerButtonFlag = false;
                if (clicks > clickerCost)
                {
                    clickers++;
                    clicks -= clickerCost;
                    clickerCost *= 1.6F;
                }
                System.Diagnostics.Debug.WriteLine("clicker bought!" + clickers);
            }
            //update vars
            if (timePassed > TimeSpan.TicksPerSecond)
            {
                savedTime = nowTime;
                nowTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;
                clicks += clickers;
            }
        }
    }

I tested it on the device and buttons works.

On the other hand - what's the point of putting a method that waits for a flag buton click, when you can put the job easily to button click event. Let it happen when user clicked button - don't check buton state all the time.

Upvotes: 0

Walt Ritscher
Walt Ritscher

Reputation: 7047

There is a different approach you might want to consider.

If your task is to increment a numeric value when a user touches a button (and have the numbers increase at a steady pace) consider using the RepeatButton.

RepeatButton: Represents a control that raises its Click event repeatedly from the time it is pressed until it is released.

XAML

 <!-- 
   Delay: The time, in milliseconds, the RepeatButton waits 
          when it is pressed before it starts repeating the click action.

  Interval: The time, in milliseconds, between repetitions 
            of the click action, as soon as repeating starts.
  -->
  <RepeatButton Content='Buy'
                Interval='50' Delay='100' 
                Click='RepeatButton_Click' />

Code

private float buyCounter = 0;
private void RepeatButton_Click(object sender, RoutedEventArgs e) {
  buyCounter += 1;
  buyClickerButtonCost.Text = buyCounter.ToString();
}

Upvotes: 0

poy
poy

Reputation: 10557

First of all... you will quickly find that 10ms is not really 10ms... It might not even be that close... If you did 1000ms... that would be expected to be more accurate.

Also, a DispatcherTimer is going to queue up a function call to the GUI thread each interval... which means you are flooding the GUI thread with startLoop() calls. This doesn't give the thread much time to update anything else... like your buttons.

Upvotes: 1

Related Questions