How to create custom pages in .Net Maui? - c#

I have a custom page template defined as follows :
Page1 :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Resources.Controls.Page1"
Title="Page1">
<ContentPage.ControlTemplate>
<ControlTemplate>
<Grid RowDefinitions="auto,*">
<Label Text="Label 1" Grid.Row="0">
<!-- Content of page 1 -->
<ContentPresenter Grid.Row="1" />
</Grid>
</ControlTemplate>
</ContentPage.ControlTemplate>
</ContentPage>
All the pages inheriting from Page1, have "Label 1". So this is working fine.
Now I need to create a new custom page inherting from Page1. Basically adding new elements to the template and keep what is already in Page1.
Page2 :
<?xml version="1.0" encoding="utf-8" ?>
<Controls:Page1 xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Resources.Controls.Page2"
xmlns:Controls="clr-namespace:MyApp.Resources.Controls"
Title="Page2">
<Controls:Page1.ControlTemplate>
<ControlTemplate>
<Grid RowDefinitions="auto,*" >
<Label Text="Label 2" Grid.Row="0">
<!-- Content of page 2 -->
<ContentPresenter Grid.Row="1"/>
</Grid>
</ControlTemplate>
</Controls:Page1.ControlTemplate>
</Controls:Page1>
Now the pages inheriting from Page2 don't have "Label 1". They have only "Label 2". While I'm expecting these pages to have both "Label 1" and "Label 2"
Does anyone know how to solve that please ?
Thanks.

Short version of what you can do:
Make custom control class (lets say in namespace Controls), inheriting ContentView
public class MyControl : ContentView
In ResourceDictionary, add control template, and inside it, add your VisualElements.
< ControlTemplate x:Key="MyControlTemplate" >
...
< /ControlTemplate >
In your View, add your control:
< controls:MyControl ControlTemplate="{StaticResource MyControlTemplate}" />
Where controls is:
xmlns:controls="clr-namespace:MyNamespace.Controls"
And now your user interface can be reused in every page you want.
(And bind commands/properties to it, use different templates, etc...)
Best part is that you make changes at one place, and it is changed across your whole project.

Related

Display a ToolBar in a Xamarin.Forms modal page

The "new" and recommended way to display a modal page with the Xamarin.Forms Shell uri-based navigation is to set this tag in the XAML file (source): Shell.PresentationMode="ModalAnimated"
and to navigate to it by using a standard route and invoking it with the function Shell.Current.GoToAsync("routeToMyPage").
However, this displays the modal page without a toolbar. Without Shell navigation, I would have wrapped this page in a NavigationPage, but since the pages are initialized through reflection (at least that's what it looks like - don't quote me on this), I don't know how to do that.
Adding a ToolbarItem in the page's XAML code doesn't solve this, neither does the Shell.NavBarIsVisible="True" property, and adding a Button in the Shell.TitleView tag doesn't display a toolbar either.
Is there a way to display the default navigation toolbar without rendering a custom one myself?
Here is the XAML code I used to try to have the Toolbar displayed:
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Shell.PresentationMode="ModalAnimated"
Shell.NavBarIsVisible="True"
x:Class="StackOverflow.Views.MyModalPage">
<ContentPage.ToolbarItems >
<ToolbarItem Text="Hi"/>
</ContentPage.ToolbarItems>
<Shell.TitleView>
<Button Text="Toolbar Button"/>
</Shell.TitleView>
<ContentPage.Content>
</ContentPage.Content>
</ContentPage>
Edit: I have created a small sample project to showcase my issue: https://github.com/Kuurse/StackOverflowExample
You can first create the NavigationPage root page in the app class:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
}
Then set like this in your mainpage.xaml:
<?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="StackOverflow.Views.MyModalPage"
NavigationPage.HasNavigationBar="True">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Hi"/>
</ContentPage.ToolbarItems>
</ContentPage>
By the way, do you want to display only the default navigation toolbar?

Displaying the default back button of the navigation bar of a ContentPage assigned to the Xamarin.Forms Shell

I have a ContentPage which is assigned to the Xamarin.Forms.Shell class as a ShellContent and require the back button to be displayed in the navigation bar of the ContentPage.
The XAML source of the ContentPage in concern is as follows:
<?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="UI_test.TestPage">
<Shell.NavBarIsVisible>True</Shell.NavBarIsVisible>
<Shell.BackButtonBehavior>
<BackButtonBehavior IsEnabled="True" />
</Shell.BackButtonBehavior>
<Shell.FlyoutBehavior>Disabled</Shell.FlyoutBehavior>
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
I found that that assigning a custom value to the attributes TextOverride and IconOverride of the <BackButtonBehavior> tag will display the back button, but I am looking for a way to display the platform's default back button (rather than a custom one) as the above ContentPage does not display as back button in its navigation bar as seen in the screenshot below.
Thanks in advance.
Your project seems to contain one page only, It won't appear if no navigation has been made, and it makes sense. If you do a Shell.GotoAsync(..) or Shell.Navigation.PushAsync(..) to navigate to another page it will then appears (the default native back button) allowing to go back to the previous page in the navigation stack.

Xamarin forms maps error :"Not compatable code running

