2016-06-09 13 views
0

Ich muss einen MessageDialog von einem ViewModel anzeigen, und ich muss eine Aktion mit der Schaltfläche gedrückt verknüpfen.warten DisplayActionSheet (...) gibt sofort null unter Windows zurück

//Dummy implementation 
private string Translate(string element) => element; 

public async Task ShowAsync(string message, Dictionary<string, Action> commands) 
{ 
    var translatedCommands = new Dictionary<string, Action>(); 
    foreach (var element in commands) 
     translatedCommands.Add(Translate(element.Key), element.Value); 

    string selectedElement = null; 

    var buttons = new string[translatedCommands.Keys.Count]; 
    translatedCommands.Keys.CopyTo(buttons, 0); 

    Task<string> Result = null; 
    Device.BeginInvokeOnMainThread(() => 
    { 
     Result = App.Current.MainPage.DisplayActionSheet(message, null, null, buttons); 
    }); 

    selectedElement = await Result; 
    if (selectedElement == null) 
     return; 

    translatedCommands[selectedElement]?.Invoke(); 
} 

Und dann nenne ich es von einem RelayCommand

private async void ExecuteButtonCommand(object p) 
     { 
      int Selectedindex = 0; 

      var messageCommands = new Dictionary<string, Action>() 
      { 
       { "Before 2003",() => 
        { 
         Selectedindex = 1; 
        } 
       }, 
       { "After 2003",() => 
        { 
         Selectedindex = 2; 
        } 
       }, 
      }; 

      await ShowAsync("Select period", messageCommands); 
      var dummy = Selectedindex; 
     } 

, die sehr gut auf Android arbeitet aber unter Windows DisplayActionSheet return null sofort: Zu diesem Zweck habe ich folgendes geschrieben. Ich habe gesehen this so question, aber es funktioniert nicht für mich, denn wenn ich innen Device.BeginInvokeOnMainThread erwarte, wird ShowAsync nicht erwartet.

Antwort

0

Wenn eine Lösung gefunden.

Unter Windows (Phone) DisplayActionSheet sollte nicht im MainThread ausgeführt werden, sondern nur gewartet.

public async Task ShowAsync(string message, Dictionary<string, Action> commands) 
{ 
    var translatedCommands = new Dictionary<string, Action>(); 
    foreach (var element in commands) 
     translatedCommands.Add(Translate(element.Key), element.Value); 

    var buttons = new string[translatedCommands.Keys.Count]; 
    translatedCommands.Keys.CopyTo(buttons, 0); 


    string selectedElement = null; 

    if (Device.OS == TargetPlatform.Android) 
    { 
     Task<string> Result = null; 
     Device.BeginInvokeOnMainThread(() => 
     { 
      Result = App.Current.MainPage.DisplayActionSheet(message, null, null, buttons); 
     }); 

     selectedElement = await Result; 
    } 
    else if (Device.OS == TargetPlatform.Windows || Device.OS == TargetPlatform.WinPhone) 
    { 
     selectedElement = await App.Current.MainPage.DisplayActionSheet(message, null, null, buttons); 
    } 
    else 
     throw new NotImplementedException("Only implemented for Android and Windows (Phone)"); 

    if (selectedElement == null) 
     return; 

    translatedCommands[selectedElement]?.Invoke(); 
} 
1

Meine Vermutung ist, dass auf Android, Action in BeginInvokeOnMainThread sofort ausgeführt wird, und Result ist ein Wert zugewiesen. Unter Windows wird die Action möglicherweise nicht ausgeführt, sobald die Methode BeginInvokeOnMainThread aufgerufen wird.

Sie sollten wirklich keine ergebnisabhängige Aktion für einen anderen Thread ausführen, wie Sie es hier tun. Stattdessen sollten Sie entweder warten, bis Result zugewiesen wird oder den letzten Teil von ShowAsync am Haupt-Thread ausführen.

würde ich die zweite Option empfehlen, da Sie nicht wirklich sind aus dem Konsum Result etwas anderes auseinander zu tun, nachdem sie in dem Haupt-Thread zugeordnet:

Device.BeginInvokeOnMainThread(() => 
{ 
    string selectedElement = await App.Current.MainPage.DisplayActionSheet(message, null, null, buttons); 
    if (selectedElement == null) 
     return; 

    translatedCommands[selectedElement]?.Invoke(); 
}); 

Dies führt jedoch nicht ShowAsync asynchron machen nicht mehr. Um eine asynchrone Version dieses Verfahrens zu machen, extrahieren Sie einfach die bearbeiteten Inhalte von ShowAsync in eine synchrone Show Methode, und erstellen Sie einen Asynchron-Wrapper:

private void Show(string message, Dictionary<string, Action> commands) 
{ 
    // Code in ShowAsync is moved here 
} 

public Task ShowAsync(string message, Dictionary<string, Action> commands) 
{ 
    return Task.Run(() => Show(message, commands)); 
} 
+0

Nein! Es hat nicht funktioniert. Die Show wartet nicht, bis der Nachrichtendialog geschlossen ist, und DisplayActionSheet wartet nicht. Also meine Aktion wird nicht ausgeführt. –