Jackz
Jackz

Reputation: 151

Change DispatchTimers to other timer to solve performance issues. Cannot update UI, program shutting down

EDIT #1: I have placed worker.RunWorkerAsync() within my timer loop and my application does not shut down anymore. Although nothing seems to happen now.

For performance reasons i need to replace DispatcherTimers with a other timer that runs in a different thread. There are to much delays / freezes so DispatcherTimer is no longer a option.

I am having problems to actually update my GUI thread, my application always seems to shut down without any warnings / errors. I have mainly been trying to experiment with BackGroundWorker in attempt to solve my problem. Everything results in a shut down of my application when i launch it.

Some code examples would be greatly apperciated.

Old code dispatcher code:

    public void InitializeDispatcherTimerWeging()
    {
        timerWegingen = new DispatcherTimer();
        timerWegingen.Tick += new EventHandler(timerWegingen_Tick);
        timerWegingen.Interval = new TimeSpan(0, 0, Convert.ToInt16(minKorteStilstand));
        timerWegingen.Start();
    }

    private void timerWegingen_Tick(object sender, EventArgs e)
    {
        DisplayWegingInfo();
        CaculateTimeBetweenWegingen();
    }

Every 5 seconds the DisplayWegingInfo() and Calculate method should be called upon.

The GUI updates happen in the Calculate method. There a button gets created dynamically and added to a observerableCollection.

Button creation (short version):

    public void CreateRegistrationButton()
    {
        InitializeDispatcherTimerStilstand();

        RegistrationButton btn = new RegistrationButton(GlobalObservableCol.regBtns.Count.ToString());
        btn.RegistrationCount = GlobalObservableCol.regBtnCount;
        btn.Title = "btnRegistration" + GlobalObservableCol.regBtnCount;
        btn.BeginStilstand = btn.Time;

        GlobalObservableCol.regBtns.Add(btn);
        GlobalObservableCol.regBtnCount++;

        btn.DuurStilstand = String.Format("{0:D2}:{1:D2}:{2:D2}", 0, 0, 0);         
    }

New code using threading timer that runs in a different thread then the GUI

    public void InitializeDispatcherTimerWeging()
    {
        worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
        worker.RunWorkerAsync();
    }

    void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        TimerCallback callback = MyTimerCallBack;
        timerWegingen = new Timer(callback);

        timerWegingen.Change(0, 5000);
    }


    private void MyTimerCallBack(object state)
    {
        DisplayWegingInfo();
        CaculateTimeBetweenWegingen();
    }

I timer runs in a separate thread then the GUI thread (that dispatcherTimer uses). But i cannot seem to be able to send this update to the UI thread itself so the updates get actually implemented in the UI.

The button gets refilled with new values every 1 sec trough a other timer. "DuurStilstand" is a dependency property

    private void FillDuurStilstandRegistrationBtn()
    {
        TimeSpan tsSec = TimeSpan.FromSeconds(stopWatch.Elapsed.Seconds);
        TimeSpan tsMin = TimeSpan.FromMinutes(stopWatch.Elapsed.Minutes);
        TimeSpan tsHour = TimeSpan.FromMinutes(stopWatch.Elapsed.Hours);

        if (GlobalObservableCol.regBtns.Count >= 1
                    && GlobalObservableCol.regBtns[GlobalObservableCol.regBtns.Count - 1].StopWatchActive == true)
        {
            GlobalObservableCol.regBtns[GlobalObservableCol.regBtns.Count - 1].DuurStilstand =
                            String.Format("{0:D2}:{1:D2}:{2:D2}", tsHour.Hours, tsMin.Minutes, tsSec.Seconds);
        }
    }

Would i need to use the invoke from Dispatcher in the above method? If so how exactly?

Not sure how to call the ui thread after initializing the doWork method of the BackGroundWorker, my application keeps shutting down after right after start up. I have tried using Dispatcher.BeginInvoke in several methods but all failed so far. At the moment i have no clue how to implement it.

All the above code is written in a separate c# class.

Best Regards, Jackz

Upvotes: 1

Views: 270

Answers (1)

Steve Wong
Steve Wong

Reputation: 2256

When I ran my sample of your code, the DisplayWegingInfo() was throwing an exception trying to access UI components. We need to call Invoke() from the Timer thread to update the UI. See DisplayWegingInfo() below. Note: this assumes that CaculateTimeBetweenWegingen() does not interact with the UI.

   void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        TimerCallback callback = MyTimerCallBack;
        timerWegingen = new System.Threading.Timer(callback);
        timerWegingen.Change(0, 3000);

    }

    private void MyTimerCallBack(object state)
    {
        DisplayWegingInfo();
        CaculateTimeBetweenWegingen();
    }

    private void DisplayWegingInfo()
    {
        if (this.InvokeRequired)
        {
            this.Invoke(new Action(DisplayWegingInfo));
            return;
        }

        // at this point, we are on the UI thread, and can update the GUI elements
        this.label1.Text = DateTime.Now.ToString();
    }

    private void CaculateTimeBetweenWegingen()
    {
        Thread.Sleep(1000);
    }

Upvotes: 1

Related Questions