web-dev-qa-db-ja.com

mvvmでのXamarin.formページナビゲーション

Xamarin.formクロスプラットフォームアプリケーションに取り組んでいます。ボタンをクリックすると、あるページから別のページに移動できます。 Code-Behidファイルでのみ可能なため、ViewModelでNavigation.PushAsync(new Page2());を実行できないため。これを行う方法を提案してください?

これが私の見解です:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.Microsoft.com/winfx/2009/xaml"
             x:Class="Calculator.Views.SignIn"
             xmlns:ViewModels="clr-namespace:Calculator.ViewModels;Assembly=Calculator">

    <ContentPage.BindingContext>
        <ViewModels:LocalAccountViewModel/>
    </ContentPage.BindingContext>

    <ContentPage.Content>

            <StackLayout>
                <Button Command="{Binding ContinueBtnClicked}"></Button>

            </StackLayout>


    </ContentPage.Content>
</ContentPage>

ここに私のViewModelがあります:

 public class LocalAccountViewModel : INotifyPropertyChanged
        {




            public LocalAccountViewModel()
            {
                this.ContinueBtnClicked = new Command(GotoPage2);
            }


            public void GotoPage2()
            {
                 /////

            }


            public ICommand ContinueBtnClicked
            {

                protected set;
                get;
            }

           public event PropertyChangedEventHandler PropertyChanged;


        protected virtual void OnPropertyChanges([CallerMemberName] string PropertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

        }
9
Waleed Arshad

1つの方法は、VMコンストラクターを介してナビゲーションを渡すことができます。ページはVisualElementから継承するため、Navigationプロパティを直接継承します。

コードビハインドファイル:

_public class SignIn : ContentPage
{
    public SignIn(){
       InitializeComponent();
       // Note the VM constructor takes now a INavigation parameter
       BindingContext = new LocalAccountViewModel(Navigation);
    }
}
_

次に、VMでINavigationプロパティを追加し、コンストラクターを変更してINavigationを受け入れます。その後、ナビゲーションにこのプロパティを使用できます。

_public class LocalAccountViewModel : INotifyPropertyChanged
{

       public INavigation Navigation { get; set;}


        public LocalAccountViewModel(INavigation navigation)
        {
            this.Navigation = navigation;
            this.ContinueBtnClicked = new Command(async () => await GotoPage2());
        }


        public async Task GotoPage2()
        {
             /////
             await Navigation.PushAsync(new Page2());
        }


        ...
_

修正する必要があるコードの問題に注意してください。GoToPage2()メソッドをasyncに設定し、Task型を返す必要があります。さらに、コマンドは非同期アクション呼び出しを実行します。これは、ページナビゲーションを非同期に行う必要があるためです!

それが役に立てば幸い!

17
TaiT's

簡単な方法は

this.ContinueBtnClicked = new Command(async()=>{

    await Application.Current.MainPage.Navigation.PushAsync(new Page2());
});
13

VMから

public Command RegisterCommand
        {
            get
            {
                return new Command(async () =>
                {
                    await Application.Current.MainPage.Navigation.PushAsync(new RegisterNewUser());
                });

            }
        }
2
AG70

原則に基づいた私のアプローチは、すべてのビューがVMアプリのコンテキストベースの場所のみにナビゲートできる:

ViewModelでは、私はそのようなINavigationHandlerインターフェスを宣言します:

public class ItemsViewModel : ViewModelBase
{
    public INavigationHandler NavigationHandler { private get; set; }


    // some VM code here where in some place i'm invoking
    RelayCommand<int> ItemSelectedCommand => 
        new RelayCommand<int>((itemID) => { NavigationHandler.NavigateToItemDetail(itemID); });


    public interface INavigationHandler
    {
        void NavigateToItemDetail(int itemID);
    }
}

そして、ViewModelのINavigationHandlerとして分離コードクラスを割り当てます。

public class ItemsPage : ContentPage, ItemsViewModel.INavigationHandler
{
    ItemsViewModel viewModel;

    public ItemsPage()
    {
        viewModel = Container.Default.Get<ItemsViewModel>();
        viewModel.NavigationHandler = this;
    }


    public async void NavigateToItemDetail(int itemID)
    {
        await Navigation.PushAsync(new ItemDetailPage(itemID));
    }
}
1

私はこれを調べましたが、それはナビゲーションをどのように処理したいかによって異なります。ビューモデルでナビゲーションを処理するか、ビューを使用しますか。さまざまな状況やアプリケーションに合わせて異なるナビゲーション形式を選択できるように、ビューでナビゲーションを処理するのが最も簡単であることがわかりました。この状況では、コマンドバインディングモデルを使用するのではなく、ボタンクリックイベントを使用して、コードビハインドのナビゲーションスタックに新しいページを追加します。

ボタンを次のように変更します。

<StackLayout>
    <Button Clicked="Button_Clicked"></Button>
</StackLayout>

そして、コードビハインドでメソッドを実装し、そこでナビゲーションを実行します。

public void Button_Clicked(object sender, EventArgs e)
{
    Navigation.PushAsync(new Page2());
}

ビューモデルベースのナビゲーションを実行しようとしている場合、MvvmCrossでこれを行う方法はあると思いますが、そのツールには慣れていません。

1
Rob