2016-08-01 35 views
-1

In meinem Xamarin.Forms pcl-Projekt habe ich eine xaml Seite mit label. Ich möchte label nach einigen async task aktualisieren. In meinem ViewModel constructor setze ich Standardtext für meine label. Und erstellen Sie eine async Task Funktion namens SomeTask().So aktualisieren Sie die Benutzeroberfläche nach dem asynchronen Task in viewmodel

Frage 1: Wo kann ich SomeTask() Funktion aufrufen. Nicht in der Lage, async Task Funktion in constructor aufzurufen.

Frage 2: Wie zu aktualisieren Label Text nach async Task SomeTask() Funktion.

Mein Code:

public class MyPageViewModel : ViewModelBase 
    { 
     private String _selectedText; 
     public String SelectedText 
     { 
      get { return _selectedText; } 
      set { 
       if (_selectedText != value) 
       { 
        _selectedText = value;   
       }  
      } 
     } 

     public MyPageViewModel() 
     { 
      _selectedText = "Welcome"; //Default text 
     } 

     private async Task<string> SomeTask() 
     {    
      return await Task.Run(async() => 
      { 
       await Task.Delay(3000); //Dummy task. It will return the status of Task. 
       return "Thanks";   //Update Text  
      });   
     } 
    } 
+0

Sie es aus dem Konstruktor aufrufen können - obwohl man nicht * await * it (small es einen Unterschied.). Anstatt die Aufgabe zurückzugeben, könntest du 'string ret = have appear task ...;/* Text aktualisieren */return ret; '? – Default

+0

Sie können eine asynchrone Factory-Methode erstellen und Ihren Konstruktor als privat definieren. Dann rufen Sie diese Methode auf, um eine Instanz von 'MyPageViewModel' zu erstellen. Innerhalb dieser Methode können Sie' string str = await SomeTask' aufrufen. – user3185569

Antwort

0

Wie wäre es

public MyPageViewModel() 
{ 
    _selectedText = "Welcome"; //Default text 
    SomeTask().ContinueWith(previousTask => SelectedText = previousTask.Result); 
} 
+0

Würde dies die Benutzeroberfläche nicht blockieren? oder zumindest zu unerwarteten Ergebnissen führen, da die Aufgabe nicht erwartet wird und der Aufrufer diese Instanz möglicherweise verwendet, bevor die Aufgabe erledigt ist. – user3185569

+0

Es sollte nicht die Benutzeroberfläche blockieren, weil wir nur Aufgabe erstellen und starten. Wenn wir dem Aufrufer verbieten müssen, SelectedText zu verwenden, bevor der asynchrone Aufruf beendet wird, benötigen wir hier zusätzliche Logik, aber für die aktuelle Frage war dies nicht erforderlich. – tym32167

0

Was ist someTask? d. h. wo sollte es aus welchem ​​Grund aufgerufen werden? Der Kontext ist hier notwendig, um zu wissen, was akzeptabel ist, um die Funktion aufzurufen. Soll die Funktion auf der Seite ausgeführt werden? Kann es später ausgeführt werden? Wie wäre es mit Benutzereingaben?

Ich würde eine statische Methode vorschlagen, dass Sie, wie anrufen:

public static async Task<T> someTask() { 
    Console.WriteLine("Asynchronous method called."); 
} 

Dann Sie diese aus einer Reihe von Orten aufrufen können. Dies hängt ganz davon ab, wo und wann die Methode aufgerufen werden muss. Es könnte unter anderem auf dem Load Event-Handler sein.

0

Sie können eine asynchrone Factory-Methode erstellen und Ihren Konstruktor als privat definieren. Dann rufen Sie diese Methode auf, um eine Instanz von MyPageViewModel zu erstellen. Innerhalb dieser Methode können Sie string str = await SomeTask

public class MyPageViewModel : ViewModelBase 
{ 
    public async MyPageViewModel CreateAsync() 
    { 
     var model = new MyPageViewModel(); 

     SelectedText = await SomeTask(); 

     return model; 
    }   

    private MyPageViewModel() 
    { 
     _selectedText = "Welcome"; //Default text 
    } 

