【发布时间】:2014-08-28 18:57:42
【问题描述】:
我是新人,使用 Task.Run() 以及 async 和 await 以使 UI 响应更快,所以我可能没有正确实现某些东西。
我已经阅读了 Stephen Cleary 关于使用 AsyncCommands 的精彩文章,并使用了他来自 Patterns for Asynchronous MVVM Applications: Commands 的代码作为拥有响应式 UI 的基础,但是当我运行代码时,它似乎仍然冻结(我无法移动窗口或与其他按钮交互,直到功能完全完成。
我正在尝试执行通常需要 5-10 秒才能返回的搜索。下面是创建AsyncCommand 的代码以及函数的作用。
代码:
public ICommand SearchCommand
{
get
{
if (_SearchCommand == null)
{
_SearchCommand = AsyncCommand.Create(() => Search());
}
return _SearchCommand;
}
}
private async Task Search()
{
IEnumerable<PIPoint> points = await SearchAsync(_CurrentPIServer, NameSearch, PointSourceSearch).ConfigureAwait(false);
SearchResults.Clear();
foreach (PIPoint point in points)
{
SearchResults.Add(point.Name);
}
}
private async Task<IEnumerable<PIPoint>> SearchAsync(string Server, string NameSearch, string PointSourceSearch)
{
{
PIServers KnownServers = new PIServers();
PIServer server = KnownServers[Server];
server.Connect();
return await Task.Run<IEnumerable<PIPoint>>(()=>PIPoint.FindPIPoints(server, NameSearch, PointSourceSearch)).ConfigureAwait(false);
}
}
我认为问题在于我如何将长时间运行的函数推送到线程上,并且它没有脱离 UI 线程,或者我对 Tasks 和 async/await 如何完全关闭的理解。
编辑 1: 按照斯蒂芬的回答,我更新了功能,但我没有看到 UI 响应能力有任何变化。我创建了第二个命令来执行相同的操作,并且在任何一种情况下我都会从 UI 中得到相同的响应。现在的代码如下所示
代码:
public ICommand SearchCommand
{
get
{
if (_SearchCommand == null)
{
_SearchCommand = AsyncCommand.Create(async () =>
{
var results = await Task.Run(()=>Search(_CurrentPIServer, NameSearch, PointSourceSearch));
SearchResults = new ObservableCollection<string>(results.Select(x => x.Name));
});
}
return _SearchCommand;
}
}
public ICommand SearchCommand2
{
get
{
if (_SearchCommand2 == null)
{
_SearchCommand2 = new RelayCommand(() =>
{
var results = Search(_CurrentPIServer, NameSearch, PointSourceSearch);
SearchResults = new ObservableCollection<string>(results.Select(x => x.Name));
}
,()=> true);
}
return _SearchCommand2;
}
}
private IEnumerable<PIPoint> Search(string Server, string NameSearch, string PointSourceSearch)
{
PIServers KnownServers = new PIServers();
PIServer server = KnownServers[Server];
server.Connect();
return PIPoint.FindPIPoints(server, NameSearch, PointSourceSearch);
}
我一定错过了什么,但我现在不确定是什么。
编辑 2:
在对花费了这么长时间的原因进行了更多调查之后,发现结果后对列表的迭代是挂起该过程的原因。通过简单地更改 Search 函数返回的内容并让它已经在对象列表上迭代,可以让 UI 保持响应。我将斯蒂芬的回答标记为正确,因为它处理了我的主要问题,即正确地将工作移出 UI 线程,我只是没有移走实际耗时的工作。
【问题讨论】:
-
你的
server.Connect()方法在做什么? -
@yuval-itzchakov 说对象和方法是由第三方提供的,但是在调试中它是一个快速的操作。
.FindPIPoints方法是阻止程序响应的缓慢操作。 -
除了这个方法还有其他运行吗?任何长时间运行的 UI 操作?
-
@YuvalItzchakov 这是唯一运行的方法。单击调用命令之前的整个程序只是在等待用户。一旦用户单击按钮,我只希望 UI 在等待响应时能够响应。
标签: c# wpf multithreading asynchronous mvvm