2

我是异步编程和 WP8 的新手,这是我的第一个应用程序,但 Dispatcher.BeginInvoke(..)

在视图类后面的代码中,我试图在第二个选项卡的 Pivot scree 异步中加载数据。

这是我现在拥有的:

public partial class ReminderPivot : PhoneApplicationPage
    {
        #region Reminder Members
        private ReminderViewModel _model;
        private IRepository _repository;
        #endregion Reminder Members

        #region Constructors
        public ReminderPivot()
        {
            InitializeComponent();
            _model = new ReminderViewModel();
            _repository = new LocalStorageRepository();

            LoadData();
            LoadAsyncData();

            this.DataContext = _model;

        }
        #endregion Constructors

        public void LoadData()
        {
            IEnumerable<Reminder> activeList = _repository.GetRemindersByStatusId(2);
            if (activeList != null)
            {
                foreach (var reminder in activeList)
                {
                    _model.ActiveReminders.Add(reminder);
                }
            }
        }
        public void LoadAsyncData()
        {            
            Action action = () =>
            {
                Thread.Sleep(5000);

                IEnumerable<Reminder> inactiveList = _repository.GetRemindersByStatusId(3);
                if (inactiveList != null)
                {
                    _model.InctiveReminders = new System.Collections.ObjectModel.ObservableCollection<Reminder>(inactiveList);
                }
            };

           Dispatcher.BeginInvoke(action);
        }

问题是这仍然阻塞了我的 UI 线程。我在这里想念什么?

编辑:想法是将数据异步加载到 ViewModel ObservableCollection 中,它是 XAML 中的 ModelBinded。

如果我尝试使用 Task.Factory(...) 等在另一个线程上进行异步调用,那么这会崩溃,因为我正在从另一个线程而不是 UI 线程更改绑定。

4

2 回答 2

2

在@PedroLamas 的建议之后,我让它工作,不确定这是最好的方式还是最优雅的方式,但它完成了工作。

我使用 Task.Factory 在另一个线程上完成调用需要时间并使其可等待,最后只需使用 Dispatcher 更新 UI。

public async void LoadAsyncDataWithTask()
        {
            IEnumerable<Reminder> inactiveList = null;
            Action action = () =>
            {
                Thread.Sleep(2000);
                inactiveList = _repository.GetRemindersByStatusId(2);
            };

            await Task.Factory.StartNew(action);

            Action action2 = () =>
            {
                if (inactiveList != null)
                {
                    foreach(var item in inactiveList)
                    {
                        _model.InctiveReminders.Add(item);
                    }
                }
            };

            Dispatcher.BeginInvoke(action2);

        }
于 2013-03-01T20:00:37.957 回答
1

虽然您发现的工作和使用Task是最新的,但通过使用Thread.Sleep您仍然会无缘无故地阻塞 ThreadPool 中的线程。

您可以通过使用一次性System.Threading.Timer请参阅 MSDN 参考)来避免这种情况,它将在(后台)ThreadPool 线程之一上触发。然后Dispatcher.BeginInvoke(...)在计时器回调结束时使用 a 来更新 UI。

例如:

        var timer = new System.Threading.Timer(
            state =>
                {
                    // ... your code to run in background

                    // ... call BeginInvoke() when done
                    Dispatcher.BeginInvoke(() => MessageBox.Show("done"));
                },
            null,
            5000,
            System.Threading.Timeout.Infinite);
于 2013-03-01T20:34:46.653 回答