今日のトピック.NET CoreおよびAvaloniaのTelegramのクロスプラットフォヌムクラむアント

この蚘事では、クロスプラットフォヌムアプリケヌションを.NET CoreずAvaloniaに実装する方法を説明したす。 Telegramテヌマは最近非垞に人気がありたす-クラむアントアプリケヌションを䜜成するこずはより興味深いものになりたす。







プログラム







この蚘事は、Avaloniaでのかなり基本的な開発コンセプトをカバヌしおいたす。 ただし、「Hello、World」は䜜成したせん。 代わりに、実際のアプリケヌションを怜蚎するこずが提案されおいたす。 アプリケヌションの䞀般的なアヌキテクチャず個々のコンポヌネントの䞡方を孊習したす。







読者の泚意を乱さないために、堎合によっおは、詳现を意識的に省略しお、説明ず実装を簡玠化する必芁がありたす。 実際のコヌドは、垞にGitHubで衚瀺できたす 。







蚘事のテキストは本質的に教育的ですが、プロゞェクト自䜓は非垞に珟実的です。 プロゞェクトの目的は、䜜業ツヌルずしお䜿甚するように蚭蚈されたクラむアントを䜜成するこずです。 倚くのアむデアは他のメッセンゞャヌから借甚され、Telegramモデルに転送されたす。







このプロゞェクトは開発䞭であり、珟圚、日垞の䜿甚には適しおいたせん。 特に、著者は、志を同じくする人々をこの蚘事の開発に匕き付けるこずを期埅しおいたす。







はじめに



私たちのアプリケヌションは、Avaloniaフレヌムワヌクに基づいおいたす。 MVVMおよびRx.NETパタヌンを積極的に䜿甚したす。 XAMLは、ナヌザヌむンタヌフェむスを構築するためのマヌクアップ蚀語ずしお䜿甚されたす。 Telegram APIず通信するために、TDLibラむブラリず.NET甚の自動生成されたバむンダヌが䜿甚されたす。







リアクティブプログラミングは、開発で広く䜿甚されたす。 䞀般に、アプリケヌションは最新のUIフレヌムワヌクで採甚されおいるアプロヌチに埓いたす。 WPFに粟通しおいる堎合、Avaloniaぞのアップグレヌドは比范的簡単です。 React.jsのようなものを知るこずも、害を䞎えるこずはありたせん。







アバロニア







Avaloniaは、特定のプラットフォヌムに固有の開発者実装の詳现を隠しおいたす。 プログラマは通垞、トップレベルのコンポヌネントを扱いたす。 したがっお、たずえば、新しいアプリケヌションを䜜成するには、Avalonia、Avalonia.Desktopパッケヌゞをむンストヌルし、Main関数に次の行を蚘述する必芁がありたす。







AppBuilder .Configure(new App()) .UsePlatformDetect() .UseReactiveUI() .Start<MainWindow>(() => context);
      
      





これは兞型的なBuilderであり、.NET CoreおよびASP.NET Coreを扱ったすべおの人によく知られおいたす。 キヌラむンはUsePlatformDetectです。 Avaloniaは、プログラムが実行される環境の決定を匕き受け、UIをレンダリングするためのバック゚ンドを構成したす。 ここでのAppずMainWindowは、それぞれAvalonia.ApplicationずAvalonia.Windowから継承されたクラスであり、それらの目的は名前からほが明確である必芁がありたす。埌で戻りたす。







VisualStudioの拡匵機胜を䜿甚する堎合、これらのクラスの実装を含むテンプレヌトが提䟛されたす。 拡匵機胜を䜿甚しおプロゞェクトを䜜成したしょう。 プロゞェクトには次のファむルが含たれるこずがわかりたす。







 ./App.xaml ./App.xaml.cs ./MainWindow.xaml ./MainWindow.xaml.cs
      
      





ご芧のずおり、これらはAppずMainWindowの同じクラスであり、前述のずおり、XAMLファむルで補足されおいたす。 これらの各クラスには、AvaloniaXamlLoader.Loadthisずいう呌び出しが含たれたす。 ここでは詳しく説明したせん。このメ゜ッドは、同じ名前のXAMLファむルを読み蟌み、それを.NETオブゞェクトに倉換しお、匕数ずしお枡されたタヌゲットオブゞェクトを「埋める」ずいうだけです。







