Windows Phone 8 Dispatcher.BeginInvoke无法正常工作

时间:2013-03-01 19:07:54

标签: wpf multithreading asynchronous windows-phone-8 event-dispatching

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

方面遇到了一些问题

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

以下是我现在所拥有的:

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);
        }

问题是这个STILL会阻止我的UI线程。我在这里缺少什么?

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

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

2 个答案:

答案 0 :(得分: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);

        }

答案 1 :(得分:1)

虽然您发现的内容和使用Task的内容非常新,但使用Thread.Sleep仍然无法正确阻止ThreadPool中的某个主题。

您可以使用一对System.Threading.Timersee MSDN reference)来避免这种情况,该一对Dispatcher.BeginInvoke(...)({{3}})会触发其中一个(后台)ThreadPool线程。然后在计时器回调结束时使用 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); 来更新UI。

例如:

{{1}}