我首先应该提到我是编程新手。我将尽最大努力解释我的问题和问题。
我想知道是否可以更新ObjectListView的单个列(从此处称为OLV)。我想要的是有一列显示每行的“经过时间”。此Elapsed Time列将每15至30秒刷新一次。
我如何设置我的OLV
myOLV.SetObjects(GetMyList());
GetMyList方法返回从简单数据库查询填充的列表。
在GetMyList方法中,它会将DateTime列转换为显示已用时间的字符串。然后OLV将其显示为字符串,而不是日期时间......
elapsed_time = ((TimeSpan)(DateTime.Now - x.time_arrived)).ToString("hh\\:mm\\:ss");
我是如何尝试完成此工作的方法是使用一个每30秒调用一次GetMyList方法的计时器。因为该方法将重新查询数据库并返回它检索到的记录,所以它们更新。这很好,直到我在OLV中有超过20行。 200行的每次“刷新”需要4秒才能完成。这是UI没有响应的4秒......
由于我是编程新手,我从未对多线程做过任何事情,但我做了一些阅读并尝试创建解决方案。即使我创建一个新线程来“刷新”OLV对象,它仍然会导致整个表单无响应。
我的问题是,如何在每隔15-30秒刷新一次ObjectListView中的列,而不会导致整个UI无响应? 是否有可能/一个好主意让ObjectListView在后台刷新,然后在它准备好后显示它?
答案 0 :(得分:2)
问题是数据库查询的运行时间,而不是ObjectListView的更新(在ObjectListView中更新200行应该需要大约200ms)。您需要让数据库工作在UI线程之外并进入后台线程。然后,该后台线程可以定期从数据库中获取更新的数据。获得更新的数据后,更新ObjectListView非常快。
然而,多线程是一个深刻的话题,可能会让你感到困惑。有很多事情可能会出错。您最好在UI上使用按钮,用户可以单击该按钮以刷新网格,并同步运行所有内容。一旦同步版本完美运行,然后开始处理更容易出错的多线程版本。
要严格回答您的问题,您可以这样做:
var thread = new Thread(_ => {
while (!_cancelled) {
Thread.Sleep(15 * 1000);
if (!_cancelled) {
var results = QueryDatabase();
this.objectListView1.SetObjects(results);
}
}
});
thread.Start();
_cancelled
是类中的布尔变量,允许您取消查询过程。 QueryDatabase()
是获取新数据的方法。
此示例不处理错误,这是后台线程中的一个重要问题。
另一个问题是大多数UI组件无法从后台线程更新,但是,ObjectListView有一些线程安全的方法,而SetObjects()
就是其中之一,所以你可以像这样调用它。
重复一遍:你真的应该从同步版本开始,只有在对这个版本感到满意时才开始考虑异步。