    private Task<string> SomeTask() 
    {    
     return Task.Run(async() => 
     { 
      await Task.Delay(3000); //Dummy task. It will return the status of Task. 
      return "Thanks";   //Update Text  
     });   
     } 
} 

Also statt der Erstellung Ihres Modells wie folgt aufrufen:

var model = new MyPageViewModel(); 

Sie schaffen es wie folgt aus:

var model = await MyPageViewModel.CreateAsync(); 
1

Ich empfehle Ihnen, my NotifyTask type verwenden ; es ist in meinem MSDN article on asynchronous MVVM data binding beschrieben, und ich denke, es ist der einfachste Ansatz:

public class MyPageViewModel : ViewModelBase 
{ 
    private NotifyTask<string> _selectedText; 
    public NotifyTask<string> SelectedText => _selectedText; 

    public MyPageViewModel() 
    { 
    _selectedText = NotifyTask.Create(SomeTask(), "Welcome"); 
    } 

    private async Task<string> SomeTask() 
    {    
    await Task.Delay(3000); 
    return "Thanks"; 
    } 
} 

Ihre Daten dann geändert werden, würde die Bindung an SelectedText.Result zu binden „Welcome“, gefolgt von „Danke“ angezeigt werden soll. Es gibt weitere NotifyTask<T> Eigenschaften für die Datenbindung, wie IsNotCompleted, IsCompleted und ErrorMessage, mit denen Sie Fehlerbedingungen auch über Datenbindung behandeln können.

Wenn Sie wollen diese Art nicht verwenden, können Sie etwas ähnliches auf eigene Faust tun:

public class MyPageViewModel : ViewModelBase 
{ 
    private string _selectedText; 
    public string SelectedText 
    { 
    get { return _selectedText; } 
    set 
    { 
     if (_selectedText != value) 
     { 
     _selectedText = value; 
     RaisePropertyNotifyChanged(); // However you're doing this. 
     } 
    } 
    } 

    public MyPageViewModel() 
    { 
    _selectedText = "Welcome"; 
    var _ = RunSomeTask(); 
    } 

    private async Task RunSomeTask() 
    { 
    try 
    { 
     SelectedText = await SomeTask(); 
    } 
    catch (Exception ex) 
    { 
     // TODO: Handle the exception. 
     // It *must* be handled here, or else it will be silently ignored! 
    } 
    } 

    private async Task<string> SomeTask() 
    {    
    await Task.Delay(3000); 
    return "Thanks"; 
    } 
} 

Der Konstruktor startet eine RunSomeTask Operation und dann ignoriert ausdrücklich seine Ergebnisse (beachten Sie, dass dies bedeutet, dass alle Ausnahmen wird ignoriert).Die RunSomeTask ist verantwortlich für die Ausführung SomeTask und die Behandlung ihrer Ergebnisse (und Ausnahmen). Das Ergebnis wird nur zum Aktualisieren von SelectedText verwendet und Ausnahmen werden behandelt, wie Sie es für Ihre App für angemessen halten.

0

Problem 1:

Verwenden Sie delegieren und Ereignis.

  1. erstellen Delegierter & zugehörige Ereignis:

    • private delegate void MyDelegate();
    • private event MyDelegate myEvent;
  2. der Veranstaltung Abonnieren in Konstruktor:

    • myEvent += async() => await SomeTask();
  3. das Ereignis ausführen, wo immer Sie benötigen:

    • myEvent(); //Note: Check the event for null, before executing

Problem 2:

Wenn auf einem Nicht-UI thread, dann:

  • einig Framework-Klasse Verwenden Sie für UI-Betrieb ausgeführt wird: zum Beispiel - Xamarin bietet Device.BeginInvokeOnMainThread

  • Wir immer Databinding mit dem Etikett verwenden und aktualisieren nur den Wert des Binding Path von Ansichtsmodell, Veranstaltung mit Abonnement.


string _message; 

public string Message 

     { 
      get => _message; 
      set 
      { 
       _message = value; 
      } 
     } 
myEvent +=() => Message = "New Value"; 

<Label Text = "{Binding Message}"/>