2017-10-28 7 views
0

私は何か新しい試みをしています。アプリはUWPです。ほとんどのフォームはマスター/ディテールです。すべてのフォームが同じデータインスタンスにアクセスするようなグローバルコレクションが必要です。コレクションに複数のフォームまたはスレッドが同時にアクセスできる状況はありません。C#でファイルから初期化されたシングルトンコレクションを作成しようとしています

私は「所有者」という名前のクラス(モデル)を持っています。

using System; 

namespace MyApp.Models 
{ 
    public class Owner 
    { 
     public Int16 Identifier { get; set; } 
     public String Name { get; set; } 
     public String Description { get; set; } 
     public String Image { get; set; } 
     public Boolean Active { get; set; } 
     public DateTime Modified { get; set; } 
    } 
} 

OwnerXという名前のシングルトンクラスを作成しました。私が苦労しているこのクラスの2つの側面があります。 最初 OwnerXがコレクションIEnumerableの所有者リストである必要があります。 Second LoadFileAsyncメソッドを作成プロセスに組み込む必要があります。フォームコードは、 "OwnersX Owners = OwnersX.Instance();"を使用してコレクションにアクセスします。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Threading.Tasks; 

using MyApp.Models; 
using MyApp.Services; 

namespace MyApp.Collections 
{ 
    public sealed class OwnersX 
    { 
     //Need OwnersX to be an IEnumerable<Owner> 

     private OwnersX() { } 

     private static OwnersX _instance; 

     public static OwnersX Instance() 
     { 
      if (_instance == null) 
      { 
       _instance = new OwnersX(); 
      } 

      return _instance; 
     } 

     // Need this as part of the instance creation process. 

     private static async Task<IEnumerable<Owner>> LoadFileAsync() 
     { 
      String fileContent = await DataFileServicecs.ReadDataFile("Owners.txt", "Data"); 

      StringReader stringReader = new StringReader(fileContent); 

      String header = stringReader.ReadLine(); 
      String line; 

      List<Owner> owners = new List<Owner>(); 

      while ((line = stringReader.ReadLine()) != null) 
      { 
       String[] fields = line.Split('\t'); 

       owners.Add(new Owner 
       { 
        Identifier = Int16.Parse(fields[0]), 
        Name = fields[1].Replace("\"", String.Empty), 
        Description = fields[2].Replace("\"", String.Empty), 
        Image = fields[3], 
        Active = Boolean.Parse(fields[4]), 
        Modified = DateTime.Parse(fields[5]) 
       }); 
      } 

      return owners as IEnumerable<Owner>; 
     } 
    } 
} 

ありがとうございました。

答えて

0

あなたはいくつかのオプション

1を持っている)あなたはLoadFileAsync()がReadDataFileでreturedタスクに.Resultを呼び出すことによって、代わりに同期して行うことができます。私はオプションではないあなたの質問から印象を得ます。

2)あなたは、あなたのシングルトンを非同期アクセス作り、非同期ロジック上向き

public static async Task<OwnersX> Instance() 

3)あなたはここで説明する他のパターンのいずれかを使用して、あなたのシングルトンを初期化することができます渡すことができますを除き http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html

を最初のオプションは、基本的に非同期コードを上向きに押すことです。非同期コードでは、これは一般的に起こり、悪いことではありません。非同期コードを上から下に非同期にすることによって完全に非同期コードを採用しない限り、非同期コードをどこかで呼び出す同期コードを持つことになり、そのポイントがどこにあるかを見つけるだけで済みます。

編集:私はあなたの質問の最初の部分に答えなかった。

あなたはだからここで起こってすごみがたくさんありますIEnumerable<Owner>を実装し、GetEnumerator()

public sealed class OwnersX : IEnumerable<Owner> 
{ 
    private IEnumerable<Owner> owners; 

    public IEnumerator<T> GetEnumerator() 
    { 
     return owners.GetEnumerator(); 
    } 
} 
0

を実装OwnersX持つことができます。静的メンバーを実際には非同期的にロードすることはできません。私はそれのすべての論理に入るつもりはないが、私はあなたの質問にこれに答えようと努力し、それが助けてくれることを願っています。

私がとるソリューションは、シングルトンクラスとロードされたデータを保持するプロパティでイベントを作成することです。私はINotifyPropertyChangedが好きですが、それを観測可能にしていますが、うまくいきます。次に、非シングルトンクラスをViewModelとして作成し、基本的にシングルトンから情報を借用し、ビューがバインドできる変更をリッスンします。

考え方は、シングルトンをインスタンス化してデータを非同期にロードできるということです。 ViewModelは必要に応じて頻繁に作成することができ、まずシングルトンからデータを取得し、変更して更新したデータを待機します。ここに私が意味する例があります。

public class MySingleton : INotifyPropertyChanged 
{ 
    private AutoResetEvent ownersResetEvent = new AutoResetEvent(true); 
    private List<Owner> owners; 
    private static MySingleton instance = new MySingleton(); 
    private MySingleton() => Initialize(); 
    public static MySingleton Instance => instance; 
    public event PropertyChangedEventHandler PropertyChanged; 

    public IEnumerable<Owner> Owners 
    { 
     get 
     { 
      ownersResetEvent.WaitOne(); 
      var tempOwners = owners?.ToList() ?? Enumerable.Empty<Owner>(); 
      ownersResetEvent.Set(); 
      return tempOwners; 
     } 
     private set 
     { 
      ownersResetEvent.WaitOne(); 
      owners = value.ToList(); 
      ownersResetEvent.Set(); 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Owners))); 
     } 
    }  

    private async void Initialize() 
    { 
     Owners = await LoadFileAsync(); 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Owners)); 
    } 
} 

ここでViewModelを追加します。

public class MyViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public MyViewModel() => MySingleton.Instance.PropertyChanged += (s, e) => 
          { 
           if (e.PropertyName == nameof(MySingleton.Owners)) 
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Owners))); 
          }; 

    public IEnumerable<Owner> Owners => MySingleton.Instance.Owners; 
} 

ここで、シングルトンを開始することができます。データがnullでも大したことはありません。とにかく非同期にロードされ、データが設定されると更新されます。必要に応じてViewModelを頻繁に使用することができます。既存のデータを使用し、データが更新されると更新します。コードまたはマークアップを使用してViewModelにバインドできます。あなたは技術的にシングルトンにバインドすることができますが、その中にMVVMのパワーを失うことになります。これは簡単な例です。スタジオなしで私の頭の中で嘲笑された;うまくいけば、あなたはまだアイデアを得ることができます。

また、データのロードと取得をロックする方法は最良の方法ではありませんが、シングルトンで非同期にロードされている場合はデータを同期する必要があることをここで十分に示しています。

関連する問題