Cannot see the Master Section in Masterdetail page of Xamarain - c#

I am trying to get into Xamarain development and I am trying to do a small App which have the login screen and when the user press the screen it will be navigated to a Dashboard Which is actually a Master Details Page
My master details Page is as follows
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MobArt.View"
x:Class="MobArt.View.MasterFrontPage">
<MasterDetailPage.Master>
<ContentPage Tittle="Menu">
<StackLayout Orientation="Vertical">
<Button Text="WF"></Button>
<Button Text="FW"></Button>
<Button Text="RO Out"></Button>
<Button Text="RO IN"></Button>
<Button Text="Loan Out"></Button>
<Button Text="Loan IN"></Button>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<local:RollScan></local:RollScan>
</MasterDetailPage.Detail>
</MasterDetailPage>
And Codebehind is just constructor
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MasterFrontPage : MasterDetailPage
{
public MasterFrontPage()
{
InitializeComponent();
}
}
And in LoginButtonclick I tried to navigate using below cODE
async void OnLoginButtonClicked(object sender, EventArgs e)
{
var Username = usernameEntry.Text;
var Password = passwordEntry.Text;
UserServices usrserv = new UserServices();
User usr = await usrserv.GetSelecteduserdataASync(Username, Password);
if(usr.User_PK!=0&& usr.UserLoc_PK!=0)
{
MasterDetailPage fpm = new MasterFrontPage();
Application.Current.MainPage = fpm;
}
}
Iam able to See the Details Section in my Page.But cannot see the Menu(Master section) when I tried for Android. Can Anyone suggest what I am missing

I am able to See the Details Section in my Page.But cannot see the Menu(Master section) when I tried for Android. Can Anyone suggest what I am missing
The Menu(Master Section) is still there, but is hidden. You can get it by swipping from the left:
But it is highly recommended using NavigationPage as the details Page:enter code here
...
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<local:RollScan />
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
...
Thus, you will have a toggle button for your menu:

Related

Scrollview control not working properly in .Net MAUI (Android)

