Xamarin.Formsでページを切り替えるにはどうすればよいですか?


99

Xamarinフォームのページをどのように切り替えますか?

私のメインページはContentPageであり、タブ付きページなどに切り替えたくありません。

ContentPageが見つかるまで新しいページをトリガーするコントロールの親を見つけ、それからContentを新しいページのコントロールと交換することで、疑似操作を行うことができました。しかし、これは本当にずさんなようです。


この質問にはすでに多くの回答があり、MVVM構造パターンを使用してそれを行う方法を確認するには、このstackoverflow.com/a/37142513/9403963を
Alireza Sattari

回答:


67

Xamarin.Forms 組み込みの複数のナビゲーションホストをサポート:

  • NavigationPage、次のページがスライドインする場所、
  • TabbedPage、あなたが嫌い​​なもの
  • CarouselPage、左と右を次/前のページに切り替えることができます。

これに加えて、すべてのページPushModalAsync()は、既存のページの上に新しいページをプッシュすることもサポートしています。

最後に、ユーザーが前のページに戻れないようにする場合(ジェスチャーまたはハードウェアの戻るボタンを使用)、同じものをPage表示したままにして、を置き換えることができますContent

ルートページを置き換えるための推奨オプションも機能しますが、プラットフォームごとに異なる方法で処理する必要があります。


PushModalAsyncはナビゲーションの一部のようですよね?ナビゲーションオブジェクト/クラスにアクセスする方法がわかりません。INavigationを実装するものにアクセスする必要があると思いますが、何ですか?
エリック

ページがNavigationPage内に含まれている場合、ページ内からNavigationプロパティにアクセスできるはずです
Jason

1
NavigationPageの使用を開始すると、すべてがうまくいきました。ありがとう
エリック

1
私の最初のページがCarouselPageであると私の2ページ目は、私はページを切り替えることができ、その後どのようにmasterDetailPageある場合@stephane教えてください stackoverflow.com/questions/31129845/...
アトゥールDhanuka

64

Appクラスでは、MainPageをナビゲーションページに設定し、ルートページをContentPageに設定できます。

public App ()
{
    // The root page of your application
    MainPage = new NavigationPage( new FirstContentPage() );
}

次に、最初のContentPage呼び出しで:

Navigation.PushAsync (new SecondContentPage ());

私はそれをしましたが、それでもメインページが開いているデフォルトのページです。メインページに設定したページには何の影響もありません。設定した最初のページを開くだけです。どうしたの?
Behzad

Visual StudioではAndroid.Content.Res、ナビゲーション用にインポートすることをお勧めします。それは正しくないようです、どこからインポートする必要がありますか?
クリスチャン

41

プロジェクトがPCLフォームプロジェクトとして設定されている場合(おそらく共有フォームとしても同様ですが、まだ試していない場合)、次のようなクラスApp.csがあります。

public class App
{
    public static Page GetMainPage ()
    {     
        AuditorDB.Model.Extensions.AutoTimestamp = true;
        return new NavigationPage (new LoginPage ());
    }
}

GetMainPageメソッドを変更して、新しいTabbedPagedまたはプロジェクトで定義した他のページを返すことができます

そこから、コマンドまたはイベントハンドラーを追加してコードを実行し、

// to show OtherPage and be able to go back
Navigation.PushAsync(new OtherPage());

// to show AnotherPage and not have a Back button
Navigation.PushModalAsync(new AnotherPage()); 

// to go back one step on the navigation stack
Navigation.PopAsync();

3
これはページを切り替えません。これにより、最初に読み込まれるページのみが変更されます。
dakamojo 2014

あなたの質問はメインページについて話していました。ナビゲーションの例については、更新された回答を参照してください
Sten Petrov

Navigationこの例では一体何ですか?-それはあなたがどこかに作成したオブジェクトですか?-このコードサンプルには表示されません。
BrainSlugs83

ナビゲーションはページのプロパティです
Sten Petrov

ありがとう。FTR PushAsync()は機能しませんでしたが、機能しましPushModalAsync()
knocte

23

新しいページをスタックにプッシュしてから、現在のページを削除します。これにより切り替えが発生します。

item.Tapped += async (sender, e) => {
    await Navigation.PushAsync (new SecondPage ());
    Navigation.RemovePage(this);
};

最初にナビゲーションページにいる必要があります。

MainPage = NavigationPage(new FirstPage());

大きなページが1つとOnAppearing ectなどのページイベントが1セットしかないため、コンテンツの切り替えは理想的ではありません。