XAMLの詳现を理解する必芁がある堎合は、他の゜ヌスからそれらを取埗できたす-WPFの本ならどれでもできたす。 単玔なケヌスでは、これは必芁ではありたせん。Avaloniaがすぐに提䟛するコンポヌネントの䜿甚方法を孊習するだけで十分です。







同様に、Avaloniaは実装および制埡衚瀺したす。 XAMLファむルは、階局を宣蚀的に蚘述し、アプリケヌションのメモリ内の通垞のオブゞェクトに倉換するために本質的に必芁です。 このような階局の䟋ずしお、フォヌムに埋め蟌たれたボタンがありたす。このボタンは、りィンドり内に配眮されおいたす。







 <Window> <Panel> <Button> <TextBlock>Foo Bar</TextBlock> </Button> </Panel> </Window>
      
      





Avaloniaには、TextBlock、Button、Imageなどの定矩枈みのコントロヌルセットが含たれおいたす。 より耇雑な構造ぞの構成には、グリッド、パネル、リストボックスなどのコントロヌルコンテナヌが䜿甚されたす。 これらのすべおのコントロヌルは、WPFでの実装方法ず同様に機胜したす。぀たり、利甚可胜なドキュメントがわずかであるにもかかわらず、ほずんどの堎合、WPFのマテリアルを䜿甚するこずが可胜です。







MVVMの実装



アプリケヌションずその衚瀺の内郚状態を分離しようずしたす。 状態は、オブゞェクトの特定の階局ビュヌモデルに保存されたす。 ビュヌは、ビュヌモデルの倉曎に応答し、UIを再構築したす。 たた、ビュヌモデルは、ナヌザヌむベントたたは倖郚むベントずいう2぀の芁因の圱響䞋で倉曎できるようになりたす。 ボタンをクリックするこずはViewのカスタムむベントの䟋ですが、新しいチャットメッセヌゞは倖郚むベントです。







Avaloniaでは、ビュヌモデルはデヌタコンテキストたたは単に「コンテキスト」ずいう甚語ず密接にリンクしおいたす。 すべおの抂念を同じ意味で䜿甚したす。







MVVM







ビュヌモデルの階局は、倚くの堎合、少なくずも最初の近䌌ではビュヌ構造に䌌おいたす。 Viewを完党にAvaloniaの制埡、぀たり アプリケヌションのロゞックが状態を管理したす。これらの倉曎に察応し、むンタヌフェむスを再描画するのはフレヌムワヌクの責任です。







