Xamarin Forms QueryParameter Being Ignored - c#

I have a shell app and I want to navigate from one page to another. I have followed the documentation and turotials step by step but for some reason the QueryParameter is being ignored(Since the Init method is not being called). Am I missing something?
First Page:
List<int> rowColumn = Methods.GetGridRowColumn((Frame)s);
HomeTab homeTab = dict[rowColumn[0]+""+rowColumn[1]];
var content = JsonConvert.SerializeObject(homeTab);
await Shell.Current.GoToAsync($"{nameof(CategoriesPage)}?homeTab={content}");
Page to navigate:
[XamlCompilation(XamlCompilationOptions.Compile)]
[QueryProperty(nameof(HomeTab), "homeTab")]
public partial class CategoriesPage : ContentPage
{
private HomeTab homeTab;
public string HomeTab
{
set
{
string content = Uri.UnescapeDataString(value);
homeTab = JsonConvert.DeserializeObject<HomeTab>(content);
Init();
}
}
public CategoriesPage()
{
InitializeComponent();
}
}

Related

How to pass parameters with shell navigation before binding

I am writing a program using Xamarin, Shell and MVVM.I want to send a parameter to next page and I am using the following code:
await Shell.Current.GoToAsync($"//{nameof(CopyBooksPage)}?RegisteredUserId={registeredUser.Id}");
Question: How to get the parameter before binding?
First wrong solution:
In CopyBooksPage.xaml I have binding to properties in VM but I have no affiliation with the VM.
I do this:
[XamlCompilation(XamlCompilationOptions.Compile)]
[QueryProperty(nameof(RegisteredUserId), "RegisteredUserId")]
public partial class CopyBooksPage : ContentPage
{
private int _registeredUserId;
public int RegisteredUserId
{
get { return _registeredUserId; }
set
{
_registeredUserId = value;
CopyBooksViewModel copyBooksViewModel = App.GetViewModel<CopyBooksViewModel>();
copyBooksViewModel.RegisteredUserId = _registeredUserId;
BindingContext = copyBooksViewModel;
copyBooksViewModel.RefreshBinding();
}
}
public CopyBooksPage()
{
InitializeComponent();
}
}
Call order:
construktor
properties RegisteredUserId
The problem is twofold.
After calling the constructor, I get information about binding errors (because there is no VM). It's not annoying but I want (need) to get rid of it.
I do the binding only in the propertis and this causes the problem that for each VM propertis I have to call the OnPropertyChanged method to refresh the binding. And this is troublesome for me. I do not want to do it.
Second wrong solution
Code behind:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CopyBooksPage : ContentPage
{
public CopyBooksPage()
{
InitializeComponent();
BindingContext = App.GetViewModel<CopyBooksViewModel>();
}
}
ViewModel:
class CopyBooksViewModel : BaseViewModel, IQueryAttributable
{
private int registeredUserId;
//read from database
private CopyBook copyBookModel;
public string BookTitle
{
get { return copyBookModel.Title; }
set
{
copyBookModel.Title = value;
OnPropertyChanged(nameof(Title));
}
}
public CopyBooksViewModel()
{
}
public void ApplyQueryAttributes(IDictionary<string, string> query)
{
if (query.ContainsKey("RegisteredUserId"))
{
registeredUserId = int.Parse(HttpUtility.UrlDecode(query["RegisteredUserId"]));
copyBookModel = ReadFromDatabase(registeredUserId);
}
}
}
Call order:
construktor
Binding
method ApplyQueryAttributes
When binding the BookTitle, I reference the copyBookModel which is null. I could secure it.
The problem is that the ApplyQueryAttributes method is called last. In it again I would have to call OnPropertyChanged for all propertis. I do not want to do it.

How to open an instance of another or of itself from the current page