Navigation.RemovePage();Androidではサポートされていません。
Rohit Vipin Mathews

1
Navigation.RemovePage(page); Androidで動作します。最初にナビゲーションページ内にある必要があります。
Daniel Roberts

Forms 1.4.2のプロジェクトで幅広く使用しています。おそらく彼らはバグを修正したのでしょうか、それとも幸運でまだヒットしていません。
Daniel Roberts

私は最新バージョンを使用しており、それを複製することができます。だからあなたは運が良すぎると思います。
Rohit Vipin Mathews

2
ハンディのヒント-のページを変更するときに2番目のパラメータとして偽を追加し、トランジションを削除するには:await Navigation.PushAsync(new SecondPage(),false);
ダミアン・グリーン

8

前のページに移動したくない場合、つまり認証が完了した後でユーザーにログイン画面に戻らせない場合は、使用できます。

 App.Current.MainPage = new HomePage();

バック機能を有効にしたい場合は、

Navigation.PushModalAsync(new HomePage())

4

このスレッドは非常に人気があるようで、代替方法があることは言うまでもありません。 ViewModel First Navigationです。MVVMフレームワークのほとんどはそれを使用していますが、それが何であるかを理解したい場合は、読み続けてください。

Xamarin.Formsの公式ドキュメントはすべて、MVVMの純粋なソリューションですが、シンプルではありませんが、わずかなものです。これは、Page(ビュー)がについて何も知らないためでViewModelあり、その逆も同様です。この違反の良い例を次に示します。

// C# version
public partial class MyPage : ContentPage
{
    public MyPage()
    {
        InitializeComponent();
        // Violation
        this.BindingContext = new MyViewModel();
    }
}

// XAML version
<?xml version="1.0" encoding="utf-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:viewmodels="clr-namespace:MyApp.ViewModel"
    x:Class="MyApp.Views.MyPage">
    <ContentPage.BindingContext>
        <!-- Violation -->
        <viewmodels:MyViewModel />
    </ContentPage.BindingContext>
</ContentPage>

2ページのアプリケーションを使用している場合、このアプローチが適している可能性があります。ただし、大規模なエンタープライズソリューションに取り組んでいる場合は、ViewModel First Navigationアプローチを使用することをお勧めします。(ビュー)ViewModels間のナビゲーションの代わりにナビゲートできるようにする、少し複雑ですがよりクリーンなアプローチですPages。懸念事項を明確に分離する以外の利点の1つは、ViewModelナビゲーションの直後にパラメーターを簡単に渡したり、非同期初期化コードを実行したりできることです。次に詳細について説明します。

(私はすべてのコード例をできるだけ単純化するように努めます)。

1.まず最初に、すべてのオブジェクトを登録し、オプションでそれらの寿命を定義できる場所が必要です。この問題については、IOCコンテナを使用できます。自分で選択できます。この例では、Autofacを使用します(これは、最も高速なものの1つです)。への参照をに保持して、Appグローバルに使用できるようにすることができます(良いアイデアではありませんが、簡略化のために必要です)。

public class DependencyResolver
{
    static IContainer container;

    public DependencyResolver(params Module[] modules)
    {
        var builder = new ContainerBuilder();

        if (modules != null)
            foreach (var module in modules)
                builder.RegisterModule(module);

        container = builder.Build();
    }

    public T Resolve<T>() => container.Resolve<T>();
    public object Resolve(Type type) => container.Resolve(type);
}

public partial class App : Application
{
    public DependencyResolver DependencyResolver { get; }

    // Pass here platform specific dependencies
    public App(Module platformIocModule)
    {
        InitializeComponent();
        DependencyResolver = new DependencyResolver(platformIocModule, new IocModule());
        MainPage = new WelcomeView();
    }

    /* The rest of the code ... */
}

2. Page特定の(ビュー)を取得するオブジェクト、ViewModelおよびその逆のオブジェクトが必要です。2番目のケースは、アプリのルート/メインページを設定する場合に役立ちます。そのため、すべてのViewModelsViewModelsディレクトリにあり、Pages(ビュー)がディレクトリにあるという単純な規則に同意する必要がありますViews。つまりViewModels[MyApp].ViewModels名前空間とPages(ビュー)名前空間に存在する必要があり[MyApp].Viewsます。それに加えて、WelcomeView(ページ)にはWelcomeViewModelやなどが必要であることにも同意する必要があります。マッパーのコード例を次に示します。

