Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#和任务-UI线程挂起-预异步/等待关键字_C#_Asynchronous_Task Parallel Library_Async Await - Fatal编程技术网

C#和任务-UI线程挂起-预异步/等待关键字

C#和任务-UI线程挂起-预异步/等待关键字,c#,asynchronous,task-parallel-library,async-await,C#,Asynchronous,Task Parallel Library,Async Await,我试图理解,当我无法访问用于检索数据的客户机库时,异步获取一组数据的正确代码是什么。我指定了一个端点和一个日期范围,我应该检索一个播放列表。在Start()调用之后,我现在拥有的东西再也不会回来了。注意:这是在WinForm中运行的。我试图更好地理解任务,而不仅仅是想跳转到等待者或后台工作人员。我知道我在什么地方迷路了 private void GoButtonClick(object sender, EventArgs e) { string baseUrl =

我试图理解,当我无法访问用于检索数据的客户机库时,异步获取一组数据的正确代码是什么。我指定了一个端点和一个日期范围,我应该检索一个播放列表。在Start()调用之后,我现在拥有的东西再也不会回来了。注意:这是在WinForm中运行的。我试图更好地理解任务,而不仅仅是想跳转到等待者或后台工作人员。我知道我在什么地方迷路了

    private void GoButtonClick(object sender, EventArgs e)
    {
        string baseUrl = "http://someserver/api";
        var startDateTime = this._startDateTimePicker.Value;
        var endDateTime = this._endDateTimePicker.Value;
        _getPlaylistsFunc = delegate()
            {
                var client = new PlaylistExportClient(baseUrl);
                return client.GetPlaylistsByDateRange(startDateTime, endDateTime).ToList();
            };
        var task = new Task<List<Playlist>>(_getPlaylistsFunc);
        task.ContinueWith((t) => DisplayPlaylists(t.Result));
        task.Start();
    }

    private void DisplayPlaylists(List<Playlist> playlists)
    {
        _queueDataGridView.DataSource = playlists;
    }

看起来您正在为后台线程中的UI控件的属性赋值。这通常是个坏消息。当您这样做时,WPF通常会抛出一个异常,但不确定WinForms

在后台线程中捕获数据,但在将其分配给UI控件之前切换回主UI线程。尝试使用以下方法将数据发布到UI线程

    var uiSync = SynchronizationContext.Current;
    Task.Factory.StartNew(() =>
        {
            var client = new PlaylistExportClient(baseUrl);
            var list = client.GetPlaylistsByDateRange(...).ToList();
            uiSync.Post(() => _queueDataGridView.DataSource = list, null);
        },token,TaskCreationOptions.None,context);

我建议您使用基于任务的异步模式。这很简单:

private async void GoButtonClick(object sender, EventArgs e)
{
    string baseUrl = "http://someserver/api";
    var startDateTime = this._startDateTimePicker.Value;
    var endDateTime = this._endDateTimePicker.Value;
    var playlists = await Task.Run(() =>
    {
        var client = new PlaylistExportClient(baseUrl);
        return client.GetPlaylistsByDateRange(startDateTime, endDateTime).ToList();
    });
    _queueDataGridView.DataSource = playlists;
}
请注意,这将阻止线程池线程;如果可以将库修改为具有
getplaylisbydaterangeasync
方法,则可以提高效率

编辑:如果您被困在.NET 4.0上,您可以安装以获得完整的
async
/
wait
功能。如果出于某种无法解释的原因,您仍然不能使用
async
/
wait
,那么您可以这样做:

private void GoButtonClick(object sender, EventArgs e)
{
    string baseUrl = "http://someserver/api";
    var startDateTime = this._startDateTimePicker.Value;
    var endDateTime = this._endDateTimePicker.Value;
    var context = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Run(() =>
    {
        var client = new PlaylistExportClient(baseUrl);
        return client.GetPlaylistsByDateRange(startDateTime, endDateTime).ToList();
    }).ContinueWith(t =>
    {
        _queueDataGridView.DataSource = t.Result;
    }, context);
}

但是,请注意,这种方法的错误处理更为复杂。

如果在
getplaylisbydaterange
中放置断点,您是否看到它实际上被调用了?您需要将同步上下文传递给延续,以便它在UI线程而不是另一个线程池线程中运行。除此之外,我在这里没有看到任何真正的错误。您的更新在UI线程上运行所有任务。只有第二个应该在那里运行。我明白-我想。Post()不是我的context.Woops上的方法。好的,您所调用的上下文变量实际上是一个调度程序。我将用代码更新我的答案以获取同步上下文。看起来这非常接近。谢谢。我正在计算Post()lambda参数。现在IDE正在报告匿名函数上的不正确签名。仍然锁定我的WinForm。我所做的唯一更改是在Post()中添加(对象状态)调用。我确实在尝试了解如何在异步前/等待时完成此操作。但也有很好的信息。我根据问题中指定的
async wait
标记给出了此答案。如果您想要异步前的
async
答案,请选择
Task.ContinueWith
(与
TaskScheduler.FromCurrentSynchronizationContext
)或者
BackgroundWorker
就足够了。
async
代码比这两个选项都干净得多。使用
ContinueWith
方法查看更新的代码答案。+1.更新的代码正是海报想要的,除了
Task.Run
需要是
Task.Factory.StartNew
运行没有存在于.NET 4.0中。是的,.NET 4.0中没有。即使在安装之后,它仍然不可用。如果有人坚持使用.NET 4.0,那么他通常坚持使用VS2010,您对他的引用是无用的
private void GoButtonClick(object sender, EventArgs e)
{
    string baseUrl = "http://someserver/api";
    var startDateTime = this._startDateTimePicker.Value;
    var endDateTime = this._endDateTimePicker.Value;
    var context = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Run(() =>
    {
        var client = new PlaylistExportClient(baseUrl);
        return client.GetPlaylistsByDateRange(startDateTime, endDateTime).ToList();
    }).ContinueWith(t =>
    {
        _queueDataGridView.DataSource = t.Result;
    }, context);
}