我在使用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>)'
答案 0 :(得分:2)
您的代码正在调用方法,而不是将事件指向您的方法。
//注意没有parens,那是因为你把它指向一个方法,而不是运行方法
t.Elapsed + = new System.Timers.ElapsedEventHandler(SQLDataTotalCalls);
更简单的方法是:
t.Elapsed += SQLDataTotalCalls;
计时器只应用于触发事件,而不是返回值。在事件委托(SQLDataTotalCalls)中完成的操作应该将字符串传递给其他对象或服务以保存字符串。
您需要更改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,清楚地显示您尝试过的内容,准确解释代码的作用以及您想要的内容它可以改为做。