public class TypeMapperService
{
    public Type MapViewModelToView(Type viewModelType)
    {
        var viewName = viewModelType.FullName.Replace("Model", string.Empty);
        var viewAssemblyName = GetTypeAssemblyName(viewModelType);
        var viewTypeName = GenerateTypeName("{0}, {1}", viewName, viewAssemblyName);
        return Type.GetType(viewTypeName);
    }

    public Type MapViewToViewModel(Type viewType)
    {
        var viewModelName = viewType.FullName.Replace(".Views.", ".ViewModels.");
        var viewModelAssemblyName = GetTypeAssemblyName(viewType);
        var viewTypeModelName = GenerateTypeName("{0}Model, {1}", viewModelName, viewModelAssemblyName);
        return Type.GetType(viewTypeModelName);
    }

    string GetTypeAssemblyName(Type type) => type.GetTypeInfo().Assembly.FullName;
    string GenerateTypeName(string format, string typeName, string assemblyName) =>
        string.Format(CultureInfo.InvariantCulture, format, typeName, assemblyName);
}

3.ルートページを設定する場合はViewModelLocatorBindingContext自動的に設定する必要があります:

public static class ViewModelLocator
{
    public static readonly BindableProperty AutoWireViewModelProperty =
        BindableProperty.CreateAttached("AutoWireViewModel", typeof(bool), typeof(ViewModelLocator), default(bool), propertyChanged: OnAutoWireViewModelChanged);

    public static bool GetAutoWireViewModel(BindableObject bindable) =>
        (bool)bindable.GetValue(AutoWireViewModelProperty);

    public static void SetAutoWireViewModel(BindableObject bindable, bool value) =>
        bindable.SetValue(AutoWireViewModelProperty, value);

    static ITypeMapperService mapper = (Application.Current as App).DependencyResolver.Resolve<ITypeMapperService>();

    static void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var view = bindable as Element;
        var viewType = view.GetType();
        var viewModelType = mapper.MapViewToViewModel(viewType);
        var viewModel =  (Application.Current as App).DependencyResolver.Resolve(viewModelType);
        view.BindingContext = viewModel;
    }
}

// Usage example
<?xml version="1.0" encoding="utf-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:viewmodels="clr-namespace:MyApp.ViewModel"
    viewmodels:ViewModelLocator.AutoWireViewModel="true"
    x:Class="MyApp.Views.MyPage">
</ContentPage>

4.最後に、私たちはアプローチNavigationServiceをサポートする必要がありますViewModel First Navigation

public class NavigationService
{
    TypeMapperService mapperService { get; }

    public NavigationService(TypeMapperService mapperService)
    {
        this.mapperService = mapperService;
    }

    protected Page CreatePage(Type viewModelType)
    {
        Type pageType = mapperService.MapViewModelToView(viewModelType);
        if (pageType == null)
        {
            throw new Exception($"Cannot locate page type for {viewModelType}");
        }

        return Activator.CreateInstance(pageType) as Page;
    }

    protected Page GetCurrentPage()
    {
        var mainPage = Application.Current.MainPage;

        if (mainPage is MasterDetailPage)
        {
            return ((MasterDetailPage)mainPage).Detail;
        }

        // TabbedPage : MultiPage<Page>
        // CarouselPage : MultiPage<ContentPage>
        if (mainPage is TabbedPage || mainPage is CarouselPage)
        {
            return ((MultiPage<Page>)mainPage).CurrentPage;
        }

        return mainPage;
    }

    public Task PushAsync(Page page, bool animated = true)
    {
        var navigationPage = Application.Current.MainPage as NavigationPage;
        return navigationPage.PushAsync(page, animated);
    }

    public Task PopAsync(bool animated = true)
    {
        var mainPage = Application.Current.MainPage as NavigationPage;
        return mainPage.Navigation.PopAsync(animated);
    }

    public Task PushModalAsync<TViewModel>(object parameter = null, bool animated = true) where TViewModel : BaseViewModel =>
        InternalPushModalAsync(typeof(TViewModel), animated, parameter);

    public Task PopModalAsync(bool animated = true)
    {
        var mainPage = GetCurrentPage();
        if (mainPage != null)
            return mainPage.Navigation.PopModalAsync(animated);

        throw new Exception("Current page is null.");
    }

    async Task InternalPushModalAsync(Type viewModelType, bool animated, object parameter)
    {
        var page = CreatePage(viewModelType);
        var currentNavigationPage = GetCurrentPage();

        if (currentNavigationPage != null)
        {
            await currentNavigationPage.Navigation.PushModalAsync(page, animated);
        }
        else
        {
            throw new Exception("Current page is null.");
        }

        await (page.BindingContext as BaseViewModel).InitializeAsync(parameter);
    }
}

