tabview MAUI

3 Answers 1466 Views
TabView
Palmsenser
Top achievements
Rank 1
Palmsenser asked on 10 Feb 2022, 11:32 AM

Hallo,

I would like to use MAUI TabView. How to do the style (incl. icon like. e.g. Segoe MDL2 Assets icons) for HeaderText?

Is there any DataTemplate for the HeaderText? How to do the Binding for HeaderText?

Is it possible to load the add the "new Tab" and "Tab content" dynamically?

 

Regards,

JT

3 Answers, 1 is accepted

Sort by
0
Accepted
Palmsenser
Top achievements
Rank 1
answered on 18 Feb 2022, 07:23 PM

Hi,

I tried "ControlTemplate", based on https://docs.telerik.com/devtools/xamarin/controls/tabview/tabview-header-item#default-tabviewheaderitem-controltemplate It works, except the "BoxView" which is not showed after selecting its/other "Tab".

If I hard-coded "IsSelected="True"" inside each tabs: e.g. "<telerik:TabViewItem HeaderText="t2" IsSelected="True">" It will work, but It is not supposed to hard-coded ""IsSelected="True""" inside every tabs by default.

Any ideal?

Following xaml code:

 <telerik:RadTabView x:Name="PlotDataTabView" GridLayout.Row="0" >
                <telerik:RadTabView.HeaderItemTemplate>
                    <ControlTemplate>
                        <Grid BackgroundColor="Transparent" HeightRequest="50">                            
                            <StackLayout Orientation="Horizontal" Margin="10, 5, 10, 8" HorizontalOptions="Center" >                                
                                <Label Text="{TemplateBinding Text}"
                                       FontSize="15" FontFamily="SegMDL2"
                                       HorizontalTextAlignment="Center"
                                       TextColor="{TemplateBinding IsSelected, Converter={StaticResource TabHeaderTextColor} }"
                                       VerticalOptions="Center">
                                </Label>                                
                            </StackLayout>
                            <BoxView IsVisible="{TemplateBinding IsSelected, Converter={StaticResource TabSelectedLineColor}}"
                                     BackgroundColor="#0090C9"
                                     VerticalOptions="End"
                                     HeightRequest="5"/>
                        </Grid>
                    </ControlTemplate>
                </telerik:RadTabView.HeaderItemTemplate>

                <telerik:TabViewItem HeaderText="t1" >
                    <Label Text="tab 1"/>         
                </telerik:TabViewItem>                
                <telerik:TabViewItem HeaderText="t2" >
                    <Label Text="Tab 2"/>
                </telerik:TabViewItem>
                <telerik:TabViewItem HeaderText="t3 >
                    <Label Text="Tab 3"/>
                </telerik:TabViewItem>

            </telerik:RadTabView>   
Ivan
Telerik team
commented on 21 Feb 2022, 11:06 AM

Hello Jun,

I am not quite certain why the above code is not working, as I do not have the implementations of the TabHeaderTextColor and the TabSelectedLineColor converters. A wild speculation is that you are binding the result of the TabSelectedLineColor converter to the IsVisible property, which is of type bool, not Color.

As I have mentioned in my previous post, the new TabView control is a complete rewrite, so the documentation form Xamarin.Forms might not be relevant in all cases. To help you out, I have created a small demo application, which overrides the default Style and ControlTemplate of the header items.

The important part here is you can take advantage of the VisualStateManager to style the header items, based on their state:

 