I created WPF on the MVVM principle, but I can't make it possible to open another one from the current page.
I followed this example
We need something like this:
Example
It is also worth considering that a page instance should be created. (That is, so that you can open yourself from Page 2, but with a different name)
My failed attempt:
Page 2 ViewModel
public Page2ViewModel()
{
ButtonCommand = new RelayCommand(o => LoadOtherView());
}
public string Title { get; set; } = "Page2";
public string Text { get; set; } = "Page two";
public ICommand ButtonCommand { get; set; }
private void MainButtonClick(object sender)
{
//MainViewModel main = new MainViewModel();
//main.SelectedPageViewModel = main.PageViewModels[0];
//main.SelectedPageViewModel.Title = "да";
//main.SelectedPageViewModel.Text = "Первая страница";
}
private void LoadOtherView()
{
// Instead of interacting with a whole ViewModel, we just use the interface
//_pageDisplay.ChangePageCommand.Execute(new ContactViewModel());
_pageDisplay.ChangeViewModel(_listPageViewModels[0]);
}
Interfaces
namespace WpfMVVMCore.Interfaces
{
public interface IPageDisplay
{
public IPageViewModel GetCurrentPage();
public IList<IPageViewModel> ListPageViewModels();
public void ChangeViewModel(IPageViewModel newPage);
}
}
MainViewModel
public MainViewModel(IPageDisplay pageDisplay, IList<IPageViewModel> ListPageViewModels)
{
_pageDisplay = pageDisplay;
_pageViewModels = ListPageViewModels;
}
public IPageViewModel GetCurrentPage()
{
return _selectedPageViewModel;
}
public void ChangeViewModel(IPageViewModel newPage)
{
this.SelectedPageViewModel = newPage;
}
public IList<IPageViewModel> ListPageViewModels()
{
return _pageViewModels;
}
** If the information provided by me is not enough for you, you can download this project (with my unsuccessful attempt 🤭 ):download**
P.S. Please do not criticize me if it is not difficult for you. I'm new to MVVM. Better help :)

Why doesn't navigation work for me after calling Navigation.InsertPageBefore() in Xamarin Forms?

I'm trying to implement logging in on Xamarin Forms (5.0.0, using ActiveDirectory's built in Login page). Any ideas on how to make this work?
In the constructor of App.xaml.cs, I have:
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new LoginPage());
}
I implement the Login page w/ a view model, in which I pass in a callback that should (according to the documentation), set my navigation root to my HomePage:
public partial class LoginPage : ContentPage
{
private async Task _handleLoginAsync()
{
Navigation.InsertPageBefore(new HomePage(), this);
await Navigation.PopAsync();
}
public LoginPage()
{
InitializeComponent();
BindingContext = new LoginPageViewModel(_handleLoginAsync);
}
}
In the view model, I try to login using Device.BeginInvokeOnMainThread, calling my(note, I didn't include login logic for brevity/cleanliness)
public Command LoginCommand => new Command(LoginUsingAzureAsync);
private Func<Task>_handleLoginAsync;
public LoginPageViewModel(Func<Task> handleLoginAsync)
{
_handleLoginAsync = handleLoginAsync;
LoginCommand.Execute(null);
}
internal void LoginUsingAzureAsync()
{
Device.BeginInvokeOnMainThread(async () =>
{
try
{
if (await Login()) == true)
{
UserDialogs.Instance.HideLoading();
await _handleLoginAsync();
return;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
UserDialogs.Instance.Alert("The login has failed.");
}
});
}
It successfully goes to the homepage, but navigating to other pages afterwards doesn't work. When I call the following, it enters the OtherPage() constructor, but fails to render the new page.
Navigation.PushAsync(new OtherPage());
Note, the navigation works as expected if I use PushAsync(new HomePage()) rather than removing the login, but I'd prefer to remove the login page from the navigation stack.
Thanks in advance!
Update: Here's the initial HomeViewModel:
public class HomeViewModel
{
private readonly INavigation _navigation;
public Command GoToOtherPageCommand => new Command(GoToOtherPage);
public async void GoToOtherPage()
{
await App.Navigation.PushAsync(new OtherPage());
}
}
The problem wasn't in the login, it was in the HomePageViewModel, which was initially referencing App.Navigation (see update in question).
Passing in the navigation into my ViewModel did the trick:
public class HomeViewModel
{
private readonly INavigation _navigation;
public Command GoToOtherPageCommand => new Command(GoToOtherPage);
public async void GoToOtherPage()
{
await _navigation.PushAsync(new OtherPage());
}
public HomeViewModel(INavigation navigation)
{
_navigation = navigation;
}
}
public partial class HomePage : ContentPage
{
public HomePage()
{
InitializeComponent();
BindingContext = new HomeViewModel(Navigation);
}
}

Xamarin forms : bug in master detail Page

I have a bug in my Xamarin Forms app. When I was coding page to appear content "master-detail" when the user chose on the last page. The content doesn't appear.
During debugging, the app work without any code errors; however, it appears without any content. I am using the Firebase database.
Firebase helper:
public async Task<List<Cuts>> GetAction()
{
return (await firebase
.Child("Action")
.OnceAsync<Cuts>()).Select(item => new Cuts
{
name = item.Object.name,
link = item.Object.link,
poster = item.Object.poster
}).ToList();
}
The page which the users choose from:
public partial class ActionFilms : ContentPage
{
FirebaseHelper firebaseHelper = new FirebaseHelper();
public ActionFilms()
{
InitializeComponent();
}
protected async override void OnAppearing()
{
base.OnAppearing();
var allPersons = await firebaseHelper.GetAction();
act.ItemsSource = allPersons;
}
public void act_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var acctionn = e.PreviousSelection as Cuts;
App.Current.MainPage.Navigation.PushAsync(new ActionMaster(acctionn));
}
}
The code of master-detail Page "which the content does not appear at here":
public partial class ActionMaster : ContentPage
{
public ActionMaster(Cuts acctionn)
{
BindingContext = acctionn;
InitializeComponent();
}
}