ご覧のとおり、ナビゲーションの直後に実行されるそのようなメソッドを定義できるBaseViewModelすべてのViewModels場所の抽象基本クラスがありますInitializeAsync。そして、これはナビゲーションの例です:

public class WelcomeViewModel : BaseViewModel
{
    public ICommand NewGameCmd { get; }
    public ICommand TopScoreCmd { get; }
    public ICommand AboutCmd { get; }

    public WelcomeViewModel(INavigationService navigation) : base(navigation)
    {
        NewGameCmd = new Command(async () => await Navigation.PushModalAsync<GameViewModel>());
        TopScoreCmd = new Command(async () => await navigation.PushModalAsync<TopScoreViewModel>());
        AboutCmd = new Command(async () => await navigation.PushModalAsync<AboutViewModel>());
    }
}

あなたが理解しているように、このアプローチはより複雑でデバッグが難しく、混乱するかもしれません。ただし、多くの利点があり、ほとんどのMVVMフレームワークはそのまま使用できるため、実際に自分で実装する必要はありません。ここで示されているコード例は、githubで入手できます。アプローチ

については多くの優れた記事ViewModel First Navigationがあり、Xamarin.Forms eBookを使用した無料のエンタープライズアプリケーションパターンがあり、これと他の多くの興味深いトピックを詳細に説明しています。


3

PushAsync()メソッドを使用してプッシュすることができ、PopModalAsync()はナビゲーションスタックとの間でページをポップできます。以下のコード例には、ナビゲーションページ(ルートページ)があり、このページから、ログインページが完成したら、ログインページであるコンテンツページをプッシュします。ルートページに戻ります。

~~~ナビゲーションは、ページオブジェクトの後入れ先出しスタックと考えることができます。あるページから別のページに移動するには、アプリケーションが新しいページをこのスタックにプッシュします。前のページに戻るために、アプリケーションはスタックから現在のページをポップします。Xamarin.Formsのこのナビゲーションは、INavigationインターフェイスによって処理されます

Xamarin.Formsには、このインターフェイスを実装し、ページのスタックを管理するNavigationPageクラスがあります。NavigationPageクラスは、タイトルを表示する画面の上部にナビゲーションバーを追加し、前のページに戻るプラットフォームに適した[戻る]ボタンも備えています。次のコードは、アプリケーションの最初のページをNavigationPageでラップする方法を示しています。

上記のコンテンツへの参照とXamarinフォームの詳細について確認する必要があるリンクについては、ナビゲーションセクションを参照してください。

http://developer.xamarin.com/guides/cross-platform/xamarin-forms/introduction-to-xamarin-forms/

~~~

public class MainActivity : AndroidActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        Xamarin.Forms.Forms.Init(this, bundle);
        // Set our view from the "main" layout resource
        SetPage(BuildView());
    }

    static Page BuildView()
    {
        var mainNav = new NavigationPage(new RootPage());
        return mainNav;
    }
}


public class RootPage : ContentPage
{
    async void ShowLoginDialog()
    {
        var page = new LoginPage();

        await Navigation.PushModalAsync(page);
    }
}

//簡単にするために削除されたコードはポップのみが表示されます

private async void AuthenticationResult(bool isValid)
{
    await navigation.PopModalAsync();
}

2

Navigationプロパティを使用したXamarin.formsのあるページから別のページへのナビゲーションサンプルコードの下

void addClicked(object sender, EventArgs e)
        {
            //var createEmp = (Employee)BindingContext;
            Employee emp = new Employee();
            emp.Address = AddressEntry.Text;   
            App.Database.SaveItem(emp);
            this.Navigation.PushAsync(new EmployeeDetails());
  this.Navigation.PushModalAsync(new EmployeeDetails());
        }

ビューセル内の1つのページを別のページに移動するにはコードの下Xamrian.forms

 private async void BtnEdit_Clicked1(object sender, EventArgs e)
        {
            App.Database.GetItem(empid);
            await App.Current.MainPage.Navigation.PushModalAsync(new EmployeeRegistration(empid));
        }

以下のような例