<Style x:Key="HeaderItemStyle" TargetType="telerikMauiControls:TabViewHeaderItem">
    <Setter Property="ContentPadding" Value="10" />
    <Setter Property="TextColor" Value="Black" />
    <Setter Property="FontFamily" Value="SegoeMDL2Assets" />
    <Setter Property="FontSize" Value="24" />
    <Setter Property="HorizontalTextAlignment" Value="Center" />
    <Setter Property="VerticalTextAlignment" Value="Center" />
    <Setter Property="BorderColor" Value="Transparent" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup Name="CommonStates">
                <VisualState Name="Normal" />
                <VisualState Name="Disabled">
                    <VisualState.Setters>
                        <Setter Property="TextColor" Value="DarkGray" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState Name="Selected">
                    <VisualState.Setters>
                        <Setter Property="TextColor" Value="MediumBlue" />
                        <Setter Property="BorderColor" Value="MediumBlue" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

 

We simply style the header items for the default (Normal) state and then override the values of some properties for the other states (Disabled, Selected etc.). This is very convenient, as we do not have to resort to custom logic and converters for each property. Also, such approach eliminates the necessity to override the ControlTemplate in many cases. Of course, nothing stops us from redefining the ControlTemplate for our needs:

 

<ControlTemplate x:Key="HeaderItemTemplate">
    <VerticalStackLayout>
        <Label Text="{TemplateBinding Text}"
                Margin="{TemplateBinding ContentPadding}"
                TextColor="{TemplateBinding TextColor}"
                FontFamily="{TemplateBinding FontFamily}"
                FontSize="{TemplateBinding FontSize}"
                FontAttributes="{TemplateBinding FontAttributes}"
                TextDecorations="{TemplateBinding TextDecorations}"
                HorizontalTextAlignment="{TemplateBinding HorizontalTextAlignment}"
                VerticalTextAlignment="{TemplateBinding VerticalTextAlignment}" />
        <BoxView HeightRequest="4"
                    BackgroundColor="{TemplateBinding BorderColor}" />
    </VerticalStackLayout>
</ControlTemplate>

 

The above ControlTemplate is much simpler, as we just use TemplateBinding to bind to the corresponding styling properties. The VisualStateManager should take care of the rest.

While waiting for the documentation of the new TabView to become more complete, here is a short list of the styling properties available to the TabViewHeaderItem:

  • BackgroundColor - specifies the background color of the header item
  • BorderColor - specifies the border color of the header item
  • BorderThickness - specifies the border thickness of the header item
  • CornerRadius - specifies the corner radius of the header item
  • ContentPadding - specifies the padding of the inner content of the header item
  • TextColor - specifies the color of the text in the header item
  • FontFamily - specifies the font family of the text in the header item
  • FontSize - specifies the font size of the text in the header item
  • FontAttributes - specifies the font attributes of the text in the header item
  • TextDecorations - specifies the decorations of the text in the header item
  • HorizontalTextAlignment - specifies the horizontal alignment of the text in the header item
  • VerticalTextAlignment - specifies the vertical alignment of the text in the header item
  • ImageSource - specifies the source of the image icon in the header item
  • ImageAspect - specifies the aspect of the image icon in the header item
  • ImageWidth - specifies the width of the image icon in the header item
  • ImageHeight - specifies the height of the image icon in the header item
  • ImageSpacing - specifies the spacing between the image icon and the text in the header item
  • ImagePosition - specifies the position of the image icon relative to the text (Left, Top, Right, Bottom)

Attached to my post you can find the demo application, which creates the following customized header:

I hope this should help you style the TabView according to your needs. If you have more questions about this, do not hesitate to ask.

Kind regards,

Ivan

Palmsenser
Top achievements
Rank 1
commented on 21 Feb 2022, 11:46 AM

Hi,

it works. in stead of using "IsVisible", I use now "BackgroundColor", Thanks! Cheers !:-)

Palmsenser
Top achievements
Rank 1
commented on 21 Feb 2022, 05:14 PM

If I tried to add more Tab, it will work during the View Contructor:

public partial class TabContentView : ContentView

{

public TabContentView()
{
            InitializeComponent();

       var tabViewItem = new TabViewItem
            {
                HeaderText = "Tab1",
                Content = new Label
                {
                    Text = "My Custom Tab Content"
                }
            };

            this.PlotDataTabView.Items.Add(tabViewItem);}  // This shows extra Tab in UI

}

