在C#代码中遇到计时器问题

时间:2017-04-24 17:58:54

标签: c#

我在使用C#代码实现计时器时遇到问题。我正在做的高级概述,我有一个WPF应用程序,它根据数据源每三秒更新一次显示给用户的数据。窗口上的大多数数据每三秒更改一次,但我尝试对计数执行SQL查询,我只希望数据每5分钟更新一次。所以我构建了下面显示的SQL查询,并且计时器也如下所示,但是当它必须返回一个字符串并且我不确定如何通过它时,计时器期望它是一个空白。

我最初尝试使用Timer(这在我的main方法中运行):

Timer t = new Timer(TimeSpan.FromMinutes(5).TotalMilliseconds); // set the time (5 min in this case)
            t.AutoReset = true;
            t.Elapsed += new System.Timers.ElapsedEventHandler(SQLDataTotalCalls());
            t.Start();

我的SQL查询方法:

public string SQLDataTotalCalls(object sender, ElapsedEventArgs a)
{
    DateTime dte = DateTime.Today;

    string fixedStartDate = String.Format("{0:yyyy-MM-dd " + "05:00:00.000" + "}", dte);
    string fixedEndDate = String.Format("{0:yyyy-MM-dd " + "05:00:00.000" + "}", dte.AddDays(1));

    SqlConnection connection = null;
    try
    {
        var dataSet = new DataSet();

        connection = new SqlConnection("Data Source=QL1OADB1;Initial Catalog=OADB;User Id=username;Password=password;
        connection.Open();

        var command = new SqlCommand("SELECT COUNT(SOURCEID) AS 'MYCOUNT' "
                                     + "FROM [OADB].[oadb].[CmsCallHistory] "
                                     + "WHERE disposition = 2 and DISPSPLIT in (" + SkillNumber + ") AND SEGSTOP BETWEEN '" + fixedStartDate + "' and '" + fixedEndDate + "'",
            connection)
        {
            CommandType = CommandType.Text
        };

        var dataAdapter = new SqlDataAdapter { SelectCommand = command };

        dataAdapter.Fill(dataSet);

        return dataSet.Tables[0].Rows[0]["MYCOUNT"].ToString();

    }
    catch (Exception e)
    {
        throw new Exception(e.Message, e);
    }
    finally
    {
        if (connection != null)
        {
            connection.Close();
        }
    }
}

更新

根据下面的建议答案,我已将上述内容改为:

async Task RunPeriodicQueryTotalCalls()
{
    TimeSpan interval = TimeSpan.FromMinutes(5);

    while (true)
    {
        await Task.Delay(interval);

        string result = await Task.Run(SQLDataTotalCalls);

        TotalDailyCalls = result;
    }
}

我已经更新了我的SQL查询方法以获得此声明:

public string SQLDataTotalCalls() { ... }

但是我收到编译错误:

  

错误CS0121:以下方法或属性之间的呼叫不明确:' Task.Run< TResult>(Func< TResult>)'和' Task.Run(Func< Task>)'

2 个答案:

答案 0 :(得分:2)

  1. 您的代码正在调用方法,而不是将事件指向您的方法。

    //注意没有parens,那是因为你把它指向一个方法,而不是运行方法

    t.Elapsed + = new System.Timers.ElapsedEventHandler(SQLDataTotalCalls);

  2. 更简单的方法是:

                t.Elapsed += SQLDataTotalCalls;
    
    1. 计时器只应用于触发事件,而不是返回值。在事件委托(SQLDataTotalCalls)中完成的操作应该将字符串传递给其他对象或服务以保存字符串。

    2. 您需要更改SQLDataTotalCalls方法的签名以返回void,以便它与计时器处理程序所需的签名匹配

答案 1 :(得分:2)

假设C#允许您订阅string - 返回方法到void - 声明的事件。确切地说,您认为实际上会收到哪些代码返回值?你会在哪里使用它?

您的问题中没有太多上下文,这使得很难(如果不是不可能的话)准确理解您希望代码执行的操作。您的问题中没有任何内容表明您将如何获得返回的string值,也不知道您将如何使用它。

所有这一切,我认为使用Task Parallel Library API而不是计时器可能会更好地满足您的需求。这将允许您轻松地将返回值从后台任务移动到UI线程,以及为您处理时间。

例如:

async Task RunPeriodicQuery()
{
    TimeSpan interval = TimeSpan.FromMinutes(5);

    while (true)
    {
        await Task.Delay(interval);

        string result = await Task.Run((Func<string>)SQLDataTotalCalls);

        // do something with "result" here...you'll be in the UI thread, so make it quick
    }
}

在上文中,您将从SQLDataTotalCalls()方法声明中删除参数。

您需要在初始化代码的某些部分调用方法RunPeriodicQuery() ,否则将创建并启动计时器。上面的实现使用了一个inifite while (true)循环,当然你可以引入任何你希望它允许方法退出的机制,如果你想让它停止运行,比如使用bool字段代替true来控制循环操作。

如果这不能令人满意地解决您的问题,请通过编辑来改进问题,以便它包含一个好的Minimal, Complete, and Verifiable code example,清楚地显示您尝试过的内容,准确解释代码的作用以及您想要的内容它可以改为做。