public class OptionsViewCell : ViewCell
    {
        int empid;
        Button btnEdit;
        public OptionsViewCell()
        {
        }
        protected override void OnBindingContextChanged()
        {
            base.OnBindingContextChanged();

            if (this.BindingContext == null)
                return;

            dynamic obj = BindingContext;
            empid = Convert.ToInt32(obj.Eid);
            var lblname = new Label
            {
                BackgroundColor = Color.Lime,
                Text = obj.Ename,
            };

            var lblAddress = new Label
            {
                BackgroundColor = Color.Yellow,
                Text = obj.Address,
            };

            var lblphonenumber = new Label
            {
                BackgroundColor = Color.Pink,
                Text = obj.phonenumber,
            };

            var lblemail = new Label
            {
                BackgroundColor = Color.Purple,
                Text = obj.email,
            };

            var lbleid = new Label
            {
                BackgroundColor = Color.Silver,
                Text = (empid).ToString(),
            };

             //var lbleid = new Label
            //{
            //    BackgroundColor = Color.Silver,
            //    // HorizontalOptions = LayoutOptions.CenterAndExpand
            //};
            //lbleid.SetBinding(Label.TextProperty, "Eid");
            Button btnDelete = new Button
            {
                BackgroundColor = Color.Gray,

                Text = "Delete",
                //WidthRequest = 15,
                //HeightRequest = 20,
                TextColor = Color.Red,
                HorizontalOptions = LayoutOptions.EndAndExpand,
            };
            btnDelete.Clicked += BtnDelete_Clicked;
            //btnDelete.PropertyChanged += BtnDelete_PropertyChanged;  

            btnEdit = new Button
            {
                BackgroundColor = Color.Gray,
                Text = "Edit",
                TextColor = Color.Green,
            };
            // lbleid.SetBinding(Label.TextProperty, "Eid");
            btnEdit.Clicked += BtnEdit_Clicked1; ;
            //btnEdit.Clicked += async (s, e) =>{
            //    await App.Current.MainPage.Navigation.PushModalAsync(new EmployeeRegistration());
            //};

            View = new StackLayout()
            {
                Orientation = StackOrientation.Horizontal,
                BackgroundColor = Color.White,
                Children = { lbleid, lblname, lblAddress, lblemail, lblphonenumber, btnDelete, btnEdit },
            };

        }

        private async void BtnEdit_Clicked1(object sender, EventArgs e)
        {
            App.Database.GetItem(empid);
            await App.Current.MainPage.Navigation.PushModalAsync(new EmployeeRegistration(empid));
        }



        private void BtnDelete_Clicked(object sender, EventArgs e)
        {
            // var eid = Convert.ToInt32(empid);
            // var item = (Xamarin.Forms.Button)sender;
            int eid = empid;
            App.Database.DeleteItem(empid);
        }

    }

2

コール:

((App)App.Current).ChangeScreen(new Map());

App.xaml.cs内にこのメソッドを作成します。

public void ChangeScreen(Page page)
{
     MainPage = page;
}

2
In App.Xaml.Cs:

MainPage = new NavigationPage( new YourPage());

YourPageから次のページに移動する場合は、次のようにします。

await Navigation.PushAsync(new YourSecondPage());

Xamarinフォームナビゲーションの詳細については、https//docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/hierarchicalを参照してください。

Microsoftはこれに関してかなり良いドキュメントを持っています。

の新しい概念もありShellます。これにより、アプリケーションを構造化する新しい方法が可能になり、場合によってはナビゲーションが簡略化されます。

イントロ:https : //devblogs.microsoft.com/xamarin/shell-xamarin-forms-4-0-getting-started/

シェルの基本に関するビデオ:https : //www.youtube.com/watch?v=0y1bUAcOjZY&t=3112s

ドキュメント:https : //docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/


0

これを追加するXAMLページ

<ContentPage.ToolbarItems>
            <ToolbarItem Text="Next" Order="Primary"
            Activated="Handle_Activated"/>

</ContentPage.ToolbarItems>   

CSページ

 async void Handle_Activated(object sender, System.EventArgs e)
        {
            await App.Navigator.PushAsync(new PAGE());
        }

0

PushAsync使用して現在のページを削除PopAsyncした後this

await Navigation.PushAsync(new YourSecondPage());
this.Navigation.PopAsync(this);

0

XamarinにはNavigationPageというページがあります。ContentPageのスタックを保持します。NavigationPageには、PushAsync()およびPopAsync()のようなメソッドがあります。PushAsyncはスタックの最上部にページを追加します。そのとき、そのページページは現在アクティブなページになります。PopAsync()メソッドは、スタックの最上部からページを削除します。

App.Xaml.Csでは、次のように設定できます。

MainPage = new NavigationPage(new YourPage());

await Navigation.PushAsync(new newPage()); このメソッドは、スタックの一番上にnewPageを追加します。この時点で、nePageは現在アクティブなページになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.