I tried to add some extra Tab from code behind (by clicking the button):

<telerikInput:RadButton x:Name="button" 
                  Text="Click me!"  
                  BorderThickness="2" 
                  BorderColor="#4488F6" 
                  AutomationId="button"
                  Clicked="button_Clicked"/>

private void button_Clicked(object sender, System.EventArgs e)
        {
            var tabViewItem = new TabViewItem
            {
                HeaderText = "Tab1",
                Content = new Label
                {
                    Text = "My Custom Tab Content"
                }
            };

            this.PlotDataTabView.Items.Add(tabViewItem); // It shows NO extra Tab in UI
        }

 <telerik:RadTabView x:Name="PlotDataTabView" GridLayout.Row="0"
                                HeaderItemStyle="{StaticResource HeaderItemStyle}"
                                 HeaderItemTemplate="{StaticResource HeaderItemTemplate}" >

                <telerik:TabViewItem HeaderText="t1" >
                    <telerikInput:RadButton x:Name="button" 
                  Text="Click me!"  
                  BorderThickness="2" 
                  BorderColor="#4488F6" 
                  AutomationId="button"
                  Clicked="button_Clicked"/>
                </telerik:TabViewItem>
                <telerik:TabViewItem HeaderText="t2" >
                   <Label Text = tab2 />
                </telerik:TabViewItem>
                <telerik:TabViewItem HeaderText="t3" >
                     <Label Text = tab3 />
                </telerik:TabViewItem>                

            </telerik:RadTabView>

                

Please, help.


Ivan
Telerik team
commented on 22 Feb 2022, 08:58 AM

Hello Jun,

Attached you can find the test application I have used in my attempt to reproduce the problem. According to my tests, adding a new tab dynamically on button click works as expected. I assume you are using the latest preview version 0.4.0 from January.

Could you check if the problem is still reproducible on your side with my application? If the problem persists, please, give us some more details on what platform an OS version you are testing. If the problem is not reproducible with my application, but you still cannot make it work for you, perhaps sending us a small repro application could help us isolate the reason.

Regards,

Ivan

0
Ivan
Telerik team
answered on 11 Feb 2022, 10:40 AM

Hello Jun,

The RadTabView for MAUI is a completely new control, in our attempt to overcome the limitations of the existing Xamarin.Forms control. The documentation of the new control is a work in progress, so your confusion is understandable. I'll try my best to explain how to customize the control here.

The RadTabView control has two main sections: the header area (of type TabViewHeader) and the content area (of type TabViewContent). The header area is a container for the individual header items (of type TabViewHeaderItem), as illustrated in the following picture:

The RadTabView has properties to customize both areas and the header items as well:

  • HeaderStyle (of type Style) - specifies the style of the entire header area (border, background color etc.);
  • HeaderTemplate (of type ControlTemplate) - specifies the template of the entire header area;
  • HeaderItemStyle (of type Style) - specifies the style of the individual header items (font, text color etc.)
  • HeaderItemTemplate (of type ControlTemplate) - specifies the template of the individual header items;
  • ContentStyle (of type Style) - specifies the style of the entire content area (borders, background color etc.);
  • ContentTemplate (of type ControlTemplate) - specifies the template of the entire content area;

If I understand you correctly, what you need is to set the FontFamily of the header items to some custom font with icon glyphs. To do so, you do not need to redefine the entire template. Instead, you can use the HeaderItemStyle property do customize the style of the header items:

<telerikMauiControls:RadTabView x:Name="tabView">
    <telerikMauiControls:RadTabView.HeaderItemStyle>
        <Style TargetType="telerikMauiControls:TabViewHeaderItem">
            <Setter Property="FontFamily" Value="YOUR_CUSTOM_FONT_FAMILY" />
        </Style>
    </telerikMauiControls:RadTabView.HeaderItemStyle>
