Xamarin.Forms: TabbedPage navigáció az aloldalak között

Címkék
Xamarin.Forms: TabbedPage navigáció az aloldalak között
2018-09-13T14:48:44+02:00
2018-09-14T13:18:25+02:00
2022-10-15T21:41:14+02:00
[OP]Destroy-man
Sziasztok!

Van egy egyszerűnek tűnő (de annál inkább nem találok rá megoldást) problémám.
Adott egy 3 oldalas TabbedPage-m. Az első oldalon vannak kattintható adatok (Labelek, gesture felismeréssel). Ez még működik is, vagyis felismeri.
A feladat az lenne, hogy a kattintás után átnavigáljon a TabbedPage 3. oldalára 1-1 paraméter megadásával (string).
Ehhez viszont nem találtam semmilyen megoldást, hogy lehetne ezt megoldani.
Az alkalmazás MVVMLightot használ.

Kódot azért nem másoltam be, mert gyakorlatilag semmi sincs ebből a feladatból, ha csak a standard RelayCommand megvalósítást nem vesszük annak, amiből "csak" a navigálásos kód hiányzik :)

A segítséget előre is köszi!
Mutasd a teljes hozzászólást!
Ha külön controlokat készítesz akkor a BindableProperty lesz a barátod. Így módosul a program:

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?> <TabbedPage x:Name="Self" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:TabbedPageDemo.Views" x:Class="TabbedPageDemo.Views.MainPage"> <TabbedPage.Children> <views:Tab1 x:Name="Tab1" TabbedPage="{x:Reference Self}" NextPage="{x:Reference Tab2}" /> <views:Tab2 x:Name="Tab2" TabbedPage="{x:Reference Self}" NextPage="{x:Reference Tab1}" /> </TabbedPage.Children> </TabbedPage>
MainPage.xaml.cs

using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace TabbedPageDemo.Views { [XamlCompilation(XamlCompilationOptions.Compile)] public partial class MainPage : TabbedPage { public MainPage() { InitializeComponent(); } } }
Tab1.xaml

<?xml version="1.0" encoding="utf-8"?> <ContentPage x:Name="Self" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:TabbedPageDemo.Views" x:Class="TabbedPageDemo.Views.Tab1"> <BindableObject.BindingContext> <views:Model1 /> </BindableObject.BindingContext> <StackLayout> <Button Text="{Binding Text}" Command="{Binding Source={x:Reference Self}, Path=Command1}" /> </StackLayout> </ContentPage>
Tab1.xaml.cs

using System.Diagnostics; using System.Windows.Input; using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace TabbedPageDemo.Views { public class Model1 : BindableObject { string _text = "Button name 1"; public string Text { get => _text; set { _text = value; OnPropertyChanged(); } } } [XamlCompilation(XamlCompilationOptions.Compile)] public partial class Tab1 : ContentPage { public static readonly BindableProperty TabbedPageProperty = BindableProperty.Create( nameof(TabbedPage), typeof(TabbedPage), typeof(Tab1)); public TabbedPage TabbedPage { get => (TabbedPage) GetValue(TabbedPageProperty); set => SetValue(TabbedPageProperty, value); } public static readonly BindableProperty NextPageProperty = BindableProperty.Create( nameof(NextPage), typeof(Page), typeof(Tab1)); public Page NextPage { get => (Page) GetValue(NextPageProperty); set => SetValue(NextPageProperty, value); } public ICommand Command1 { get; } public Tab1() { Command1 = new Command(Method1); InitializeComponent(); } void Method1() { var model = (Model1) BindingContext; Debug.WriteLine(model.Text); var nextModel = (Model2) NextPage.BindingContext; Debug.WriteLine(nextModel.Text); TabbedPage.CurrentPage = NextPage; } } }
Tab2.xaml

<?xml version="1.0" encoding="utf-8"?> <ContentPage x:Name="Self" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:TabbedPageDemo.Views" x:Class="TabbedPageDemo.Views.Tab2"> <BindableObject.BindingContext> <views:Model2 /> </BindableObject.BindingContext> <StackLayout> <Button Text="{Binding Text}" Command="{Binding Source={x:Reference Self}, Path=Command2}" /> </StackLayout> </ContentPage>
Tab2.xaml.cs

