wpf Таймер множественной отправки для приложения таймера: одновременное выполнение нескольких таймеров

Чтение нескольких stackoverflow, решение codeproject, не удалось интегрировать в мою проблему.

Иметь сетку данных в пользовательском элементе управления, которая загружается в окно. Каждый DataRow в DataGrid представляет настройку таймера.

Нравится:

timer name  : Test 1 , Timer : 1h 3m
timer name  : Test 2 , Timer : 2h 2m
timer name  : Test 3 , Timer : 3h 1m

Выделив строку и нажав кнопку «Старт», запустит таймер этой строки. И с событием тика диспетчера он обновляет сетку, которую я делал до этого. Теперь мне нужно запустить еще один (или два, или ...) таймер, который будет делать то же самое одновременно. Я застрял на этом. Позвольте мне поделиться тем, что я пробовал!

btnStartClickEvent в mainwindow.xaml.cs

if (btnStart.Content.ToString() == "Start")
        {
            if (_AUC == ActiveUserControl.Grid)
            {
                runningRow = (TaskGridData)_TG.dgEmployee.SelectedItem;
                if (runningRow != null)
                {
                    currentlyRunningID.Add(runningRow.ID);
                    btnStart.Content = "Stop";
                    //worker.RunWorkerAsync(runningRow);
                    StartTimer(runningRow);
                }
            }
        }
        else if (btnStart.Content.ToString() == "Stop")
        {
            btnStart.Content = "Start";
            StopTimer();

        }
 private DateTime TimerStart { get; set; }
    private void StartTimer(TaskGridData tgd)
    {
        dispatcherTimer = new DispatcherTimer();

        dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 0);
        dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
        TimerStart = DateTime.Now;
        dispatcherTimer.Start();
        //worker.RunWorkerAsync();

        //string etime = DateTime.Now.Second.ToString();
    }

    private void StopTimer()
    {
        dispatcherTimer.Stop();
    }
private void dispatcherTimer_Tick(object sender, EventArgs e)
    {
        var currentValue = DateTime.Now - TimerStart;
        runningRow.Duration = DurationValueToString(currentValue);
        temp = (List<TaskGridData>)_TG.dgEmployee.ItemsSource;
        foreach (TaskGridData item in temp)
        {
            if (item.ID == runningRow.ID)
            {
                item.Duration = DurationValueToString(DurationStringToVlaue(item.Duration) - DurationStringToVlaue(runningRow.Duration));
                break;
            }
        }
        //_TG.dgEmployee.ItemsSource = null;
        //_TG.dgEmployee.ItemsSource = temp;
        Thread NewThreadforStartProcessAfterTraining = new Thread(() => UpdateGrid());
        NewThreadforStartProcessAfterTraining.IsBackground = true;
        NewThreadforStartProcessAfterTraining.SetApartmentState(ApartmentState.STA);
        NewThreadforStartProcessAfterTraining.Start();

    }
    private void UpdateGrid()
    {
        this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
        {
            _TG.dgEmployee.ItemsSource = null;
            _TG.dgEmployee.ItemsSource = temp;
        }));

    }

Я знаю, что этот код предназначен для одного таймера. Если я щелкну вторую строку и попытаюсь запустить таймер, появится ошибка в событии тика, running row будет обнаружен как null.

Мне интересно, как я могу сохранить этот код и заставить его работать для нескольких таймеров. Может быть многопоточным. Руководство для этого будет очень полезно.


person Abdur Rahim    schedule 28.02.2017    source источник


Ответы (1)


    Thread NewThreadforStartProcessAfterTraining = new Thread(() => UpdateGrid());
    NewThreadforStartProcessAfterTraining.IsBackground = true;
    NewThreadforStartProcessAfterTraining.SetApartmentState(ApartmentState.STA);
    NewThreadforStartProcessAfterTraining.Start();

Вся вышеупомянутая часть, где вы запускаете новый поток STA, не нужна и неверна в этом контексте, поскольку вы не можете обновить визуальное дерево таким образом. Вы можете найти правильный пример использования потока STA в одном из моих предыдущих ответов: https://stackoverflow.com/a/42473167/6996876

Попытайтесь понять концепцию сходства потоков в WPF.

Вам просто нужен UpdateGrid(), в котором вы должны делегировать работу пользовательского интерфейса диспетчеру.

Кроме того, здесь уже объясняется передача аргумента событию Tick: https://stackoverflow.com/a/16380663/6996876 В вашем случае вы можете изменить текущий уникальный runningRow, чтобы вместо этого он передавался событию.

person Community    schedule 28.02.2017
comment
Я попытался добавить свой метод UpgradeGrid() в событие backgroundworker_dowork. и обновите сетку данных в фоновом режиме. но пока я пытался это сделать, он не обновляется. - person Abdur Rahim; 28.02.2017
comment
Потому что вы не выполняете всю работу пользовательского интерфейса в диспетчере. Прочтите мой ответ внимательно. - person ; 28.02.2017