【问题标题】:wpf Multiple dispatch timer for timer application : Run multiple timer simulteniouslywpf 用于计时器应用程序的多个调度计时器:同时运行多次
【发布时间】:2017-02-28 06:06:18
【问题描述】:

阅读多个stackoverflow,codeproject解决方案,无法集成到我的问题中。

在加载到窗口中的用户控件中有一个数据网格。 DataGrid 中的每个 DataRow 代表一个计时器设置。

喜欢:

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

选择一行,单击开始按钮,启动该行的计时器。通过调度程序滴答事件,它会更新我在此之前所做的网格。现在我必须启动另一个(或两个或...)计时器,它会同时做同样的事情。我坚持这一点。让我分享一下我的尝试!

ma​​inwindow.xaml.cs 中的 btnStartClickEvent

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 被发现为空。

我想知道如何保留此代码并使其适用于多个计时器。可能是多线程。这样做的指南将非常有帮助。

【问题讨论】:

    标签: c# wpf dispatchertimer


    【解决方案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(),您必须将 UI 工作委派给调度程序。

    此外,将参数传递给Tick 事件已在此处解释:https://stackoverflow.com/a/16380663/6996876 在您的情况下,您可能希望更改当前唯一的 runningRow 以便将其传递给事件。

    【讨论】:

    • 我尝试在 backgroundworker_dowork 事件中添加我的UpgradeGrid() 方法。并在后台升级数据网格。但是当我尝试这种方式时,它变得不可更新。
    • 因为您没有在 dispatcher 中完成所有 UI 工作。仔细阅读我的答案。
    猜你喜欢
    • 2022-01-23
    • 1970-01-01
    • 2017-03-17
    • 2019-03-02
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    相关资源
    最近更新 更多