2016-05-27 10 views
0

Ich habe versucht, MVVM mit MessagingCenter von meinem ViewModel zu implementieren. erhielt ich den folgenden Fehler, weil Multiples Threads die gleiche Meldung „ClearStackLayout“ erhalten und nicht das Ende eines jeden anderen Rückruf warten:warten auf MessagingCenter in Xamarin Forms

Index außerhalb der Grenzen des Arrays war.

Hier ist meine Ansicht Code:

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

     } 

    } 

Antwort

3

Die Nummer eins ist immer Aufruf StackLayout.Children.Clear|Add auf dem UI-Thread. iOS mag nicht, wenn UIView Subviews abseits der Haupt UI-Thread zu entfernen und Ausnahmen auslösen und nativer stürzt sogar dazu führen kann

Dies ist, wie ich die Messaging-Anrufe 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(); 
}); 

Hinweis: try/finally sollte die SemaphoreSlim.Release und eine catch wickeln, um jeden Wiederherstellungscode auszuführen, der von Add/Clear-Fehlern benötigt wird.

UIUnit Paralleltest Methode:

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

Anmerkung: AddLayout/ClearLayout sind Verfahren für die Umhüllungen von MessageCenter.SendAddToStackLayout und ClearStackLayout.