xaml指向のアプリケーションでビュー(画面)間を移動することは、かなり重要で興味深いタスクです。 これは、 MVVMパターンのフレームワークでの実装に特に当てはまります。 理想的には、クロスプラットフォームであり、複数のプロジェクトで繰り返し使用される可能性を維持するために、ビューモデルにはビューへの直接リンクを含めないでください。 今日はこれを達成する方法を学びます。
xaml開発では、 コマンドの概念は非常に密接に関連しています。 Aeroフレームワークライブラリでのこのパターンの実装は、直感的であり、すでにドキュメントで簡単に説明されているため、今日は検討しません。
この問題のアーキテクチャ上の重要性にもかかわらず、ナビゲートするための驚くほどシンプルで信頼できる方法があります...あなたはそれがとても簡単だとすぐに信じさえしないかもしれません。
ほとんどの場合、視覚要素をクリックしてコマンドを実行するとナビゲーションが発生するため、コマンドにパラメーターとしてターゲットビューの識別子(アドレスまたはタイプ)を渡さないのはなぜですか? 結局のところ、それは非常に簡単で論理的です。
<Button Content="{Localizing About}" Command="{Context Key=Navigate}" CommandParameter="/Views/AboutView.xaml">
<Button Content="{Localizing About}" Command="{Context Key=Navigate}" CommandParameter="{x:Type views:PaymentView}">
<Button Content="{Localizing About}" Command="{Context Key=Navigate}" CommandParameter="http://makeloft.by/">
public class NavigationViewModel : ContextObject, IExposable { public virtual void Expose() { this[Context.Navigate].CanExecute += (sender, args) => args.CanExecute = 'any conditions'; this[Context.Navigate].Executed += (sender, args) => Navigator.GoTo(args.Parameter); } }
特定のプレゼンテーションをナビゲートする機能は、チームのCanExecuteイベントによって管理され、 Navigatorクラスは技術的な詳細を担当します。 つまり、ターゲットアドレスは、ビューモデルを介してのみ転送されます。
少し複雑なナビゲーションスクリプトは次のようになります。
<!--LoginView.xaml--> <View DataContext="{Store Key=viewModels:LoginViewModel}"> <StackPanel> <TextBlock Text="{Localizing Key=Name}"/> <TextBox Text="{Binding Name, Mode=TwoWay}"/> <TextBlock Text="{Localizing Key=Password}"/> <PasswordBox Password="{Binding Password, Mode=TwoWay}"/> <Button Command="{Context Key=Login}" CommandParameter="{x:Type ProductsView}" Content="{Localizing Key=Login}"/> <TextBlock Text="{Binding Error}"/> </StackPanel> </View>
[DataContract] public class LoginViewModel : ContextObject, IExposable { [DataMember] public string Name { get { return Get(() => Name); } set { Set(() => Name, value); } } public string Password { get { return Get(() => Name); } set { Set(() => Name, value); } } public UserData UserData { get { return Get(() => UserData); } set { Set(() => UserData, value); } } public virtual void Expose() { this[() => Name].PropertyChanged += (sender, args) => Context.Login.RaiseCanExecuteChanged(); this[() => Password].PropertyChanged += (sender, args) => Context.Login.RaiseCanExecuteChanged(); this[() => Name].Validation += () => Error = Name == null || Name.Length < 3 ? Unity.App.Localize("InvalidName") : null; this[() => Password].Validation += (sender, args) => Error = Name == null || Name.Length < 4 ? Unity.App.Localize("InvalidPassword") : null; this[Context.Login].CanExecute += (sender, args) => { args.CanExecute = string.IsNullOrEmpty(Error); // Error contains last validation fail message }; this[Context.Login].Executed += async (sender, args) => { try { UserData = await Bank.Current.GetUserData(); Navigator.GoTo(args.Parameter); } catch (Exception exception) { Error = Unity.App.Localize(exception.Message); } }; this[Context.Logout].Executed += (sender, args) => { UserData = null; Navigator.RedirectTo(args.Parameter); }; } }
ナビゲーション後、直接注入メカニズムを使用するビューは、コンテナから目的のビューモデルを受け取ります。
これはすべて、Webナビゲーションに似ており、各ページはuriによってサーバーから要求されます。 しかし、この場合、パラメーターを転送する方法は? 直接注入の原則の適用に関連して、実際には各ビューは任意のビューモデルにアクセスし、そこから必要な情報を直接抽出できるため、パラメーターを転送する必要はありません。
すぐにトリッキーな例を思いつくかもしれませんが、複数のビューへの移行が可能で、どのビューが事前にわからない場合...論理条件に応じて、これらのボタンは設計および/または非表示です。 別の場合では、コンバーターを作成してCommandParameterプロパティにバインドすることもできます。
さまざまなバリエーションを考案できますが、アイデア自体は変更されません。ナビゲーション中に目的のビューの識別子がコマンドパラメーターで渡されます。 しかし、誰かが反対するかもしれませんが、コマンドに別のパラメーターを渡す必要がある場合はどうでしょうか? ただし、解決方法があります。コマンドに多くの引数を簡単に渡すことができます。
public class Set : ObservableCollection<object> { }
<Set x:Key="ParameterSet"> <system:String>/Views/AnyView.xaml</system:String> <system:String>SecondParaneter</system:String> </Set>
<Button Content="{Localizing GoToAnyView}" Command="{Context Key=GoTo}" CommandParameter="{StaticResource ParameterSet}">
概念は次のとおりです。 ビューはナビゲート可能な他のビュー(画面)を認識しており、特定のビューに切り替える可能性は、ビューモデルのロジックと状態によって決まります。 ビューモデルにはビジュアルインターフェイスへのリンクはありません。コマンドのパラメーターとしての次の画面の識別子は、特定のプラットフォームでのナビゲーションメカニズムの技術的な実装を既に担当しているNavigatorクラスに転送されます。 パラメーターを渡す必要はありません。直接注入の原理のおかげで、各ビューはほぼすべてのビューモデルに既にアクセスできます。
その結果、きれいなビューモデルとかなり透過的なナビゲーションロジックが得られ、重要なのは信頼性が高いことです。 おそらく、場合によっては、まだ背後コードを使用する必要がありますが、この記事の著者は、検討されたアプローチの助けを借りても解決できないこのための単一の実例を思い付くことはできませんでした。
ご清聴ありがとうございました! 質問や代替意見がある場合は、コメントで自由に表現してください!