Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you create Xamarin Forms class hierarchies inheriting from the 'Page' type?

In Xamarin.Forms, I'm trying to create a page that I then subclass, like this:

public partial class PageA : ContentPage {
  public PageA() {InitializeComponent ();}
}

public partial class PageB : PageA {
  public PageB() : base() { ... }
}

Both of these pages are xaml pages with code behinds, but the PageB page is not working and I'm not sure why (I'm new to XAML, Xamarin, C# and basically coding in general).

I can't compile the code at the moment, since this line:

this.FindByName<Label>

gives me a warning of:

PageB does not contain a definition for 'FindByName', and the best extension method ... requires a receiver of type 'Element'

And this line:

await Navigation.PushAsync(new PageB());

gives an error that PageB is not an Xamarin.Forms.Page. I don't know why PageA would be considered such a type, but it is.

Questions:

  1. Is it possible to create subclasses of custom pages?
  2. Why is a class that subclasses ContentPage (PageA) considered to be both of type 'Element' and of type 'Page'? And why is PageB NOT considered to be of those types?

I suspect I'm wildly off in many things here, so any corrections in how I've phrased the question and pointers to what question I SHOULD be asking are greatly welcome!

=========== EDIT

In response to a comment below:

PageA

The .cs file (codebehind) has the namespace AppName.FolderName, and the xaml has the x:Class attribute value x:Class="AppName.FolderName.PageA"

<?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="AppName.FolderName.PageA">

             ... (some elements) ...

</ContentPage>

PageB

The .cs file (codebehind) has the namespace AppName.FolderName.SubFolderName, and the xaml has the x:Class attribute value x:Class="AppName.FolderName.SubFolderName.PageB"

And I have a reference with the following using AppName.FolderName, which gives me access to the PageA class

<?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="AppName.FolderName.SubFolderName.PageB">
</ContentPage>
like image 834
Zach Smith Avatar asked Jun 30 '17 08:06

Zach Smith


2 Answers

Try this

FYI this code is from my app which is a working example

Create a base page as below

<?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="Sthotraani.Views.BasePage">

</ContentPage>

your base page cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace Sthotraani.Views
{
    public partial class BasePage : ContentPage
    {
        public BasePage()
        {
            InitializeComponent();
        }
    }
}

now derived page looks like this

<?xml version="1.0" encoding="utf-8" ?>
<views:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:views="clr-namespace:Sthotraani.Views;assembly=Sthotraani"
                x:Class="Sthotraani.Views.LoginPage"
                BackgroundColor="#009688"
                xmlns:controls="clr-namespace:Sthotraani.CustomControls;assembly=Sthotraani"
                xmlns:converters="clr-namespace:Sthotraani.Converters;assembly=Sthotraani"
                xmlns:behaviors="clr-namespace:Sthotraani.Behaviors;assembly=Sthotraani">

</views:BasePage>

derived page cs looks like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace Sthotraani.Views
{
    public partial class LoginPage : BasePage
    {
    }
}
like image 123
Krishna Avatar answered Oct 19 '22 17:10

Krishna


This is a slight variation on Krishna's excellent answer.
(I would have made it a comment, but I wanted to show the code changes clearly.)

IF BasePage does not define any elements in XAML (see Krishna's answer - <views:BasePage> has no children), THEN BasePage.xaml is not needed; simply do this in BasePage.xaml.cs:

using Xamarin.Forms;

public abstract class BasePage : ContentPage
{
    public BasePage()
    {
        // Each sub-class calls InitializeComponent(); not needed here.
    }
}

Then your sub-page must call InitializeComponent();, as you normally do in a ContentPage constructor.

I think this is preferable design, as it would be surprising to NOT see InitializeComponent(); in the derived page constructors; leaves reader wondering if it should be there but was accidentally left out. That is why I use this variation. Each page declaration looks just like a normal content page, except that it inherits from BasePage instead of ContentPage.
Trivial to change back and forth between a regular content page, and this subclass.
I create one of these by using xamarin forms template for ContentPage, then changing base class to BasePage, in both C# and XAML.

So, derived page C# becomes:

public partial class LoginPage : BasePage
{
    public LoginPage()
    {
        InitializeComponent();
    }
}

and derived page XAML is as shown in Krishna's answer.

like image 44
ToolmakerSteve Avatar answered Oct 19 '22 18:10

ToolmakerSteve