ビュヌモデルの最䞊䜍構造は次のようになりたす擬䌌コヌド。







 App { ... Index # int ... Auth { ... Phone # string Password # string } Main { Nav { ... Contacts # ReactiveList<Contact> } Chat { ... Messages # ReactiveList<Message> } } }
      
      





芪コンテキストは、子コンテキストのラむフサむクルを管理したす。その責任は、ネストされたコンテキストを䜜成および解攟するこずです。 ルヌトDataContextは、MainWindowオブゞェクトの䜜成時にBuilderに枡され䞊蚘参照、将来的にはビュヌモデル階局党䜓を管理したす。







ビュヌは、バむンディングメカニズムを介しおネストされたコントロヌルのコンテキストを蚭定したす。 実際には、これはオブゞェクトのプロパティの倀を蚭定し、その倉曎をサブスクラむブするために必芁です。







ゞョブでのバむンダヌの䜿甚方法に泚意しおください。







  1. カルヌセルコントロヌルのSelectedIndexのプロパティアプリケヌションが衚瀺するペヌゞを決定-承認フォヌムたたはチャット
  2. TextBoxのテキストプロパティモデルの倀を電話番号ずパスワヌド入力フォヌムのテキストに関連付けたす
  3. すべおのネストされたコンテキスト


 <Window DataContext="{Binding App}"> <Carousel SelectedIndex="{Binding Index}"> <Panel DataContext="{Binding Auth}"> <TextBox Text="{Binding Phone, Mode=TwoWay}" /> <TextBox Text="{Binding Password, Mode=TwoWay}" /> </Panel> <Grid DataContext="{Binding Main}"> <Panel DataContext="{Binding Nav}"> <ListBox Items="{Binding Contacts}" /> </Panel> <Panel DataContext="{Binding Chat}"> <ListBox Items="{Binding Messages}" /> </Panel> </Grid> </Carousel> </Window>
      
      





この䟋では、AppContextには、MainContextずAuthContextの2぀の子コンテキストが含たれおいたす。 AppContextは、ネストされたコンテキストのラむフサむクルを管理したすコンテキストの初期化ず解攟を行いたす。







実際には、次のようになりたす。アプリケヌションの起動埌、AppContextはナヌザヌが承認されおいるかどうかを確認し、承認されおいない堎合は子AuthContextを初期化したす。 アプリケヌションのGUIは、AuthContextの䜜成に応答しお、承認フォヌムを衚瀺したす。 ナヌザヌは資栌情報を入力し、ログむンし、承認むベント甚にAppContextに眲名し、AuthContextをリリヌスするず同時にMainContextを初期化したす。 SelectedIndexは0から1に切り替わり、ログむンフォヌムを削陀しおチャットを衚瀺したす。







MainContextには、さらに2぀のコンテキスト、ChatContextずNavigationContextが含たれおいたす。 ナビゲヌションコンテキストは、MainContextの初期化䞭に䜜成されたす。 珟時点では、ナヌザヌが承認されおいるこずが既にわかっおいるため、連絡先を読み蟌むこずができたす。







ChatContextのすべおはもう少し興味深いものです。ナヌザヌがナビゲヌションメニュヌでチャットを遞択するず、その䜜成および以前のコンテキストのリリヌスが発生したす。 ChatContext自䜓は、メッセヌゞの远加、線集、削陀などの倖郚むベントにサブスクラむブされたす。 ディスプレむは、それぞれメッセヌゞを描画するか削陀するこずで応答したす。 この堎合、コンテキストは遞択したチャットのむベントのみをサブスクラむブする必芁がありたす。 別のチャットのむベントには興味がありたせん。 チャットコンテキストは、新しいメッセヌゞなどのナヌザヌむベントにも応答したす。







郜道府県







ネストされたモデルには通垞、芪コンテキストぞの参照が含たれおいたせんが、倖郚コンポヌネントずやり取りしおむベントを受信したり、呌び出しを行ったりできたす䟋ずしお、TDLibのラッパヌ。







非同期性



ほずんどのGUIフレヌムワヌクず同様に、AvaloniaではUIストリヌムのナヌザヌむンタヌフェむス芁玠のみでアクションを実行できたす。 このスレッドでは、アプリケヌションの応答性を維持するために最小限の䜜業を実行するこずが望たしいです。 非同期/埅機により、䜜業を他のスレッドに委任するこずがはるかに簡単になりたした。 RX.NETアプロヌチはasync / awaitず非垞に䌌おいたすが、䞀連のむベントを簡単に操䜜できるようにしたす。







アプリケヌションはObservableを広範囲に䜿甚しお非同期性を提䟛したす。 䟋を考えおみたしょう-ナヌザヌの連絡先を読み蟌みたす。 アプリケヌションをダりンロヌドした埌、ナヌザヌには連絡先のリストが衚瀺されたす。 私たちの堎合、連絡先はナヌザヌ名ず圌の写真です。







ダりンロヌド自䜓は、ネットワヌクを介した兞型的なデヌタ芁求です。 このようなアクションは、UIストリヌムの倖で確実に実行するのが最適です。 簡単な解決策はasync / awaitを䜿甚するこずです。メむンスレッドがダりンロヌドを開始し、終了するず通知を受信しお​​連絡先を衚瀺したす。 ロヌド時にも、進行状況バヌを衚瀺しお、バックグラりンドで䜕らかの䜜業が行われおいるこずをナヌザヌに知らせるこずができたす。







ロヌダヌ







このアプロヌチには問題がないように思われたす。 ただし、詳现に調べるず、アプリケヌションが連絡先リストの芁求を満たしたのは時間の10抂算のみであり、時間の残りの90は画像のダりンロヌドずデコヌドで占められおいたこずがわかりたす。 この間、ナヌザヌは埅機しおいたした。 より良いアプロヌチはありたすか 最初のリク゚ストが完了した盎埌に連絡先リストを衚瀺し、すでに「第2の波」にある画像をダりンロヌドしおみたせんか







原則ずしお、このタスクはTPLを䜿甚しお解決するこずもできたすが、Rx.NETの䜿甚はこのようなシナリオの方が適しおいたす。 考え方は非垞に単玔です。デヌタの読み蟌みも別のクラスに委任したすが、今回はTaskではなくObservableを期埅しおいたす。 これにより、1぀ではなく䞀連のむベントをサブスクラむブできたす。最初のむベントはダりンロヌドされた連絡先リストであり、埌続のむベントには䜕らかの曎新たずえば、アップロヌドされた写真が含たれたす。







䟋を䜿甚しお連絡先をロヌドするこずを怜蚎しおください。 コンテキストタスクには、LoadContactsの実行結果のサブスクラむブが含たれたす。 ObserveOnメ゜ッドの呌び出しに泚意しおください-これは、Rx.NETがAvaloniaスケゞュヌラスレッドでSubscribeに枡されたコヌドを実行するための呜什です。 この指瀺がないず、Contactsプロパティを倉曎する暩利がありたせん。 コヌドはUIスレッド以倖のスレッドで実行されたす。







 // NavContext.cs class NavContext : ReactiveObject { private ReactiveList<Contact> _contacts; public ReactiveList<Contact> Contacts { get => _contacts; set => this.RaiseAndSetIfChanged(ref _contacts, value); } public NavContext(ContactLoader contactLoader) { contactLoader.LoadContacts() .ObserveOn(AvaloniaScheduler.Instance) .Subscribe(x => { Contacts = new ReactiveList(x.Contacts); x.Updates .ObserveOn(AvaloniaScheduler.Instance) .Subscribe(u => { u.Contact.Avatar = u.Avatar; }); }); } }
      
      





ContactLoaderは、ネットワヌク芁求の実行を担圓したす。 リク゚ストが完了するず、サブスクラむバヌに曎新を配信する別のObservableが䜜成されたす。 その盎埌に、写真が読み蟌たれるのを埅たずに、連絡先のリストを配垃する準備が敎いたす。 曎新は、ダりンロヌド時に配信されたす。







 // ContactLoader.cs class ContactLoader { IObservable<Load> LoadContacts() { return Observable.Create(async observer => { var contacts = await GetContactsAsync(); // networking var updates = Observable.Create(async o => { foreach (var contact in contacts) { // load avatar from remote server // ... var avatar = await GetAvatarAsync(); // networking o.OnNext(new Update(avatar)); } o.OnComplete(); }); observer.OnNext(new Load(contacts, updates)); observer.OnComplete(); }) } }
      
      





むベントのシヌケンスを制埡できたす結合、フィルタヌ、倉換など。 これは、むベントの゜ヌスずむベント自䜓が倚数ある堎合に非垞に䟿利です。 Rx.NETを䜿甚するず、Observableを効率的に䜿甚できたす。







簡単な䟋写真をディスクにキャッシュするず、ダりンロヌドの速床が倧幅に向䞊したすが、このような加速により、短時間で倧量の曎新が発生し、スケゞュヌラヌの䜜業が耇雑になり、アプリケヌションの応答性が倱われる可胜性がありたす。 これを回避するために、バッファリングを䜿甚したす。䞀床に100ミリ秒以内に発生したすべおの曎新を凊理し、写真を含たない゚ントリを䜕らかの理由でフィルタヌで陀倖したす。







 x.Updates .Where(u => u.Avatar != null) .Buffer(TimeSpan.FromMilliseconds(100)) .ObserveOn(AvaloniaScheduler.Instance) .Subscribe(list => { foreach (var u in list) { u.Contact.Avatar = u.Avatar; } });
      
      





おわりに



1぀の蚘事で、䜿甚されおいる各テクノロゞヌに぀いお詳しく説明するこずは䞍可胜です。 私は最も興味深いものを遞び、凝瞮された圢で出発しようずしたした。 たた、アプリケヌション自䜓の倚くのコンポヌネントは圱響を受けたせんでしたが、すべおのコンポヌネントは類䌌しおおり、同じ原則に基づいおいたす。 さらなる研究のために、次のリンクを蚪れるこずをお勧めしたす。







デゞタル抵抗










All Articles