</telerikMauiControls:RadTabView>

Regarding your question how to populate the tabs dynamically, if I understand you correctly, all you need to do is to populate the Items property (which is a collection of TabViewItems) like this:

var tabViewItem = new TabViewItem
{
    HeaderText = "My Custom Tab",
    Content = new Label
    {
        Text = "My Custom Tab Content"
    }
};

this.tabView.Items.Add(tabViewItem);

Populating the tabs via data-binding is currently not supported, as the new RadTabView control is still a work in progress. We have this feature in mind however, but I cannot give you any specific time frame for the time being.

Regards,
Ivan
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

-1
Lance | Senior Manager Technical Support
Telerik team
answered on 10 Feb 2022, 03:05 PM

Hello Jun,

You can set the HeaderItemTemplate property of the RadTabView. As to your question of content binding, it's the same approach as you would use for any databinding. The HeaderItemTemplate is of type ControlTemplate.

For guidance, you can use the same technique as seen in the Xamarin documentation here https://docs.telerik.com/devtools/xamarin/controls/tabview/tabview-header-item#default-tabviewheaderitem-controltemplate (we will have the UI for MAUI documentation prepared before release).

As far as custom fonts go, you can do whatever you want to the Label inside the ControlTemplate. It's the same as you'd do to any other text rendering component. Here's a screenshot to guide you:

Important Note: If you are building a custom library, you may experience an issue, see the official MAUI repo Issue => [Bug] Custom font not working when used inside a custom library.

Custom Binding Context

The BindingContext of the Header ControlTemplate is supplied by the TabView's API, you cannot change this to your own data model. However, you can always use a RelativeSource binding to bind to the property you want.

To give you a head-start, I have already built such an example that you can use for guidance. TabView Header BusyIndicator. 

In that KB article, you will see that I have added a BusyIndicator to the header ControlTemplate. In order to operate that BusyIndicator, I bind to my custom data item's IsLoading property through the use of a RelativeSource AncestorType binding.

 

Further Assistance

If you have any further issues before UI for MAUI is released as an official product, please open a new UI for .NET MAUI Forum post (instead of a private UI for Xamarin Priority Support ticket). This will avoid potential 24-72 hour delay in getting you an answer. When UI for MAUI is an official released product, you will be able to open support tickets for it.

Regards,
Lance | Manager Technical Support
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tobias
Top achievements
Rank 1
commented on 27 Jun 2023, 11:56 AM | edited

This is not working for MAUI, because in my understandings it is not possible to set the BindingContext for each Header of TabViewItem. It is only possible to set the HeaderText. There is only one Template and no possibility to determine wich data context is responsible for the according Header/TabItem, because there is also no relation between headerViewItem to TabViewItem. It is not an ancestor.
Lance | Senior Manager Technical Support
Telerik team
commented on 28 Jun 2023, 06:05 PM

Hi Tobias, you're correct that the MAUI TabView's structure is different form Xamarin.Forms and the older approach no longer works. This is because there's no shared visual tree between the TabHeader and the Tab content, please read Ivan's answer below for a better description.

However, this doesn't mean you cannot find the connection between what tab header belongs to which tab. In fact, the HeaderText can be used for that!

Please see my Multi-Window Tearable Tabs demo. In it, you'll see that I am able to get the original tab from the tab header's BindingContext in order to move it to a new window.

As to how you'd use this knowledge, you would need to write a behavior (or similar) to be able to use code to get those references, as it cannot be done in XAML with bindings alone. In the behavior, you can pass both a reference to the TabView and the TabViewHeaderItem, this is enough to find the original tab.

Tags
TabView
Asked by
Palmsenser
Top achievements
Rank 1
Answers by
Palmsenser
Top achievements
Rank 1
Ivan
Telerik team
Lance | Senior Manager Technical Support
Telerik team
Share this question
or