I am trying to create a simple map page using Xamarin forms maps checking this project only on Andorid.
I Installed the Xamarin forms map. and added the Xaml Below,
in addition I've added the in the Android manifest XML all the relavent
premiisions and Key.
however I am getting this error:Not compatable code running the selected debug engine does not support any code executing on the current thread
would appericate any help
<?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:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
x:Class="MashamApp.mapPage" Title="מפה" >
<ContentPage.Content>
</ContentPage.Content>
<Grid>
<maps:Map x:Name="LocationMap"
IsEnabled="True" IsVisible="True"
MapType="Hybrid"
HasScrollEnabled="True"
HasZoomEnabled="True"
HeightRequest="480"
WidthRequest="480"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" >
</maps:Map>
</Grid>
As pointed out by Yuri, a content page should only have a single view or layout.
Change your page to look like this:
<?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:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
x:Class="MashamApp.mapPage" Title="מפה" >
<Grid>
<maps:Map x:Name="LocationMap"
IsEnabled="True" IsVisible="True"
MapType="Hybrid"
HasScrollEnabled="True"
HasZoomEnabled="True"
HeightRequest="480"
WidthRequest="480"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" >
</maps:Map>
</Grid>
</ContentPage>
You don't even need the Grid unless you are going to add more views inside it.
See here for more details

Detect Current Child of TabbedPage from ViewModel

I have a Xamarin Forms application with a TabbedPage that contains different Children pages. I want to be able to know which child (tab) is active from my viewmodel. So I can
The ServiceListPage.xaml looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseTabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:ABBI_XPlat_3.Pages;assembly=ABBI_XPlat_3"
x:Class="ABBI_XPlat_3.Pages.ServiceListPage"
SelectedItem="{Binding CurrentTab, Mode=TwoWay}"
Title="Control ABBIs">
<pages:BaseTabbedPage.ToolbarItems>
<ToolbarItem x:Name="DisconnectButton" Name="Disconnect" />
</pages:BaseTabbedPage.ToolbarItems>
<pages:BaseTabbedPage.Children>
<pages:ProfilesPage Title="Profiles" />
<pages:VolumePage Title="Volume" />
<pages:SensitivityPage Title="Sensitivity" />
<pages:RemoteCtrlPage Title="Remote Control" />
</pages:BaseTabbedPage.Children>
</pages:BaseTabbedPage>
All the children pages use the same viewmodel. Which I navigate to using mvvmcross:
ShowViewModel<ServiceListViewModel>(new MvxBundle(bundle));
I have tried to Bind the CurrentTab property in the viewmodel, but the setter never gets called when I change tabs.
How can I detect which Tab is active then?

Xamarin Forms: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation

I am struggling with this issue. I created just a simple cross platform page here is XAML code:
<?xml version="1.0" encoding="utf-8" ?>
<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ForTesting.TestPage">
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
<ContentPage>
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness" iOS="0,40,0,0" Android="0,40,0,0" />
</ContentPage.Padding>
</ContentPage>
</CarouselPage>
And here is same cross platform page class:
public partial class TestPage: CarouselPage
{
public TestPage()
{
InitializeComponent();
new Label
{
Text = "heelow",
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.Center
};
}
}
For testing I created simple label, but even without label it is doesn't work.
I am calling this page in my MainPage.xaml :
<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ForTesting;assembly=ForTesting"
x:Class="ForTesting.MainPage"
MasterBehavior="Popover">
<ContentPage.ToolbarItems>
<ToolbarItem x:Name="CClick"
Text="C :"
Order="Primary">
</ToolbarItem>
</ContentPage.ToolbarItems>
<MasterDetailPage.Master>
<local:MasterPage x:Name="masterPage" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<local:TestPage/>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
And on this line of class: ForTesting.MainPage.xaml.g.cs I am getting error when I am executing program:
public partial class MainPage : global::Xamarin.Forms.MasterDetailPage {
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "0.0.0.0")]
private global::Xamarin.Forms.ToolbarItem CClick;
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "0.0.0.0")]
private global::ForTesting.MasterPage masterPage;
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "0.0.0.0")]
private void InitializeComponent() {
--> this.LoadFromXaml(typeof(MainPage));
}
}
Error:
Unhandled Exception: System.Reflection.TargetInvocationException:
Exception has been thrown by the target of an invocation.
And I have another cross platform page which is same as TestPage.xaml , but it is working when I am executing.
To build upon #Wes answer, you can make the error message clearer by telling Visual Studio to automatically break at any exception:
Go to Debug > Windows > Exception Settings to open the Exception Settings window
Select the checkbox for the base exception System.Exception
Start debugging again.
In general, I've noticed that any syntax errors in XAML may show up as this exception.
You have mistake in your Carousel page
<?xml version="1.0" encoding="utf-8" ?>
<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ForTesting.TestPage">
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
<ContentPage>
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness" iOS="0,40,0,0" Android="0,40,0,0" />
</ContentPage.Padding>
</ContentPage>
</CarouselPage>
Carousel page should have only one child, and it should be a ContentPage, you won't be able to add both label and content page. Remove this line
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
If you want to have both label and content in a Carousel, I would suggest using something like CarouselView.
EDIT 1
I've create a sample Carousel project with latest Xamarin.Forms (2.2.0.31), I've tested it on iOS and Android and it works. You can use it as a starter to implement your version. I use this control in production app.

Categories