Xamarin.Formsの自己完結型コントロール:「コードを最大限に再利用してください!」。 パート2





そのため、最後の章は、コントロール-サービスなどのアーキテクチャモデルについて検討しました。 このモデルでは、目的のコントロールのViewModelがサブスクライブするイベントを持つビジネスロジックレイヤーにサービスが作成されます。 このアプローチの結果として、インターフェース表示層はデータについて考える必要はなく、インターフェースの事柄のみを扱います。



最後の章では、認可の例を示しました。 最初は、コントロールサービスモデルを使用する理由は明確ではありませんが、より自給自足のコントロールが必要な場合、別のコントロールのViewModelメソッドに直接移動すると、メソッド呼び出しの可能性があるため、あるコントロールを別のコントロールに切り替えると問題が発生する可能性があります-サブスクリプション。



次の例を考慮してください。製品カタログ-製品が追加されるバスケット。 商品のカタログをリスト形式で表示する必要がある場合を考えてみましょう。各製品をバスケットに追加し、バスケットに追加した製品をリストに追加済みとしてマークします。 二重中毒があります。







このモデルでは、コントロールが互いに強く依存しているため、すぐに多くの問題が発生します。 主なものは、バスケットなしでリストコントロールなどの別のアプリケーションで使用することは不可能であり、再利用が主な目標です。 この状況では、コントローラー-サービスモデルの方が適しています。 ViewModelが関連するすべての情報を表示し続けるようにしますが、他のコントローラーとの相互作用の問題をサービスのレベルまで取り上げます。 サービス自体はシングルトンであり、それらのインターフェイスはDIコンテナに追加されます。 したがって、たとえば、バスケットにアイテムを追加するとき、DIコンテナーにバスケットサービスがあるかどうかを一度確認すれば十分です。もしそうであれば、バスケットに追加ボタンを表示してから、バスケットの変更を自分でサブスクライブします。 バスケットサービスについても同様です。 製品はどこからでも、たとえばサイトから追加でき、アプリケーションではバスケットのみを表示できます。 この場合のバスケットは、リストの可用性に依存しません。 また、コントローラー自体を社内の他のすべてのアプリケーションで再利用できるようになりました。



具体的にはコードに目を向けます。 メソッドを持つAPIがあるとします:





既存の方法に基づいて、製品のリストを含むアプリケーションを実装する必要があります。リストヘッダーには、実際の製品数を示すバスケットアイコンがあり、クリックするとバスケット画面が開きます。 バスケットのある画面で、バスケット内の特定の製品の数量を増減したり、完全に空にすることができます。



リストコントロールを作成する前に、APIメソッドの呼び出しのトピックに触れたいと思います。 クライアントアプリケーションを作成するときは、すべての要求がサーバーに到達できるわけではないという事実を常に考慮する必要があります(ある時点で、インターネットが単純に消滅する可能性があります)。 したがって、データへのアクセス層を実装する必要があります。この状況では、最初に要求をキューに入れ、インターネットが表示されたら、要求を再送信できます。 このような状況では、アプリケーションでのクライアントの作業を遅くしないために、データの必要な精度に応じて、キャッシュからデータを表示することができます。 このトピックは、別のシリーズの記事に値します。 Mobile Dimensionでこの状況をどのように解決するか、そのような関心があれば、別のシリーズの記事で説明します。



これらのコントロール自体のインターフェイスを作成する方法、既存のコントロールを拡張する方法、または任意の画面サイズに適応できるようにする方法について、この記事シリーズの私の同僚は語っています。



ビジネスロジックレイヤーは、データの到着方法を知る必要がなく、すべてのサービスがビジネスロジックと同じレベルにある場合、「仮想」データレイヤーにアクセスし、要求に応じて結果を返すことができます(成功したかどうか)成功)。 要求は無期限に処理できることに注意してください。ただし、私の同僚がインターフェイスに関する記事で書いたように、インターフェイスはクリックにすぐに応答する必要があります。 したがって、データレベル(DAL)の要求には、サブスクライブできるイベントがあります。これは、結果が成功した要求と、エラーが発生した失敗した要求のイベントです。 一般的な場合、これは、リクエスト自体、APIへのアクセス方法、そしてもちろんイベント自体が存在するチケット(チケット)です。 したがって、サービスは要求を送信し、これらのイベントにサブスクライブし、結果に応じて、コントローラーがサブスクライブする独自のイベントを呼び出します。 コントローラー自体で、を押すと、サービスのオンデマンド作業の開始(BLL)が初期化され、この時点で負荷インジケーターが表示され、結果イベントがサブスクライブされます。



