2016-05-27 13 views
0

私はViewModelからMessagingCenterを使用してMVVMを実装しようとしました。 倍数のスレッドが同じメッセージ「ClearStackLayout」を受信し、互いのコールバックの終了を待っていないので、私は次のエラーを取得:XamarinフォームでMessagingCenterを待機します

インデックスが配列の範囲外でした。ここで

私のビューのコードは次のとおりです。

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

     } 

    } 

答えて

3

ナンバーワンの事はUIスレッド上常にコールStackLayout.Children.Clear|Addです。 iOSのは、メイン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/finallySemaphoreSlim.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はAddToStackLayoutMessageCenter.SendClearStackLayout方法ラッパーです。

関連する問題