Xamarin.Forms Navigate to another page using ViewModel

I have several ContentPages and I want to navigate from one to another at the click of an element in the page. I have my ViewModel class:
class JumpVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private INavigation _navigation;
public ICommand NewPage
{
get
{
return new Command(async () =>
{
await _navigation.PushAsync(new MySettingsPage());
});
}
}
public JumpVM() { }
public JumpVM(INavigation navitation)
{
_navigation = navitation;
}
}
And this is one of my pages( for the sake of space, i put only the relevant code):
BindingContext = new JumpVM(this.Navigation);
....
Image fbInvite = new Image
{
Source = ImageSource.FromResource(Constants.ASSETLOCATION + ".facebookInviteIcon.png"),
HorizontalOptions = LayoutOptions.Center
};
fbInvite.GestureRecognizers.Add(new TapGestureRecognizer(sender =>
{
//navigation in the method below
FaceboonInviteFriends();
fbInvite.Opacity = 0.8;
fbInvite.FadeTo(1);
}));
I want when I click the image, to execute the Command in the JumpVM class and navigate to the page there. How can I do that?
This is Answer for Navigating one page to another page in ViewModel concept.
public ICommand NavigationList { get; set; }
NavigationList = new Command(GetListview);
public void GetListview()
{
Xamarin.Forms.Application.Current.MainPage.Navigation.PushAsync(new ListViewPerson());
}
Try adding the following line after the FadeTo line:
((JumpVM)BindingContext).NewPage.Execute(null).
If you are using ViewModels you can implement this easily with ICommand.
namespace YourApp.ViewModels
{
public class CurrentPageViewModel
{
public ICommand BackToPage {get; private set; }
public CurrentPageViewModel()
{
BackToPage = new Command(async () => {
await Application.Current.MainPage.Navigation.PushModalAsync(new MainPage());
});
}
}
}
And in the ViewModel of the page that you want to go, you need to implement the PopAsync as follows.
namespace YourApp.ViewModels
{
public class MainPageViewModel
{
public ICommand BackToMain { get; private set; }
public MainPageViewModel()
{
BackToMain = new Command(async () => {
await Application.Current.MainPage.Navigation.PopAsync();
});
}
}
}
Also remember to use the Bindings at your Views CodeBehind on both the current page and that you want to go the like this.
namespace RealmApp1.Views
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageViewModel();
}
}
}
Hope it works for you!
Have A Nice Code!!!

Categories

Resources