using System.Diagnostics; using System.Windows.Input; using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace TabbedPageDemo.Views { public class Model2 : BindableObject { string _text = "Button name 2"; public string Text { get => _text; set { _text = value; OnPropertyChanged(); } } } [XamlCompilation(XamlCompilationOptions.Compile)] public partial class Tab2 : ContentPage { public static readonly BindableProperty TabbedPageProperty = BindableProperty.Create( nameof(TabbedPage), typeof(TabbedPage), typeof(Tab2)); public TabbedPage TabbedPage { get => (TabbedPage) GetValue(TabbedPageProperty); set => SetValue(TabbedPageProperty, value); } public static readonly BindableProperty NextPageProperty = BindableProperty.Create( nameof(NextPage), typeof(Page), typeof(Tab2)); public Page NextPage { get => (Page) GetValue(NextPageProperty); set => SetValue(NextPageProperty, value); } public ICommand Command2 { get; } public Tab2() { Command2 = new Command(Method2); InitializeComponent(); } void Method2() { var model = (Model2) BindingContext; Debug.WriteLine(model.Text); var nextModel = (Model1) NextPage.BindingContext; Debug.WriteLine(nextModel.Text); TabbedPage.CurrentPage = NextPage; } } }
Mutasd a teljes hozzászólást!

  • CurrentPage property állításával lehet megoldani.
    Mutasd a teljes hozzászólást!
  • Ja a másik kérdésre pedig rakjál egy statikus atomi szintü változót vagy osztályt az modelbe ehhez hozzáférsz mindegyik oldalon.

    De használhatod az Application.Current.Properties ["id"] = someClass.ID-t is. Ehhez mindenhol hozzáférsz.
    Mutasd a teljes hozzászólást!
  • De van CommandParameter is. Itt a BindingContext-ből adhatsz referenciát pl: 

    CommandParameter="{Binding változóneve}"
    Mutasd a teljes hozzászólást!
  • De a CurrentPage-t hogyan érem el?

    Példa a jelenlegi megvalósításomra:
    TabbedPage
    ├View A
    └View B

    A ViewA-hoz és a ViewB-hez is tartozik 1-1 ViewModel.

    A ViewA-ra leteszek egy gombot, amivel szeretnék majd navigálni.

    <Button Text="Goto B View" Command="{Binding GotoBView}" CommandParameter="Pista"/>

    A ViewModelbe meg elkapom a GotoBView commandot:

    private RelayCommand<string> gotoBView; public RelayCommand<string> GotoBView { get { return gotoBView ?? (gotoBView = new RelayCommand<string>(async (text) => { //Itt a CurrentPage nem elérhető. :) })); } }
    Mutasd a teljes hozzászólást!
  • Itt nem a RelayCommandot használom, de be tudod helyettesíteni.

    A Command nem a modelben van hanem a controlban, így minden adathoz hozzáférsz.

    Én legalábbis így csinálnám.

    MainPage.xaml


    <?xml version="1.0" encoding="utf-8"?> <TabbedPage x:Name="Self" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:TabbedPageDemo.Views" x:Class="TabbedPageDemo.Views.MainPage"> <TabbedPage.Children> <ContentPage x:Name="Page1"> <BindableObject.BindingContext> <views:Model1 /> </BindableObject.BindingContext> <StackLayout> <Button Text="{Binding Text}" Command="{Binding Source={x:Reference Self}, Path=Command1}" CommandParameter="{Binding Source={x:Reference Page2}}" /> </StackLayout> </ContentPage> <ContentPage x:Name="Page2"> <BindableObject.BindingContext> <views:Model2 /> </BindableObject.BindingContext> <StackLayout> <Button Text="{Binding Text}" Command="{Binding Source={x:Reference Self}, Path=Command2}" CommandParameter="{Binding Source={x:Reference Page1}}" /> </StackLayout> </ContentPage> </TabbedPage.Children> </TabbedPage>

    MainPage.xaml.cs:

    using System.Diagnostics; using System.Windows.Input; using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace TabbedPageDemo.Views { public class Model1 : BindableObject { string _text = "Button name 1"; public string Text { get => _text; set { _text = value; OnPropertyChanged(); } } } public class Model2 : BindableObject { string _text = "Button name 2"; public string Text { get => _text; set { _text = value; OnPropertyChanged(); } } } [XamlCompilation(XamlCompilationOptions.Compile)] public partial class MainPage : TabbedPage { public ICommand Command1 { get; } public ICommand Command2 { get; } public MainPage() { Command1 = new Command<Page>(Method1); Command2 = new Command<Page>(Method2); InitializeComponent(); } void Method1(Page page2) { var model2 = (Model2) page2.BindingContext; Debug.WriteLine(model2.Text); CurrentPage = page2; } void Method2(Page page1) { var model1 = (Model1) page1.BindingContext; Debug.WriteLine(model1.Text); CurrentPage = page1; } } }
    Mutasd a teljes hozzászólást!
  • Na itt lesz a legfőbb különbség. :) Nálam a View-k külön fájlokban vannak, hogy jobban átláthatóak legyenek, bár az A view így is az, a maga 1000+ sorával. :)

    <?xml version="1.0" encoding="utf-8" ?> <TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:CentralScreen.Views;assembly=CentralScreen" xmlns:system="clr-namespace:System;assembly=netstandard" x:Name="Self" x:Class="CentralScreen.Views.Main" BindingContext="{Binding Main, Source={StaticResource Locator}}"> <local:ViewA Title="A"/> <local:ViewB Title="B"/> <local:ViewC Title="C"/> </TabbedPage>
    Így meg hiába adom meg a Source-ba a Self-et a ViewA-ban, addig nem tud "felnyúlni". :(

    Ezek szerint marad az, hogy ContentPage-eket be kell másolni a TabbedPage-be. Pedig ezt szerettem volna elkerülni.
    Mutasd a teljes hozzászólást!
  • Ha külön controlokat készítesz akkor a BindableProperty lesz a barátod. Így módosul a program:

    MainPage.xaml

    <?xml version="1.0" encoding="utf-8"?> <TabbedPage x:Name="Self" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:TabbedPageDemo.Views" x:Class="TabbedPageDemo.Views.MainPage"> <TabbedPage.Children> <views:Tab1 x:Name="Tab1" TabbedPage="{x:Reference Self}" NextPage="{x:Reference Tab2}" /> <views:Tab2 x:Name="Tab2" TabbedPage="{x:Reference Self}" NextPage="{x:Reference Tab1}" /> </TabbedPage.Children> </TabbedPage>
    MainPage.xaml.cs

    using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace TabbedPageDemo.Views { [XamlCompilation(XamlCompilationOptions.Compile)] public partial class MainPage : TabbedPage { public MainPage() { InitializeComponent(); } } }
    Tab1.xaml

    <?xml version="1.0" encoding="utf-8"?> <ContentPage x:Name="Self" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:TabbedPageDemo.Views" x:Class="TabbedPageDemo.Views.Tab1"> <BindableObject.BindingContext> <views:Model1 /> </BindableObject.BindingContext> <StackLayout> <Button Text="{Binding Text}" Command="{Binding Source={x:Reference Self}, Path=Command1}" /> </StackLayout> </ContentPage>
    Tab1.xaml.cs

    using System.Diagnostics; using System.Windows.Input; using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace TabbedPageDemo.Views { public class Model1 : BindableObject { string _text = "Button name 1"; public string Text { get => _text; set { _text = value; OnPropertyChanged(); } } } [XamlCompilation(XamlCompilationOptions.Compile)] public partial class Tab1 : ContentPage { public static readonly BindableProperty TabbedPageProperty = BindableProperty.Create( nameof(TabbedPage), typeof(TabbedPage), typeof(Tab1)); public TabbedPage TabbedPage { get => (TabbedPage) GetValue(TabbedPageProperty); set => SetValue(TabbedPageProperty, value); } public static readonly BindableProperty NextPageProperty = BindableProperty.Create( nameof(NextPage), typeof(Page), typeof(Tab1)); public Page NextPage { get => (Page) GetValue(NextPageProperty); set => SetValue(NextPageProperty, value); } public ICommand Command1 { get; } public Tab1() { Command1 = new Command(Method1); InitializeComponent(); } void Method1() { var model = (Model1) BindingContext; Debug.WriteLine(model.Text); var nextModel = (Model2) NextPage.BindingContext; Debug.WriteLine(nextModel.Text); TabbedPage.CurrentPage = NextPage; } } }
    Tab2.xaml

    <?xml version="1.0" encoding="utf-8"?> <ContentPage x:Name="Self" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:TabbedPageDemo.Views" x:Class="TabbedPageDemo.Views.Tab2"> <BindableObject.BindingContext> <views:Model2 /> </BindableObject.BindingContext> <StackLayout> <Button Text="{Binding Text}" Command="{Binding Source={x:Reference Self}, Path=Command2}" /> </StackLayout> </ContentPage>
    Tab2.xaml.cs

    using System.Diagnostics; using System.Windows.Input; using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace TabbedPageDemo.Views { public class Model2 : BindableObject { string _text = "Button name 2"; public string Text { get => _text; set { _text = value; OnPropertyChanged(); } } } [XamlCompilation(XamlCompilationOptions.Compile)] public partial class Tab2 : ContentPage { public static readonly BindableProperty TabbedPageProperty = BindableProperty.Create( nameof(TabbedPage), typeof(TabbedPage), typeof(Tab2)); public TabbedPage TabbedPage { get => (TabbedPage) GetValue(TabbedPageProperty); set => SetValue(TabbedPageProperty, value); } public static readonly BindableProperty NextPageProperty = BindableProperty.Create( nameof(NextPage), typeof(Page), typeof(Tab2)); public Page NextPage { get => (Page) GetValue(NextPageProperty); set => SetValue(NextPageProperty, value); } public ICommand Command2 { get; } public Tab2() { Command2 = new Command(Method2); InitializeComponent(); } void Method2() { var model = (Model2) BindingContext; Debug.WriteLine(model.Text); var nextModel = (Model1) NextPage.BindingContext; Debug.WriteLine(nextModel.Text); TabbedPage.CurrentPage = NextPage; } } }
    Mutasd a teljes hozzászólást!
  • Köszi!

    A BindableProperty volt a megoldás.
    A NextPage propertyre végülis nem volt szükségem, a TabbedPage.GetPageByIndex(2) is megteszi helyette (fix az elemek listája, így ez is fixálható indexel).
    Mutasd a teljes hozzászólást!
Címkék
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd