Wednesday, August 1, 2018

How can I make a Xamarin Template customizable by passing in a type parameter?

Leave a Comment

Here is the method that I have come up with so far. However it seems like not such a clean solution.

Does anyone have any suggestions how I could come up with a better solution for doing this?

<?xml version="1.0" encoding="utf-8"?> <StackLayout xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"               xmlns:local="clr-namespace:Japanese;assembly=Japanese"               x:Class="Japanese.Templates.HeaderTemplate"               x:Name="this" HorizontalOptions="FillAndExpand" Orientation="Vertical" Spacing="0" Margin="0">     <StackLayout IsVisible="{Binding HeaderType, Converter={StaticResource HeaderType1BoolConverter}, Source={x:Reference this}  }" >         <!-- code -->     </StackLayout>     <StackLayout IsVisible="{Binding HeaderType, Converter={StaticResource HeaderType2BoolConverter}, Source={x:Reference this}  }" >         <!-- code -->     </StackLayout> </StackLayout> 

In my bank end CS:

using System; using System.Collections.Generic; using Xamarin.Forms;  namespace Japanese.Templates {     public partial class HeaderTemplate : StackLayout     {         public HeaderTemplate()         {             InitializeComponent();         }     public static readonly BindableProperty HeaderTypeProperty =         BindableProperty.Create(             nameof(HeaderType),             typeof(string),             typeof(DataViewCellTemplate),             default(string));      public string HeaderType     {         get { return (string)GetValue(HeaderTypeProperty); }         set { SetValue(HeaderTypeProperty, value); }     }      } } 

Converter Code:

public class HeaderType1BoolConverter : IValueConverter {     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)     {         return object.Equals(value, "1");     }      public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)     {         throw new NotImplementedException();     } }  public class HeaderType2BoolConverter : IValueConverter {     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)     {         return object.Equals(value, "2");     }      public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)     {         throw new NotImplementedException();     } } 

In the calling code:

<template:HeaderTemplate Header="Application" HeaderType="1" /> 

2 Answers

Answers 1

Using triggers is an option.

For e.g.: You can add property-triggers to check the value on HeaderType and accordingly update the Content (or layout) in your custom control HeaderView.

Please note in this case we are extending from ContentView not StackLayout on the assumption that only one layout/control is visible at a time.

XAML

<ContentView      xmlns="http://xamarin.com/schemas/2014/forms"      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"      xmlns:local="clr-namespace:SampleApp"      x:Class="SampleApp.HeaderView">      <ContentView.Triggers>          <!-- if header type is 1, use header1 layout -->         <Trigger TargetType="local:HeaderView" Property="HeaderType" Value="1">             <Setter Property="Content">                 <Setter.Value>                     <Label Text="Header1" />                 </Setter.Value>             </Setter>         </Trigger>          <!-- if header type is 2, use header2 layout -->         <Trigger TargetType="local:HeaderView" Property="HeaderType" Value="2">             <Setter Property="Content">                 <Setter.Value>                     <StackLayout>                         <Label Text="Header2" />                         <BoxView HeightRequest="1" BackgroundColor="Gray" />                     </StackLayout>                 </Setter.Value>             </Setter>         </Trigger>          <!-- you can add more layouts here if you need -->      </ContentView.Triggers>      <!-- add default content that can be displayed in case of no match -->     <StackLayout>         <Label Text="DefaultHeader" />         <BoxView HeightRequest="1" BackgroundColor="Gray" />     </StackLayout>      </ContentView> 

Code-behind

public partial class HeaderView : ContentView {     public HeaderView()     {         InitializeComponent();      }      public static readonly BindableProperty HeaderTypeProperty =         BindableProperty.Create(             nameof(HeaderType), typeof(string), typeof(HeaderView),             defaultValue: default(string));      public string HeaderType     {         get { return (string)GetValue(HeaderTypeProperty); }         set { SetValue(HeaderTypeProperty, value); }     } } 

Usage

<local:HeaderView HeaderType="1" /> 

Answers 2

I believe that what you are looking is a ControlTemplate here is an implementation.

App.xaml

<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.App">     <Application.Resources>         <ResourceDictionary>             <ControlTemplate x:Key="Header1Template">                 <StackLayout>                     <!-- code -->                 </StackLayout>             </ControlTemplate>             <ControlTemplate x:Key="Header2Template">                 <StackLayout>                     <!-- code -->                 </StackLayout>             </ControlTemplate>         </ResourceDictionary>     </Application.Resources> </Application> 

Usage (This will make header1 your default, you can pick any of the both)

<ContentView x:Name="contentView" ControlTemplate="{StaticResource Header1Template}"> 

Now there are many ways to change the header, either by defining as the default code above or with an action which can be a button click like the example given on the link or with a propertyChange event, if you want to depend on a property to choose the header like:

public int HeaderNumber { get; set; }  protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) {     base.OnPropertyChanged(propertyName);      if (propertyName == "HeaderNumber")     {         contentView.ControlTemplate = (HeaderNumber == 1) ? Header1Template : Header2Template;     } } 

Note that i never implemented a ControlTemplate but i think this solves your problem.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment