2016-06-23 8 views
1

私はVisual Studio 2015でMVVM Lightを使用してWPFアプリケーションを作成しています。コードにわずかなバリエーションを4回繰り返してコード内に繰り返す方法があります。唯一の違いは、ObservableCollectionのタイプが変更されており、データサービスレイヤーで呼び出されたメソッドです。異なるタイプで再利用可能なメソッドを作成する方法

ObservableCollectionStatusViewModelオブジェクトを返します。このオブジェクトは、ComboBoxのデータを格納するために使用されます。 StatusVmComboBoxSelectedItemに結合するために使用され、コレクション内の最初の項目として設定し、「ブランク」です。

private async Task<ObservableCollection<StatusViewModel>> GetStatuses() 
{ 
    var result = new ObservableCollection<StatusViewModel>(); 
    var blank = new StatusViewModel 
    { 
     StatusId = -1, 
     Status = null, 
     Description = null, 
     IsActive = false, 
     CreatedDate = DateTime.Now 
    }; 
    result.Add(blank); 
    var dataService = new MyDataService(); 
    foreach (var c in await dataService.GetStatuses()) 
     result.Add(c); 
    StatusVm = 
     result.SingleOrDefault(c => c.StatusId.Equals(-1)); 
    return result; 
} 

はここStatusVmのためのプライベートフィールドとパブリックプロパティです:

private StatusViewModel _statusVm; 
public StatusViewModel StatusVm 
{ 
    get { return _statusVm; } 
    set 
    { 
     if (Equals(value, _statusVm)) return; 
     _statusVm = value; 
     RaisePropertyChanged(); 
    } 
} 

ここで3回以上、3つ以上のVMタイプを使って上記を繰り返したとします。 GetStatuses()を、異なるビューモデルタイプを取り、データサービスで適切なメソッドを呼び出す方法にするにはどうすればよいですか?ありがとうございました。

更新は:ここでは、種類の別のプロパティとメソッドです:

private MroViewModel_mroVm; 
public MroViewModel MroVm 
{ 
    get { return _mroVm; } 
    set 
    { 
     if (Equals(value, _mroVm)) return; 
     _mroVm = value; 
     RaisePropertyChanged(); 
    } 
} 

private async Task<ObservableCollection<MroViewModel>> GetMro() 
{ 
    var result = new ObservableCollection<MroViewModel>(); 
    var blank = new MroViewModel 
    { 
     StatusId = -1, 
     Status = null, 
     Description = null, 
     IsActive = false, 
     CreatedDate = DateTime.Now 
    }; 
    result.Add(blank); 
    var dataService = new MyDataService(); 
    foreach (var c in await dataService.GetMro()) 
     result.Add(c); 
    MroVm = 
     result.SingleOrDefault(c => c.StatusId.Equals(-1)); 
    return result; 
} 
+1

'GetStatuses()'を一般化する際の2つの問題は、 'blank'の初期化と' GetStatuses() 'Webメソッドの呼び出しです。前者は、ビューモデルを適切に初期化する必要があるか、実用的でない場合は、空のインスタンスを返すインタフェースを実装するように要求することによって処理します。次に、呼び出し側がWebメソッドを呼び出すラムダを渡すか、ViewModelに 'CallWebMethod()'メソッドを提供する必要があるかもしれません。または、私は上記のインターフェイスに追加します。それを 'IWebMethodRetrievable'などと呼びます。インターフェイスの考え方が私の成長しています。 –

+0

ありがとう、@エイドパルケッツ。 Webメソッド呼び出しのラムダの例は何ですか? – Alex

+2

ジェネリックメソッドについてlile private asyncタスク>すべてのタイプが同じプロパティを持つ場合、GetStatuses(T t)? – Ian

答えて

3

あなたは一般的な性質のためのインタフェースを作成します。

internal interface IStatusViewModel { 
     int StatusId { get; set; } 
     string Status { get; set; } 
     string Description { get; set; } 
     bool IsActive { get; set; } 
     DateTime CreatedDate { get; set; } 
} 

あなたは方法は、静的作成し、古いステータスを取得するために、適切なメソッドを呼び出しますサービス機能を渡す

internal class MroViewModel : IStatusViewModel { 
     public int StatusId { get; set; } 
     public string Status { get; set; } 
     public string Description { get; set; } 
     public bool IsActive { get; set; } 
     public DateTime CreatedDate { get; set; } 
} 

のステータスを取得するために必要なクラスのインターフェイスを実装します。

public static async Task<ObservableCollection<T>> GetStatuses<T>(
    Func<MyDataService, Task<IEnumerable<T>>> retrieveStatusesAction) 
    where T : IStatusViewModel, new() 
{ 
    var result = new ObservableCollection<T>(); 
    var blank = new T 
    { 
     StatusId = -1, 
     Status = null, 
     Description = null, 
     IsActive = false, 
     CreatedDate = DateTime.Now 
    }; 
    result.Add(blank); 

    var dataService = new MyDataService(); 
    foreach (var c in await retrieveStatusesAction(dataService)) 
     result.Add(c); 

    // TODO Implement Expression<Func<TSource, TResult>> projection for assigning to VM 
    StatusVm = result.SingleOrDefault(c => c.StatusId.Equals(-1)); 

    return result; 
} 

あなたがそのようにように、このメソッドを呼び出します。

GetStatuses((service) => service.GetMro()); 

私はこれをテストしていないとStatusVmは表現のコンパイルを使用して割り当てる必要があります。私は今それを行う方法を見ていきますが、そのアイデアはそこにあります。

public static async Task<ObservableCollection<T>> GetStatuses<T, TContainer>(
     TContainer instance, 
     Expression<Func<TContainer, T>> viewModelProjection, 
     Func<MyDataService, Task<IEnumerable<T>>> retrieveStatusesAction) 
     where T : IStatusViewModel, new() 
    { 
     var result = new ObservableCollection<T>(); 
     var blank = new T 
     { 
      StatusId = -1, 
      Status = null, 
      Description = null, 
      IsActive = false, 
      CreatedDate = DateTime.Now 
     }; 
     result.Add(blank); 

     var dataService = new MyDataService(); 
     foreach (var c in await retrieveStatusesAction(dataService)) 
      result.Add(c); 

     var vmStatus = result.SingleOrDefault(c => c.StatusId.Equals(-1)); 

     // Warning: Check casted values, this is unsafe 
     var vm = (PropertyInfo)((MemberExpression)viewModelProjection.Body).Member; 
     vm.SetValue(instance, vmStatus, null); 

     return result; 
    } 

あなたは、このようにメソッドを呼び出します:

- - EDIT VMの割り当てのために、このような

何か Property selector Expression<Func<T>>. How to get/set value to selected property

:発現と財産割り当てるための

表現に精通して、私は説明します。 最初の引数は、ビューモデルインスタンスが配置されているオブジェクトです。 2番目の引数は、変更が必要なビューモデルに対応するそのオブジェクトからプロパティを選択します。最後の引数は、サービスを受け取り、ステータスを取得する適切なメソッドを返す関数です。これは、C++の関数へのポインタに似ています。

これはコンパイルされますが、期待どおりに動作するかどうかはわかりません。そうすべき。何か問題があれば、コメントに書き留めてください。

1

あなたは、インターフェイスを定義し、以下の(私はスキップ非同期は/簡単にするために待っています)のように、StrategyFactoryのコンボを試みることができる:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Starting"); 
     var mainVm = new MainViewModel(); 
     mainVm.GetStatuses(); 
     mainVm.GetMro(); 

     Console.WriteLine("Status: {0} {1}", mainVm.StatusVm.Name, mainVm.StatusVm.CreateDate); 
     Console.WriteLine("MroVm: {0} {1}", mainVm.MroVm.Name, mainVm.MroVm.CreateDate); 
    } 
} 

public class MainViewModel 
{ 
    public StatusViewModel StatusVm { get; set; } 
    public MroViewModel MroVm { get; set; } 

    public void GetStatuses() 
    { 
     var result = Get(VmKind.Status); 
     StatusVm = result.SingleOrDefault(c => c.StatusId.Equals(-1)) as StatusViewModel; 
    } 
    public void GetMro() 
    { 
     var result = Get(VmKind.Mro); 
     MroVm = result.SingleOrDefault(c => c.StatusId.Equals(-1)) as MroViewModel; 
    } 

    public IEnumerable<IVm> Get(VmKind vmKind) 
    { 
     var dataService = new MyDataService(); 
     return dataService.Get(vmKind); 
    } 


} 

public interface IVm 
{ 
    int StatusId { get; set; } 
    DateTime CreateDate { get; set; } 
    string Name { get; } 
} 

public class StatusViewModel : IVm 
{ 
    public DateTime CreateDate { get; set; } 
    public int StatusId { get; set; } 
    public string Name { get { return "StatusViewModel"; } } 
} 

public class MroViewModel : IVm 
{ 
    public DateTime CreateDate { get; set; } 
    public int StatusId { get; set; } 
    public string Name { get { return "MroViewModel"; } } 
} 

public enum VmKind {Status, Mro } 

#region Strategy 

public interface IDataGetter 
{ 
    IEnumerable<IVm> Get(VmKind vmKind); 
} 

public class MyDataService : IDataGetter { 
    public IEnumerable<IVm> Get(VmKind vmKind) 
    { 
     switch (vmKind) 
     { 
      case VmKind.Status: 
       return GetStatuses(); 
       //break; 
      case VmKind.Mro: 
       return GetMro(); 
       //break; 
      default: 
       throw new ArgumentException("Unknown VM type"); 
     } 
    } 

    private IEnumerable<IVm> GetMro() 
    { 
     return new List<MroViewModel> { 
      new MroViewModel { StatusId = -1, CreateDate = DateTime.Now }, 
      new MroViewModel { StatusId = 2, CreateDate = DateTime.Now } 
     }; 
    } 

    private IEnumerable<StatusViewModel> GetStatuses() 
    { 
     return new List<StatusViewModel> { 
      new StatusViewModel { StatusId = -1, CreateDate = DateTime.Now }, 
      new StatusViewModel { StatusId = 2, CreateDate = DateTime.Now } 
     }; 
    } 
} 
#endregion 

#region Factory 
public class VmFactory { 
    static IVm Create(VmKind vmKind) 
    { 
     IVm result = null; 
     switch (vmKind) 
     { 
      case VmKind.Status: 
       result = new StatusViewModel { StatusId = -1, CreateDate = DateTime.Now }; 
       break; 
      case VmKind.Mro: 
       result = new MroViewModel { StatusId = -1, CreateDate = DateTime.Now }; 
       break; 
      default: 
       throw new ArgumentException("Unknown VM type"); 
       //break; 
     } 
     return result; 
    } 
} 
#endregion 

が、私は実際にここに工場を使用していないが、あなたは可能性がVMを簡単に作成できるようにします。

関連する問題