我确定这个问题已经在某个地方得到了解答,但是我试图在这里找到一个方法,因为几个小时后再踩到Thread Timers
(这对周期性事件起作用,但不是定时器有不同的变量和间隔使用)我没有找到任何东西。我真的不确定要搜索什么。非常感谢更好的主题标题或描述!
在Thread
我正在下载一个JSON,其中包含有关虚拟项目的信息,然后使用HTTPClient
解析这些值并将其添加到ListView中。对于每个项目,JSON看起来都是这样的(项目名称从TextBox中读取并添加到请求和ListView中)
{
"success":true,
"price":"31,98",
"amount":"33"
}
ListView包含4列,而在Interval列中输入所需的刷新间隔。
Item Name Price Amount Interval
我的计划:我希望使用普通文本框和按钮将项目名称和间隔添加到ListView。然后我想启动定时器,其中每个定时器将读出一个项目的间隔,然后刷新相应项目的价格,并保留在列表中的间隔。每个项目应该有一个Timer,它可以独立于其他定时器执行HTTP请求。
Thread一次只能处理一个项目,但它不会定期自动刷新值;
private void getPrice()
{
try
{
HttpClient client = new HttpClient();
JObject o = JObject.Parse(client.GetStringAsync("http://localhost/item.php?itemname=" + tb_MarketName.Text).Result);
string Price = (string)o["price"];
string Amount = (string)o["amount"];
lV_Items.Invoke((Action)delegate
{
ListViewItem items = new ListViewItem(tb_ItemName.Text));
items.SubItems.Add(Price);
items.SubItems.Add(Amount);
items.SubItems.Add(tb_Interval.Text);
lV_Items.Items.Add(items);
});
}
catch (Exception e)
{
SendMail("Crash at " + DateTime.Now.ToString(), e.ToString());
}
}
答案 0 :(得分:2)
拥有一个计时器怎么样?使用AutoReset = true;
将其间隔设置为列表中可用的最低可能间隔(假设此示例为1分钟)。在Elapsed
事件中,浏览您的列表并确定哪些项目适合在当前时间更新(根据其间隔和上次更新时间与当前时间),并将其添加到{{1}收集。因此,当计时器在下午12:05点火时,最后一次更新时间为中午12点,间隔为5分钟的订单项。
在您的收藏中有物品后,您可以在收集的IEnumerable
内部调用Parallel.Foreach()
代码。这将基本上多线程化您的更新,而不会添加所有getPrice()
的混乱。如果将Timers
更改为异步方法,则可以阻止长时间运行的更新(例如下午12:07)阻止下一个更新(下午12:08)。
答案 1 :(得分:1)
尝试使用Microsoft的Reactive Framework(NuGet" Rx-Main")。
这将是您的整个代码:
var subscription =
lV_Items.ToObservable()
.SelectMany(x =>
Observable
.Interval(TimeSpan.FromSeconds(x.Interval))
.SelectMany(n =>
Observable
.Using(
() => new System.Net.Http.HttpClient(),
client => Observable.FromAsync(
() => client.GetStringAsync("http://localhost/item.php?itemname=" + x.MarketName)))
.Select(x => JObject.Parse(x))
.Select(o => new { lv_item = x, price = (string)o["price"], amount = (string)o["amount"] })))
.ObserveOn(lV_Items)
.Subscribe(result =>
{
result.lv_item.Amount = result.amount;
result.lv_item.Price = result.price;
});
要关闭此功能,只需拨打subscription.Dispose();
。
您必须让列表视图代码正常工作,因为我刚刚做了一个快速的工具来向您展示该做什么。