【问题标题】:await MessagingCenter in Xamarin Forms在 Xamarin 表单中等待消息中心
【发布时间】:2016-05-29 18:17:01
【问题描述】:

我尝试使用 ViewModel 中的 MessagingCenter 实现 MVVM。 我收到以下错误,因为多个线程收到相同的消息“ClearStackLayout”并且不等待回调的结束:

索引超出了数组的范围。

这是我的查看代码:

public partial class LibraryChoicePage : DefaultBackgroundPage {

        private Object thisLock = new Object();

        public LibraryChoicePage() {
            InitializeComponent();

            /* ClearStackLayout */
            MessagingCenter.Subscribe<LibraryChoiceViewModel>(this, "ClearStackLayout", (sender) => {
                lock (thisLock) {
                    this._choices.Children.Clear();
                }
            });

            /* AddToStackLayout */
            MessagingCenter.Subscribe<LibraryChoiceViewModel, View>(this, "AddToStackLayout", (sender, arg) => {
                lock (thisLock) {
                    this._choices.Children.Add(arg);
                }
            });

        }

    }

【问题讨论】:

    标签: c# xamarin xamarin.forms


    【解决方案1】:

    第一件事是总是在 UI 线程上调用 StackLayout.Children.Clear|AddiOS 不喜欢从主 UI 线程中移除 UIView 子视图,并且会抛出异常,甚至可能导致原生崩溃

    这就是我将serialized 消息呼叫的方式:

    var semaphone = new SemaphoreSlim(1);
    MessagingCenter.Subscribe<object>(this, "ClearStackLayout",  async (sender) =>
    {
        await semaphone.WaitAsync();
        Device.BeginInvokeOnMainThread(() =>
        {
            _choices.Children.Clear();
        });
        semaphone.Release();
    });
    
    MessagingCenter.Subscribe<object, View>(this, "AddToStackLayout", async (sender, arg) =>
    {
        await semaphone.WaitAsync();
        Device.BeginInvokeOnMainThread(() =>
        {
            _choices.Children.Add(arg);
        });
        semaphone.Release();
    });
    

    注意:try/finally 应该包装 SemaphoreSlim.Releasecatch 以执行添加/清除失败所需的任何恢复器代码。

    UIUnit 并行测试方法:

    Random random = new Random();
    var tasks = new List<Task>();
    for (int i = 0; i < 50; i++)
    {
        if (random.NextDouble() > .1)
            tasks.Add(Task.Factory.StartNew(() => { AddLayout(); }));
        else
            tasks.Add(Task.Factory.StartNew(() => { ClearLayout(); }));
    }
    var completed = Task.Factory.ContinueWhenAll(tasks.ToArray(), (messagecenterTasks) => { 
        foreach (var task in messagecenterTasks)
        {
            if (task.Status == TaskStatus.Faulted)
            {
                D.WriteLine("Faulted:");
                D.WriteLine($"  {task.Exception.Message}");
            }
        }
    }).Wait(1000);
    if (!completed)
        D.WriteLine("Some tasks did not complete in time allocated");
    

    注意:AddLayout/ClearLayout 是 MessageCenter.SendAddToStackLayoutClearStackLayout 的方法包装器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-24
      • 2021-04-23
      • 2020-07-10
      • 2018-03-10
      • 1970-01-01
      • 1970-01-01
      • 2011-03-09
      • 1970-01-01
      相关资源
      最近更新 更多