从任务freez ui返回值

时间:2015-11-26 11:12:24

标签: c# asynchronous

为什么这种结构会冻结ui?我做错了什么?* *

代码:

namespace WpfApplication
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new Data();
        }
    }

    public class Data : INotifyPropertyChanged
    {
        private double result;

        public double Result 
        { 
            get
            {
                return this.result;
            }

            set
            {
                this.result = value;
                this.RaisePropertyChaged("Result");
            }
        }

        public Data()
        {
            AsyncWork();
        }

        public void AsyncWork()
        {
            Task<double> TestTask = Task.Factory.StartNew<double>(() =>
            {
                System.Threading.Thread.Sleep(10000);
                return 0.5;
            });

            result = TestTask.Result;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChaged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }
}

我试图制作像

这样的东西
public Data()
{
    Result = AsyncWork().Result;
}

public async Task<double> AsyncWork()
{
    Task<double> TestTask = Task.Factory.StartNew<double>(() =>
    {
        Task.Delay(1);
        return 0.5;
    });

    return await TestTask;
}

但它也是freez ui。

3 个答案:

答案 0 :(得分:1)

调用Task.Result类似于等待任务结束而不是获取结果。 因为它在你的ctor中是非常有问题的,并且它使得应用程序在数据出现之前不会就绪。

你应该做什么(在我看来)是调用一个任务,将DataContext设置在它的末尾。

这可以防止ui冻结。

答案 1 :(得分:0)

因为result = TestTask.Result;将阻塞调用线程(恰好是ui线程)10秒,直到得到结果。

你可以在没有像这样的async / await的情况下做到这一点;

Task<double> TestTask = Task.Factory.StartNew<double>(() =>
        {
            System.Threading.Thread.Sleep(10000);
            return 0.5;
        });
        TestTask.ContinueWith(x =>
        {
             result = x.Result;
            //do my stuff when its done

        }, System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());

这里我们在你的任务完成时在ui线程上创建一个延续。我真的不认为最好像这样设置datacontext。我建议在将其分配给窗口之前准备好它

答案 2 :(得分:0)

  

为什么这种结构会冻结ui?

因为Result is a blocking call

  

如何在不阻止ui的情况下将值传递给结果?

Task<T>未来。它代表了您可能还没有的价值。如果你还没有它,那么你就无法做任何事情。

您需要做的是将ViewModel初始化为“加载”状态,然后在异步数据到达时更新。我有MSDN article on asynchronous data binding that helps with this