Проблема кросс-потоков с C # ProgressBar - PullRequest
2 голосов
/ 31 октября 2011

Я создаю таймер обратного отсчета, который позволяет пользователю выбрать правильное время, и как только обратный отсчет достигает нуля, он воспроизводит звук.

Я создал экземпляр таймера из пространства имен System.Timers и установил его Interval в 1 секунду. Я конвертирую указанное пользователем время в секунды и уменьшаю это значение на 1 каждый раз, когда срабатывает функция Timer.Elapsed. Как только он достигает нуля, это означает, что обратный отсчет достиг нуля, что означает, что пришло время воспроизвести звук.

Однако всякий раз, когда оно не достигает нуля, я уменьшаю значение времени на 1, и я также хочу увеличить ProgressBar с помощью функции progressbar.Increment.

К сожалению, всякий раз, когда я делаю это, я получаю исключение, касающееся проблем многопоточности. Я знаю, что не так, но я не уверен, как это исправить. Нужно ли запускать функцию timer.Elapsed в новом потоке?

Ошибка:

Недопустимая операция между потоками: доступ к элементу управления CountdownProgress из потока, отличного от потока, в котором он был создан.

Также приветствуются любые советы по улучшению навыков программирования. Большое спасибо!

Вот код:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;
using System.Media;
using System.Diagnostics;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form_CDA : Form
    {
        public Form_CDA()
        {
            InitializeComponent();
        }

        private bool m_CountdownActive; // declare global variables and instantiate timer.
        private bool m_Cancelled;
        public decimal seconds;
        public decimal minutes;
        public decimal hours;
        public decimal time;
        public System.Timers.Timer timer = new System.Timers.Timer();

        private void Form_CDA_Load(object sender, EventArgs e)
        {
            m_Cancelled = false;
            timer.AutoReset = false;
            timer.Interval = 0;
            m_CountdownActive = false;
            richTextBox1.Text = "Hello, please select an hour between 0 and 100, a minute between 0 and 59, and a second between 0 and 59. The countdown timer will play a sound when finished.";
            btn_Cancel.Enabled = false;
            seconds = 0;
            minutes = 0;
            hours = 0;
            time = 0;
            m_StatusBar.Text = "Program properly loaded, waiting for user input"; // initialize variables.
        }

        private void btn_SetCountdown_Click(object sender, EventArgs e)
        {
            seconds = numUpDown_Seconds.Value;
            minutes = numUpDown_Minutes.Value;
            hours = numUpDown_Hours.Value;
            time = (hours * 3600) + (minutes * 60) + seconds; // calculate the total time in seconds.
            if (time != 0) // if time is not zero, start timer and set up event handler timer.elapsed.
            {
                timer.Interval = 1000;
                timer.AutoReset = true;
                timer.Start();
                timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
                CountdownProgress.Maximum = (int)time;
                CountdownProgress.Minimum = 0;
                CountdownProgress.Value = 0;
            }
            else
            {
                m_StatusBar.Text = "Invalid selection of times. Try again.";
                return;
            }
            DateTime dt = DateTime.Now;
            dt.AddSeconds((double)time);
            Label_Countdown.Text = "Finishing time: " + dt.ToString(); // display end time to user.
            m_CountdownActive = true;
            btn_Cancel.Enabled = true;
            btn_SetCountdown.Enabled = false;
            numUpDown_Hours.Enabled = false;
            numUpDown_Minutes.Enabled = false;
            numUpDown_Seconds.Enabled = false; // disable controls.
            m_Cancelled = true;
            m_StatusBar.Text = "Timer set to " + numUpDown_Hours.Value.ToString() + " hours, " + numUpDown_Minutes.Value.ToString() + " minutes, " + numUpDown_Seconds.Value.ToString() + " seconds.";
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (time == 0)
            {
                m_StatusBar.Text = "Countdown Finished";
                SoundPlayer soundPlayer = new SoundPlayer(@"C:\Users\marupakuuu\Desktop\New stuff\doorbell.wav");
                soundPlayer.Play(); // play sound.
                timer.Stop();
                return;
            }
            else
            {
                time = time - 1;
                CountdownProgress.Increment(1); // exception occurs here; multithreading issues.
            }
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            // if user wishes to stop the countdown to start a new one.
            m_Cancelled = true;
            m_CountdownActive = false;
            btn_SetCountdown.Enabled = true;
            numUpDown_Seconds.Value = 0;
            numUpDown_Minutes.Value = 0;
            numUpDown_Hours.Value = 0;
            numUpDown_Hours.Enabled = true;
            numUpDown_Minutes.Enabled = true;
            numUpDown_Seconds.Enabled = true;
            btn_Cancel.Enabled = false;
            m_StatusBar.Text = "Countdown cancelled";
        }
    }
}

1 Ответ

8 голосов
/ 31 октября 2011

Элемент управления доступен только в том потоке, в котором он был создан.Поэтому используйте Invoke для выполнения заданного кода в качестве делегата в главном потоке, в котором был создан элемент управления (индикатор выполнения).

void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    if (time == 0)
    {
        m_StatusBar.Text = "Countdown Finished";
        SoundPlayer soundPlayer = new SoundPlayer(@"C:\Users\marupakuuu\Desktop\New stuff\doorbell.wav");
        soundPlayer.Play(); // play sound.
        timer.Stop();
        return;
    }
    else
    {
        time = time - 1;
        Invoke(new Action(() => CountdownProgress.Increment(1)));
    }
}

Возможно, вы захотите прочитать http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...