2016-07-25 31 views
0

Ich möchte den ersten Datensatz aus der AboutUs-Tabelle abrufen und als Inhaltslabel anzeigen.Das Objekt wird nicht in der ViewModel-Klasse festgelegt, und die Steuerung wechselt direkt von der Datenzugriffsklasse zu View

Ich habe 4 Klassen in MVVM-Muster erstellt.

Zuerst ist das Modell Klasse AboutUs.cs

[Table("tblAboutUs")] 
    public class AboutUs 
    { 
     [PrimaryKey, AutoIncrement, NotNull] 
     public int IDP { get; set; } 
     public string Content { get; set; } 
    } 

Zweitens ist Data Access Klasse

SQLiteAboutUs.cs

public class SQLiteAboutUs 
    { 
     private static readonly AsyncLock Mutex = new AsyncLock(); 
     private SQLiteAsyncConnection dbConn; 

     public int StatusCode { get; set; } 

     public SQLiteAboutUs(ISQLitePlatform sqlitePlatform, string dbPath) 
     { 

      if (dbConn == null) 
      { 
       var connectionFunc = new Func<SQLiteConnectionWithLock>(() => 
        new SQLiteConnectionWithLock 
        (
         sqlitePlatform, 
         new SQLiteConnectionString(dbPath, storeDateTimeAsTicks: false) 
        )); 

       dbConn = new SQLiteAsyncConnection(connectionFunc); 
       dbConn.CreateTableAsync<Model.AboutUs>(); 
      } 
     } 

     public SQLiteAboutUs() 
     { 
     } 
     public async Task Save(Model.AboutUs content) 
     { 
      using (await Mutex.LockAsync().ConfigureAwait(false)) 
      { 
       StatusCode = 0; 


      await dbConn.InsertAsync(new Model.AboutUs { Content = content.Content }); 
      StatusCode = 1; 
     } 

     //For Get first Row from Table 
     public async Task<Model.AboutUs> GetAllData() 
     { 
      return await dbConn.Table<Model.AboutUs>().Where(x => x.IDP == 1).FirstOrDefaultAsync(); 
     } 
    } 

Dritte Klasse Viewmodel Klasse

AboutUsViewModel.cs

public class AboutUsViewModel 
    { 
     readonly SQLiteAboutUs _db; 
     public string AboutUsContent { get; set; } 

     //public string AboutUs; 
     public AboutUsViewModel() 
     { 
      _db = new SQLiteAboutUs(); 
     } 
     public async void FirstRecord() 
     { 
      Model.AboutUs obj = await _db.GetAllData(); 
      this.AboutUsContent = obj.Content; 
     } 
    } 

Forth ist-Code hinter Datei meiner XAML-Seiten.

AboutUs.xaml.cs

public partial class AboutUs : ContentPage 
    { 
     readonly AboutUsViewModel aboutUsViewModel; 
     public AboutUs() 
     { 
      InitializeComponent(); 

      aboutUsViewModel = new AboutUsViewModel(); 

      aboutUsViewModel.FirstRecord(); 

      lblContent.Text = aboutUsViewModel.AboutUsContent; 
     } 
    } 

ich Debug-Code haben, aber Problem ist in AboutUsViewModel.cs Klasse in Firstrecord Method-Objekt kann auch nicht eingestellt wird, eingestellt werden, deshalb AboutUsContent String-Eigenschaft nicht .

Ich kann nicht herausfinden, warum mein Debugger direkt von GetAllData() -Methode in SQLiteAboutUs.cs zu label.text in Code hinter Datei der Ansicht springt?

+0

Was genau ist hier null? Sind Sie sicher, dass dbConn nicht null ist? Es ist mir oft passiert. Kannst du auch versuchen, eine Variable wie diese zuzuweisen? var result = erwartet dbConn.Table (). Wobei (x => x.IDP == 1) .FirstOrDefaultAsync(); mit einem Versuch fangen vielleicht, nur um sicherzustellen, wenn FirstOrDefaultAsync das Problem macht oder Rückgabetyp macht das Problem? – batmaci

Antwort

1

Willkommen in der wunderbaren Welt der Asynchronität. Ich ermutige Sie, sorgfältig darüber zu lesen, wie warten, funktioniert: How and When to use `async` and `await`

Es ist kein blockierender Anruf. So erstellen Sie die Ansicht AboutUs. Es erstellt das ViewModel AboutUsViewModel. Er fordert

aboutUsViewModel.FirstRecord(); 

Aber warten Sie nicht für den Anruf vollständig zu sein (Dont't vergessen Sie Ihre Firstrecord Funktion als async markiert ...)

So nennt es

Model.AboutUs obj = await _db.GetAllData(); 

Und direkt zurück zum Anrufer wegen des Wartebedieners. Deshalb ist es direkt an

springen
lblContent.Text = aboutUsViewModel.AboutUsContent; 

Was möchten Sie ist so etwas wie

await aboutUsViewModel.FirstRecord(); 

den Anruf warten abgeschlossen sein, bevor die nächste Zeile gehen.Das können Sie natürlich nicht tun, da Sie sich in einem Konstruktor befinden und keinen asynchronen Konstruktor haben können. Und eine Datenbank (oder eigentlich alles, was wahrscheinlich fehlgeschlagen ist) in einem Konstruktor aufzurufen, ist sowieso eine schlechte Übung.

Ich würde Ihnen raten, nur InitializeComponent() im Konstruktor zu lassen und dann etwas wie das OnDataLoaded() - Ereignis Ihrer Ansicht zu verwenden, um Ihren asynchronen Aufruf mit einem await auszuführen.

Ich hoffe, es hilft.

+0

Vielen Dank für Ihre Ermutigung. Ich sehe das eigentliche Problem nicht. Ich kann die Methode OnDataLoaded() in xamarin.forms nicht finden. Also verwende ich die OnAppearing() Methode. –

+0

aber Problem ist, wenn GetAllData-Methode aufrufen, gibt es Fehler "Objektreferenz nicht auf die Instanz des Objekts festgelegt". –

+0

OnAppearing ist wahrscheinlich zu bald, sollten Sie später nach einem anderen Ereignis suchen oder einfach etwas wie eine Initialisierungsfunktion von Hand aufrufen. – Ouarzy