2013-01-21 8 views
8

Chcę załadować niektóre dane w konstruktorze ViewModel, ale z powodu asynchronicznej natury WinRT zmuszony jestem użyć metod asynchronicznych. Niestety nie mogę mieć konstruktora asynchronicznego, więc próbuję użyć metody asynchronicznej jako metody synchronicznej. Jestem pewien, że istnieje znacznie lepszy sposób ładowania danych (asynchronizacja) przy ładowaniu aplikacji, ale mój umysł jest teraz pusty.WinRT asynchroniczne ładowanie danych w konstruktorze

Poszukuję sposobu na naprawienie mojej aplikacji za pomocą linii myślenia, którą zamierzam rozwiązać, lub naprawienia tego na stałe za pomocą bardziej odpowiedniej metody.

Kod jest bardzo prosty (nawet brakuje modelu ViewModel) tylko po to, aby zademonstrować problem, z którym się spotykam.

public sealed partial class MainPage : Page 
{ 

    public string Data { get; set; } 

    public DataService _dataService { get; set; } 

    public MainPage() 
    { 
     this.InitializeComponent(); 

     _dataService = new DataService(); 
     var t = _dataService.GetData(); 

     Data = t.Result; 
    } 

    /// <summary> 
    /// Invoked when this page is about to be displayed in a Frame. 
    /// </summary> 
    /// <param name="e">Event data that describes how this page was reached. The Parameter 
    /// property is typically used to configure the page.</param> 
    protected override void OnNavigatedTo(NavigationEventArgs e) 
    { 
    } 


} 

public class DataService 
{ 
    public async Task<string> GetData() 
    { 
     //Force async 
     await Task.Delay(1); 

     return "Hello"; 
    } 
} 

poważaniem

Odpowiedz

9

pisałem niedawno na blogu o async in constructors.

Krótko mówiąc, wolę metodę async fabryczną:

public sealed class MyViewModel : INotifyPropertyChanged 
{ 
    private readonly DataService _service; 

    private MyViewModel(DataService service) 
    { 
    _service = service; 
    } 

    private async Task InitializeAsync() 
    { 
    var result = await _service.GetData(); // async initialization 

    Data = result; // update data-bound properties with the results 
    } 

    // Data triggers INotifyPropertyChanged on write 
    public string Data { get { ... } set { ... } } 

    public static async Task<MyViewModel> CreateAsync() 
    { 
    var ret = new MyViewModel(); 
    await ret.InitializeAsync(); 
    return ret; 
    } 
} 
2

Zmuszanie metod async uruchomić synchronicznie zwykle prowadzi do impasu, więc nie polecam tego. Rzecz w modelach widokowych polega na tym, że zazwyczaj obsługują powiadomienia o zmianach za pośrednictwem zdarzenia INotifyPropertyChangedPropertyChanged, więc nie ma potrzeby natychmiastowego udostępniania wszystkich danych. W rzeczywistości, jeśli twoje dane nie są zakodowane na sztywno - nie powinieneś oczekiwać natychmiastowego ujrzenia danych i najprawdopodobniej chciałbyś pokazać wskaźnik postępu podczas ładowania danych. Tak więc ...

W swoim konstruktorze wywołaj metodę asynchronizacji bez oczekiwania na wynik (ponieważ nie możesz czekać w konstruktorze) oraz w metodzie inicjalizacyjnej, gdy wszystkie dane są dostępne - przypisz ją do właściwości/właściwości, które przegląda powiązania, podnosi zdarzenie PropertyChanged dla tych właściwości i ukrywa wskaźnik postępu, zmieniając właściwość modelu widoku, która kontroluje jej widoczność.

+2

Należy pamiętać o obsłudze błędów. Jeśli 'Task' zwrócony przez metodę inicjowania' async' nigdy nie zostanie zaobserwowany, wszelkie wyjątki będą po cichu połknięte. Dlatego upewnij się, że masz 'try' /' catch' w swoim 'InitializeAsync' lub masz inną metodę' oczekuj' na wynik. –

+0

Oczywiście. Odnosi się to niezależnie od tego, czy wywołanie odbywa się w inicjatorze, czy w innej metodzie, która może prowadzić do złego stanu. –