2

私は非同期プログラミングと WP8 を初めて使用します。これは私の最初のアプリであり、Dispatcher.BeginInvoke(..) に問題があります。

ビュー クラスの背後にある私のコードでは、2 番目のタブの 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);
        }

問題は、これがまだ UI スレッドをブロックしていることです。ここで何が欠けていますか?

編集: アイデアは、XAML で ModelBinded である ViewModel ObservableCollection にデータを非同期にロードすることです。

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

While what you've found works and using Task is very up-to-date, by using Thread.Sleep you're still blocking a thread in the ThreadPool for no good reason.

You can avoid this by using a one-off System.Threading.Timer (see MSDN reference) which will fire on one of the (background) ThreadPool threads. Then use a Dispatcher.BeginInvoke(...) at the end of your timer callback to update the UI.

For example:

        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 に答える