Search code examples
c#xamlxamarinxamarin.formstelerik

How to add Parameters in ControlTemplate xamarin forms


I have a template for HeaderItem with the imageSource in it, so all tabs have the same image. How can I bring an additional parameter to use different images?

Template

        <ControlTemplate x:Key="HeaderControlTemplate">
        <Grid HorizontalOptions="FillAndExpand">

            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Image Source="{converters:ImageResource Media.logo-pp.png}" Grid.Row="0" WidthRequest="25" />
            <Label Grid.Row="1" Text="{TemplateBinding Text}" HorizontalTextAlignment="Center" StyleClass="tabViewHeaderTextColor"/>
            <BoxView Grid.Row="2" IsVisible="{TemplateBinding IsSelected}"
                        StyleClass="tabViewHeaderBgColor"
                         HorizontalOptions="Fill"
                         HeightRequest="2" />
        </Grid>
    </ControlTemplate>

Tabs

 <telerikPrimitives:RadTabView>
                    <telerikPrimitives:RadTabView.Items>
                        <telerikPrimitives:TabViewItem>
                            <telerikPrimitives:TabViewItem.Header>
                                <telerikPrimitives:TabViewHeaderItem Text="1" ControlTemplate="{StaticResource HeaderControlTemplate}"/>
                            </telerikPrimitives:TabViewItem.Header>
                            <telerikPrimitives:TabViewItem.Content>
                                        //SomeContent
                            </telerikPrimitives:TabViewItem.Content>
                        </telerikPrimitives:TabViewItem>

                        <telerikPrimitives:TabViewItem>
                            <telerikPrimitives:TabViewItem.Header>
                                <telerikPrimitives:TabViewHeaderItem Text="2" ControlTemplate="{StaticResource HeaderControlTemplate}"/>
                            </telerikPrimitives:TabViewItem.Header>
                            <telerikPrimitives:TabViewItem.Content>
                                        //SomeContent
                            </telerikPrimitives:TabViewItem.Content>
                        </telerikPrimitives:TabViewItem>

                        <telerikPrimitives:TabViewItem>
                            <telerikPrimitives:TabViewItem.Header>
                                <telerikPrimitives:TabViewHeaderItem Text="3" ControlTemplate="{StaticResource HeaderControlTemplate}"/>
                            </telerikPrimitives:TabViewItem.Header>
                            <telerikPrimitives:TabViewItem.Content>
                                        //SomeContent
                            </telerikPrimitives:TabViewItem.Content>
                        </telerikPrimitives:TabViewItem>
                     <telerikPrimitives:RadTabView>

TabViewHeaderItem also doesn't include the Image Source. So I don't know how to solve this. Sure I can do 3 templates, but it's not what i want.


Solution

  • I assume that Media.logo-pp.png is one of the 3 images you want to show. You could use the following trick to avoid duplicating templates:

    First of all create a converter that will convert the tab name into the target image.

    public class TabToImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {   
            string imageName;         
            switch (value.ToString())
            {
                case "1":
                    imageName= "logo-pp.png"
                    break;
                case "2":
                    imageName= "logo-pp2.png"
                    break;
                case "3":
                    imageName= "logo-pp3.png"
                    break;
                default:
                    imageName= "logo-pp.png"
                    break;
            }
            return ImageSource.FromResource($"Media.{imageName}", this.GetType().GetTypeInfo().Assembly);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    Then change your template definition as follow:

    1. add a new namespace for your converter class:

    xmlns:converters="clr-namespace:Metadia.Converters"

    1. add a static resource and reference the above converter

    <ResourceDictionary> <converters:TabToImageConverter x:Key="TabToImage" />

    1. add a name to the label so it can be referenced

    2. add binding to image source using the label's Text property and the converter

          <Grid.RowDefinitions>
              <RowDefinition Height="Auto"/>
              <RowDefinition Height="Auto"/>
              <RowDefinition Height="Auto"/>
          </Grid.RowDefinitions>
          <Image Source="{TemplateBinding Source={x:Reference tabTitle}, Path=Text, Converter={StaticResource {TabToImage}}" Grid.Row="0" WidthRequest="25" />
          <Label x:Name="tabTitle" Grid.Row="1" Text="{TemplateBinding Text}" HorizontalTextAlignment="Center" StyleClass="tabViewHeaderTextColor"/>
          <BoxView Grid.Row="2" IsVisible="{TemplateBinding IsSelected}"
                      StyleClass="tabViewHeaderBgColor"
                       HorizontalOptions="Fill"
                       HeightRequest="2" />
      </Grid>
      

    Et voilà!

    Note that if you rename the images the same as the tabs text, the converter could simply return (if not null):

    return ImageSource.FromResource($"Media.{value.ToString()}", this.GetType().GetTypeInfo().Assembly);
    

    Hope this helps & happy coding!