たとえば、サービスレベルで商品をカートに追加するリクエストを呼び出すコードは次のようになります。



public event Action<string, string> OnProductAddedSuccessfully; public event Action<string> OnProductAddedFailure; public void StartAddingProduct(string sku) { var newProduct = new BasketProduct() { Sku = sku, State = Enums.RequestState.InProgress }; //        _products.Add(newProduct); //   ,  ,    ... var tiket = _basketRepository.AddToBasket(sku); tiket.OnSuccess += (response) => { //  ,           if(response.Data.Succseeded != null && response.Data.Succseeded.Value) { //        ,      (positionId) newProduct.PositionId = response.Data.PositionId; newProduct.State = Enums.RequestState.Succseeded; //  (),     OnProductAddedSuccessfully?.Invoke(newProduct.Sku, newProduct.PositionId); } else { // ,      OnProductAddedFailure?.Invoke(sku); newProduct.State = Enums.RequestState.Failed; } }; //   ,    (     ) var priceTicket = _catalogRepository.GetPriceTicket(sku); priceTicket.OnSuccess += (response) => { if(response.Data != null){ //    newProduct.Price = response.Data.Price; } }; }
      
      





バスケットに商品を追加するサービス方法



例からわかるように、バスケットに何かを追加しようとしたことを示す2つのイベントがあります。 サービスから製品を削除するためのコードは次のようになります。



バスケットのViewModelとリストの両方が、このバスケットサービスのイベントをサブスクライブできるようになりました。 リストの製品はサービスに直接追加され、リストとバスケットの両方がサービスイベントにサブスクライブされるため、必要な変更はすべてのビューで発生します。 変更のサブスクリプションの実装は次のように行われます。



 public int? TotalCount { get { return _basketService.TotalCount; } } public int? TotalPrice { get { return _basketService.TotalPrice; } } void _basketService_OnProductAddedSuccessfully(string sku, string positionId) { var product = Products.ToList().FirstOrDefault(x => x.Sku == sku); product.CountInBasket++; product.IsAddingInProfress = false; product.PositionIds.Add(positionId); //     ,     ,     -  RaizePropertyChanged(nameof(TotalCount), nameof(TotalPrice)); }
      
      





バスケットに商品を追加するサービス方法



インターフェイスによって表示されるViewModelのフィールド自体は通常とは異なり、コードが小さくなり、フィールドの更新自体が管理可能になりました。 これは、このアプローチの追加ボーナスです。 他のViewModelも存在する可能性があります。相互作用をサービスレベルにすると、コードが明確になり、保守が容易になります。







このアプローチの欠点は、デバッグの瞬間そのものです。 突然、サービスまたはデータレベルのどこかでNREまたはその他の例外が発生すると、エラー自体がViewModelレベルで表示されます。 Visual Studioは、実際にはコールバック関数でエラーが発生するため、エラーが発生したレベルを判断しません。 おそらくこれはスタジオ自体のどこかに設定できますが、通常、コールスタックを保存します。これは、エラーの発生元を正確に示しています。



画像画像



画像は、カタログページのサービスから商品を動的に読み込む方法を示しています。 製品をバスケットに追加するときに、バスケットサービスから製品を追加しても、その数量は倉庫内で減少します。これは、残高に関連していません。 すべての同期は、変更の対応するサービスへのViewModelsサブスクリプションのおかげで機能します。



GitHubで例を見ることができます。



この記事では、後で他のプロジェクトで使用できる自給自足の2つのコントロールの相互作用を整理する方法を検討しました。 次の最後の章では、作成されたすべてのコントロールをNuGetライブラリに収集し、他のプロジェクトで再利用する方法について説明します。 また、さまざまなプラットフォーム用のカスタムインターフェイスを作成する問題についても検討します。



All Articles