3

MVVMのパターンをできるだけ踏襲したいのですが、ナビゲーションがうまくできているかわかりません。私はMasterDetailページを使用しており、ナビゲートするときに詳細側のみを変更して、マスターページを維持したいことに注意してください。

ViewModelからナビゲートする方法は次のとおりです。この例では、ViewModelOneからViewModelTwoへ:

public class ViewModelOne : ViewModelBase
{
    private void GoToViewTwo()
    {
        var viewTwo = new ViewTwo(new ViewModelTwo());
        ((MasterView)Application.Current.MainPage).NavigateToPage(viewTwo);
    }
}

マスタービューの実装:

public class MasterView : MasterDetailPage
{
    public void NavigateToPage(Page page)
    {
        Detail = new NavigationPage(page);
        IsPresented = false;
    }
}

ViewTwo の実装:

public partial class ViewTwo : PageBase
{
    public MenuView(ViewModelTwo vm)
        : base(vm)
    {
        InitializeComponent();
    }
}

PageBase の実装:

public class PageBase : ContentPage
{
    public PageBase(ViewModelBase vmb)
    {
        this.BindingContext = vmb;
    }
}

これは、ナビゲーションを行うための最良のアプローチ (および最良のパフォーマンス) ですか? いくつかのナビゲーションを行うと、アプリの実行が遅くなり始め、うまくいかないことがあります。

これは、常に MasterDetail ページを表示するナビゲーションを実行するための最良の方法ですか?

ありがとう。

4

1 に答える 1

4

確かに正しい方向に進んでいると思いますが、ここにはいくつかの問題があります。

まず、ビュー モデルでビューをインスタンス化するべきではありません。ビュー モデルがビューを認識するようになるとすぐに、パターンをほぼ破ったことになります。

var viewTwo = new ViewTwo(new ViewModelTwo());

ビューの作成は、マスター ビューが担当する必要があります。実際、ビューの作成について心配する必要さえありません。ビューには を使用できるDataTemplateからです。それについては後で説明します。

まず、View ModelsViewsから分離する必要があります。ここに私が提案するものがあります:

物事を汎用的に保つために、ある種のベースclassまたはinterfaceビューモデルが必要になります。その理由はすぐにわかります。簡単な例から始めましょう。

public abstract class ViewModel : INotifyPropertyChanged
{
    public event EventHandler OnClosed;        
    public event EventHandler OnOpened;

    //Don't forget to implement INotifyPropertyChanged.
    public bool IsDisplayed { get; private set; } 

    public void Open()
    {
        IsDisplayed = true;

        //TODO: Raise the OnOpened event (Might be a better idea to put it in the IsDisplayed getter.
    }

    public void Close()
    {
        IsDisplayed = false;

        //TODO: Raise the OnClosed event.
    }
}

もちろん、これは非常に単純な基本ビュー モデルです。後でこれを拡張できます。これの主な理由は、現在のページの表示を担当するマスタービュー モデルを作成できるようにするためです。マスター ビュー モデルの簡単な例を次に示します。

public class MasterViewModel : INotifyPropertyChanged
{
    //Don't forget to implement INotifyPropertyChanged.
    public ViewModel CurrentPage { get; private set; }

    public MasterViewModel()
    {
        //This is just an example of how to set the current page.
        //You might want to use a command instead.
        CurrentPage = new MovieViewModel();
    }

    //TODO: Some other master view model functionality, like exiting the application.
}

INotifyPropertyChanged同じコードを何度も再実装する必要があるのではなく、ある種の基本クラスの方がおそらく優れていることに注意してください。

これMasterViewModelは非常に単純で、現在のページを保持するだけですが、マスターを持つ目的は、アプリを閉じるなど、アプリケーションレベルのコードを実行できるようにすることです。これにより、このロジックを他のビューモデルから遠ざけることができます.

さて、良いものに移ります。

あなたの詳細はその親と関係があるため、それを管理するのは親の責任であると言うのは理にかなっています. この場合、マスター/ディテール ビュー モデルは次のようになります。

public class MovieViewModel : ViewModel
{
    protected PickGenreViewModel ChildViewModel { get; private set; }

    public MovieViewModel()
    {
        ChildViewModel = new PickGenreViewModel();

        //TODO: Perhaps subscribe to the closed event?
    }

    //Just an example but an important thing to note is that
    //this method is protected because it's the MovieViewModel's
    //responsibility to manage it's child view model.
    protected void PickAGenre()
    {  
        ChildViewModel.Open();
    }

    //TODO: Other view model functionality.
}

これで、ある種のビュー モデル構造ができました。「ビューについてはどうですか?」と疑問に思われることでしょう。ここで のDataTemplate出番です。

WPF では、ビューをに割り当てるTypeことができます。たとえば、次のように XAML でMovieViewを に割り当てることができます。MovieViewModel

xmlns:Views="clr-namespace:YourNamespace.Views"
xmlns:ViewModels="clr-namespace:YourNamespace.ViewModels"

... 

<DataTemplate DataType="{x:Type ViewModels:MovieViewModel}">
    <Views:MovieView/>
</DataTemplate>

マスター ビューを取得して現在のページのビューを実際に表示するには、 を作成し、それをContentPresenterにバインドするだけです。マスター ビューは次のようになります。ContentCurrentPage

<Window 
    ...
    xmlns:ViewModels="clr-namespace:YourNamespace.ViewModels">
<Window.DataContext>
    <ViewModels:MasterViewModel/>
</Window.DataContext>
<Grid>
    <ContentPresenter Content="{Binding CurrentPage}"/>
</Grid>

これをさらに拡張するには、 for it's childMasterViewを含める必要があるのは だけでなく、 it's childにも必要です。同じ方法をもう一度使用できます。ContentPresenterMovieViewPickGenreViewModel

<Grid>
    <!-- The main view code for the movie view -->
    ...
    <Border Visibility="{Binding ChildViewModel.IsDisplayed, Converter=...">
        <ContentPresenter Content="{Binding ChildViewModel}"/>
    </Border>
</Grid>

注: ブール値から可視性へのコンバーターを使用して、子コンテンツを表示するかどうかを決定します。

このメソッドを使用すると、ビューのインスタンス化DataTemplateについて心配する必要はありません。とContentPresenterがそれを処理するため、心配する必要があるのは、ビュー モデルを適切なビューにマッピングすることだけです。

ふぅ!それは多くのことを吸収するものでした。

これから取り上げる主なポイントは次のとおりです。

  1. ビュー モデルでビューを作成するべきではありません。UI は UI であり、Data は Data であることを忘れないでください。
  2. ビュー モデルの責任は、ビュー モデルの所有者にあり、親子関係では、ビュー モデルの管理者ではなく、親に子を管理させるのが理にかなっています。

最後の注意点として、これを実現する方法は他にも 1 つ以上あります。先ほど述べたように、ビューとビュー モデルの作成/削除を担当するある種のビューおよびビュー モデル マネージャーです。

于 2015-08-05T13:49:40.057 に答える