I have created custom tab control using ScrollView control and Bindable StackLayout control.
I have first created this solution in Xamarin.Forms (VS for Mac 2019) and it works fine in both platforms, but the same solution when developed in .Net MAUI (VS for Mac 2022 Prev) it's not working properly in Android.
Update 30 Jun 2022
There is an issue with BindableLayout (StackLayout) properties in MAUI currently so when we are changing values it does not get reflected, and because of this, I think I'm facing this issue. Here is the reference
Here is what I have done so far:
MainPage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:poc_maui.ViewModels"
x:Class="poc_maui.Views.HomePage"
xmlns:tabs="clr-namespace:poc_maui.Views.SubViews"
Title="HomePage">
<ContentPage.BindingContext>
<vm:MainPageViewModel />
</ContentPage.BindingContext>
<Grid RowDefinitions="50, *" RowSpacing="0">
<ScrollView Grid.Row="0" Orientation="Horizontal" VerticalOptions="Start" HorizontalScrollBarVisibility="Never"
Scrolled="ScrollView_Scrolled">
<StackLayout x:Name="TabsView"
Orientation="Horizontal"
BindableLayout.ItemsSource="{Binding Tabs}" Spacing="0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="*, 4" RowSpacing="0">
<Label Grid.Row="0"
Text="{Binding TabTitle}"
TextColor="White"
BackgroundColor="navy"
Padding="20,0"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
FontSize="12"
HeightRequest="40"/>
<BoxView Grid.Row="1"
Color="Yellow"
IsVisible="{Binding IsSelected}"/>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.TabChangedCommand,
Source={x:Reference TabsView}}"
CommandParameter="{Binding .}"/>
</Grid.GestureRecognizers>
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
<tabs:ParentRecordTabView Grid.Row="1" IsVisible="{Binding IsParentRecordTabVisible}"
VerticalOptions="FillAndExpand"/>
<tabs:AdditionalInfoTabView Grid.Row="1" IsVisible="{Binding IsAdditionalInfoTabVisible}"
VerticalOptions="FillAndExpand" />
</Grid>
</ContentPage>
MainPageViewModel
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;
using poc_maui.Models;
namespace poc_maui.ViewModels
{
public class MainPageViewModel : BaseViewModel
{
#region Constructor
public MainPageViewModel()
{
GetTabs();
}
#endregion
#region Private Properties
private bool _isParentRecordTabVisible = true;
private bool _isAdditionalInfoTabVisible;
private ObservableCollection<TabViewModel> _tabs { get; set; }
#endregion
#region Public Properties
public bool IsParentRecordTabVisible
{
get => _isParentRecordTabVisible;
set { _isParentRecordTabVisible = value; OnPropertyChanged(nameof(IsParentRecordTabVisible)); }
}
public bool IsAdditionalInfoTabVisible
{
get => _isAdditionalInfoTabVisible;
set { _isAdditionalInfoTabVisible = value; OnPropertyChanged(nameof(IsAdditionalInfoTabVisible)); }
}
public ObservableCollection<TabViewModel> Tabs
{
get => _tabs;
set { _tabs = value; OnPropertyChanged(nameof(Tabs)); }
}
#endregion
#region Commands
public ICommand TabChangedCommand { get { return new Command<TabViewModel>(ChangeTabClick); } }
#endregion
#region Private Methods
private void GetTabs()
{
Tabs = new ObservableCollection<TabViewModel>();
Tabs.Add(new TabViewModel { TabId = 1, IsSelected = true, TabTitle = "Parent record" });
Tabs.Add(new TabViewModel { TabId = 2, TabTitle = "Additional Info" });
Tabs.Add(new TabViewModel { TabId = 3, TabTitle = "Contacts" });
Tabs.Add(new TabViewModel { TabId = 4, TabTitle = "Previous inspections" });
Tabs.Add(new TabViewModel { TabId = 5, TabTitle = "Attachments" });
SelectedTab = Tabs.FirstOrDefault();
}
private void ChangeTabClick(TabViewModel tab)
{
try
{
var tabs = new ObservableCollection<TabViewModel>(Tabs);
foreach (var item in tabs)
{
if (item.TabId == tab.TabId)
{
item.IsSelected = true;
}
else
{
item.IsSelected = false;
}
}
Tabs.Clear();
Tabs = new ObservableCollection<TabViewModel>(tabs);
switch (tab.TabId)
{
case 1:
IsParentRecordTabVisible = true;
IsAdditionalInfoTabVisible = false;
break;
case 2:
IsParentRecordTabVisible = false;
IsAdditionalInfoTabVisible = true;
break;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
#endregion
}
}
#ParentTabView.xaml
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="poc_maui.Views.SubViews.ParentTabView">
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" >
<Label
Text="Welcome to Parent tab!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentView>
#AdditionalInfoTabView.xaml
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="poc_maui.Views.SubViews.AdditionalInfoTabView">
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" >
<Label
Text="Welcome to Additiona info tab!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentView>
So what happens here in Android is when I'm clicking AdditionalInfo Tab then it will show a blank white screen and if you press the hardware back button and open the app again it will show AdditionalTab as selected and its views content as well.
If I remove switch() code part from the ViewModel then it will work fine but tabs will not change. Does anyone have idea about this kind of behavior of scroll view in MAUI?
The full source code is here: maui_sample
Does this work-around fix it?
MainPage.xaml:
<ScrollView x:Name "theScrollView" ... >
MainPage.xaml.cs:
public MainPage()
{
InitializeComponent();
MessagingCenter.Subscribe<MainPageViewModel>(this, "update", (sender) =>
{
// Tell theScrollView to re-layout its contents.
(theScrollView as IView).InvalidateArrange();
});
}
MainPageViewModel:
private void ChangeTabClick(TabViewModel tab)
{
... make changes ...
MessagingCenter.Send<MainPageViewModel>(this, "update");
}
MAYBE:
I'm not sure if MessagingCenter Subscribe is on Dispatcher (Main) thread. To be reliable, do:
MessagingCenter.Subscribe<MainPageViewModel>(this, "update", (sender) =>
{
Dispatcher.Dispatch( () =>
{
(theScrollView as IView).InvalidateArrange();
});
}
UPDATE
There are other Maui bugs, that have a common "theme": Maui on Android does "something" related to layout only once - at the time the page is first drawn. UNFORTUNATELY, anything that is "not visible" at that time, is skipped. And won't work when later made visible.
Until such bugs are fixed, you'll have to do some work-around.
WORK-AROUND #1:
Start with ALL tabs IsVisible="True".
As soon as the page has been drawn the first time, in code-behind, create the desired Bindings on those IsVisible properties. Page drawn first time can be intercepted in a custom handler. But this is a temp work-around, so its easier to just run a method after a 250 ms delay. Use a boolean "flag" to make the method only run the first time.
Might have to do InvalidateArrange as shown above, to force the Bindings to function the first time.
OR WORK-AROUND #2:
Each time tab changes, use shell route to go to MainPage again. Keep same view model, so knows which tab to show first (and remembers any other state you care about).
Both of these are ugly.
I recommend creating an issue at .Net Maui github, and providing link to your github sample.
This is still not works for me properly but after looking at below two links I found that it it not what we are looking for. The Isvisible : false first and then on switch or check box change you are trying to make it visible then it will not visible but the actual control visible. So on look after I have see this link but again the answer is not what I was looking for.
Step to resolve.
On View use the Parent as ScrollView or control belongs to IView,IElement.
<ScrollView x:Name "myScrollView">
.....
...
Add Action on ViewModel
public delegate void Action(T obj);
Invoke the Action
Note: Make sure you call this on require not all the time.
e.g. On Visibility set in ViewModel call after visibility update.
MeasureAction?.Invoke("reSetVisibility");
Now on View's Code File, use Viewmodel and accept the invoke
Here Call the below line will works perfectly.
(myScrollView as IView).InvalidateMeasure();
That's IT... Enjoy IsVisible now and make your layout as require.

Xamarin UWP + Android ContentPage Navigation PushAsync

I'm converting an UWP application to Xamarin in the aim to use it on both Android and Windows devices.
I never used Xamarin before and I assume i'm doing a beginer mistake.
On my MainPage everything is OK :
But when I'm clicking on the "Options" Button it didn't load a new page exept a grey banner in the upper part of the window :
To navigate from one page to another I followed this explanation : Microsoft doc navigation
There's my code to change page in the MainPage.xaml.cs :
async void ButtonOptions_Click(object sender, EventArgs args)
{
try
{
button_options.Source = "Assets/Option_Icon_1.png";
Application.Current.MainPage = new NavigationPage(new MainPage());
var OptionsView = new OptionsView();
await Device.InvokeOnMainThreadAsync(() => Navigation.PushAsync(OptionsView, true));
//this.Frame.Navigate(typeof(StorageView1));
}
catch (Exception ex) { InterpretException("MainPage.ButtonStorage_Click()", ex); }
}
And my OptionsView.xaml :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Stock_Manager_Xamarin.OptionsView"
Title="Second Page">
<ContentPage.Content>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Label Text="Name:" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" />
</StackLayout>
<Button x:Name="navigateButton" Text="Previous Page"/>
</StackLayout>
</ContentPage.Content>
I tried different version of the xaml code without any change and I can't find a working sample.
Could someone can explain me where I'm doing a mistake ?
Wrap current page inside navigation stack in App.cs, and set it as MainPage, so that we can do the navigation operation .
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
As Jason mentioned , it is no need to set MainPage again , just navigate directly , modify your code as below .
void ButtonOptions_Click(object sender, EventArgs args)
{
try
{
button_options.Source = "Assets/Option_Icon_1.png";
var OptionsView = new OptionsView();
Navigation.PushAsync(OptionsView, true);
}
catch (Exception ex) { InterpretException("MainPage.ButtonStorage_Click()", ex); }
}

How to call a function that's in MainPage.xaml.cs from App.xaml.cs

I am building a language translator application. I am using an API to get all the languages that the user can translate their input into and storing them in a picker. Currently, I am trying to retrieve and load all the languages into the picker once the application starts. I have tried implementing the OnStartUp function in App.xaml.cs by doing the following:
App.xaml.cs
protected override void OnStart()
{
var mainPage = new MainPage();
this.MainPage = mainPage;
mainPage.getLanguages();
}
MainPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:LanguageTranslator"
x:Class="LanguageTranslator.MainPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
.......
<StackLayout x:Name="slLanguages" Grid.Row="5" Orientation="Horizontal" HorizontalOptions="Center" Margin="3, 6, 3, 3">
<Label Text="Languages: " />
<Picker x:Name="pckLanguages">
<Picker.Items>
</Picker.Items>
<Picker.SelectedIndex>1</Picker.SelectedIndex>
</Picker>
</StackLayout>
</Grid>
</ContentPage>
MainPage.xaml.cs
public void getLanguages()
{
#region Load all available languages into the picker 'pckLangugages'
// Fills the picker 'pckLanguages' with all available langauges when the main page is loaded
var serverResponse = Request(string.Format(ApiSetup.getLanguages, ApiSetup.APIKey, lblSourceLanguage.Text));
var dictionary = JsonConvert.DeserializeObject<IDictionary>(serverResponse.Content); // Converts the server response into JSON format
foreach (DictionaryEntry dictionaryEntry in dictionary)
{
if (dictionaryEntry.Key.Equals("langs"))
{
var languages = (JObject)dictionaryEntry.Value;
LanguagesList = new List<string>();
pckLanguages.Items.Clear();
foreach (var lang in languages)
{
if (!lang.Equals(lblSourceLanguage.Text))
{
pckLanguages.Items.Add(lang.Value.ToString());
LanguagesList.Add(lang.Key);
}
}
}
}
(Request is a function that sets up a RestSharp client and request. ApiSetup is a class that handles the API side of things - getting all available languages, detecting source language, etc.pckLanguages is a picker in MainPage.xaml that allows the user to choose a language to which they can translate their entered text into).
While OnStartUp does seem to get called (if I Debug.Write something, it will get printed to the console). I have also tried using OnAppearing but to no avail:
protected override void OnAppearing()
{
getLanguages();
}
I have also tried using a loaded event but the property 'Loaded' was not found on StackPanel.
If anyone has any ideas of a good way to solve this and/or knows what I'm doing wrong, it'd be much appreciated.
Possibly the easiest thing would be to create a static class. You would have a method in this class where you would store this data in a static field. It would be available everywhere where you use this class.

How to convert XAML to pure C#?

I have page in XAML and need it in pure C#. But can't figure out how to convert it.
<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="xmr_cross_test.Navigation.MDPage">
<MasterDetailPage.Master>
<ContentPage Title="Menu">
<StackLayout Orientation="Vertical">
<ListView x:Name="navigationDrawerList"
RowHeight="60"
SeparatorVisibility="None"
ItemSelected="OnMenuItemSelected">
</ListView>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
How to do so keeping binding and ability to change MasterDetailPage.Detail?
I had to remove ListView.ItemTemplate declaration as SO doesn't allow me to post so big amount of code. Guess it won't be too hard to figure out after I get answer.
MasterDetailPage mdp = new MasterDetailPage();
ContentPage master = new ContentPage { Title = "Menu" };
StackLayout menu = new StackLayout();
ListView menuList = new ListView() { RowHeight = 60 };
menuList.ItemSelected += OnMenuItemSelected;
ContentPage detail = new ContentPage();
menu.Children.Add(menuList);
master.Content = menu;
mdp.Master = master;
mdp.Detail = new NavigationPage(detail);

How to access StackLayout from the backend?

I have been using Xamarin Forms to develop iOS and Android applications. I want to access a StackLayout that is within a TabbedPage so I can make it visible or hidden whenever the user changes tabs, but when I try to access the StackLayout I get "This does not exist in the current context". Here is my XAML code and my CS code.
CS
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace DebuggerTestAndroidIOS
{
public partial class PatientTabPage : TabbedPage
{
public PatientTabPage ()
{
InitializeComponent ();
ItemsSource = PatientDataModel.tabs;
//vitalSignsStack.IsVisible = true;
this.CurrentPageChanged += (object sender, EventArgs e) => {
var i = this.Children.IndexOf(this.CurrentPage);
System.Diagnostics.Debug.WriteLine("Page No:"+i);
if (i == 1){
vitalSignsStack.IsVisible = true;
}
};
}
}
}
XAML
<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DebuggerTestAndroidIOS.PatientTabPage">
<TabbedPage.ItemTemplate>
<DataTemplate>
<ContentPage Title ="{Binding TabName}">
<!--Parent Wrapper layout-->
<StackLayout Orientation="Vertical" BackgroundColor="White">
<StackLayout x:Name="vitalSignsStack" Orientation="Horizontal" IsVisible="false">
<Image Source="VitalSigns.png" HorizontalOptions="Center"/>
</StackLayout>
</StackLayout><!--End parent wrapper-->
</ContentPage>
</DataTemplate>
</TabbedPage.ItemTemplate>
</TabbedPage>
An element is only going to be accesible within the context of the page that created it - in this case, the ContentPage.
If you want to reach it from outside of the ContentPage, you will need to add a public method or property to the ContentPage that exposes it.
You cannot access a control inside a DataTemplate with its name. The problem is, that it will be repeated and so this name would exist multiple times, what is not allowed.
But why don't you create a new Page like this:
public partial class PatientTabContentPage : TabbedPage
{
public PatientTabContentPage ()
{
InitializeComponent ();
}
public HideVitalSignsStack(bool true){
vitalSignsStack.IsVisible = true;
}
}
And change DataTemplate to
<DataTemplate>
<PatientTabContentPage Title ="{Binding TabName}">
</DataTemplate>
Then hide the stackpanel with
this.CurrentPageChanged += (object sender, EventArgs e) => {
var page = CurrentPage as PatientTabContentPage;
var i = this.Children.IndexOf(this.CurrentPage);
System.Diagnostics.Debug.WriteLine("Page No:"+i);
if (i == 1){
page.HideVvitalSignsStack(true);
}
};
Thanks for your efforts. I tried them, still was not able to access the StackLayouts. I modified a little bit my code, this helped a lot and made everything easier: Creating different layouts for each tab

Categories

Resources