0

I have a custom control that I supply a List<string> parameter and it draws a box for each string as a label.

Here is a version that is working. Clicking 'Add Tab' adds one tab at a time for each click.

I want to change the code so the List is converted into a different type of object and that is what the control displays.

enter image description here

First I show the code that is working for the image above. Then I show a changed version of the code that I am unable to get working. Hopefully for anyone answering this question, seeing the before code that works and the after code that doesn't work, you can easily spot the issue.

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"
             xmlns:local="clr-namespace:App7"
             x:Class="App7.MainPage">

    <StackLayout>
        <BoxView HeightRequest="100" />

        <local:CustomControl 
            SideTabs="{Binding MainNavigationTabs}" 
        />

        <Button Text="Add Tab" Command="{Binding AddTab}" />

    </StackLayout>

</ContentPage>

MainPageModel.cs

public class MainPageModel : FreshBasePageModel
{
    public MainPageModel() { }

    public List<string> MainNavigationTabs { get; set; }

    private int _index = 0;

    public Command AddTab
    {
        get
        {
            return new Command(() =>
            {
                _index++;

                var tabs = new List<string>();

                for (var index = 1; index <= _index; index++)
                {
                    tabs.Add($"Tab {index}");
                }

                MainNavigationTabs = tabs;
            });
        }
    }
}

CustomControl.xaml

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="App7.CustomControl"
                 BackgroundColor="Beige"
                 x:Name="this">
    <ContentView.Content>
        <StackLayout>
            <StackLayout Orientation="Vertical"
                             BindableLayout.ItemsSource="{Binding Source={x:Reference this}, Path=SideTabs}">

                <BindableLayout.ItemTemplate>
                    <DataTemplate>
                        <ContentView WidthRequest="237"
                                         Margin="0"
                                         BackgroundColor="Blue"
                                         Padding="10">
                            <Label Text="{Binding .}" TextColor="White" />
                        </ContentView>
                    </DataTemplate>
                </BindableLayout.ItemTemplate>
            </StackLayout>
        </StackLayout>
    </ContentView.Content>
</ContentView>

CustomControl.xaml.cs

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomControl : ContentView
{
    public CustomControl()
    {
        InitializeComponent();
    }

    public static readonly BindableProperty SideTabsProperty = BindableProperty.Create(
                                       propertyName: "SideTabs",
                                       returnType: typeof(List<string>),
                                       declaringType: typeof(CustomControl),
                                       defaultBindingMode: BindingMode.OneWay,
                                       defaultValue: new List<string>());

    public List<string> SideTabs
    {
        get { return base.GetValue(SideTabsProperty) as List<string>; }
        set { base.SetValue(SideTabsProperty, value); }
    }
}

I changed the CustomControl to transform the List<string> to a List<SideTab> object and have the control bind to that. Here's the code...

CustomControl.xaml.cs

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomControl : ContentView
{
    public CustomControl()
    {
        InitializeComponent();
    }

    public static readonly BindableProperty SideTabsProperty = BindableProperty.Create(
                                       propertyName: "SideTabs",
                                       returnType: typeof(List<string>),
                                       declaringType: typeof(CustomControl),
                                       defaultBindingMode: BindingMode.OneWay,
                                       defaultValue: new List<string>());

    public List<string> SideTabs
    {
        get
        {
            var tabs = new List<string>();

            foreach (var tab in _SideTabs)
            {
                tabs.Add(tab.Text);
            }

            return tabs;
        }
        set
        {
            var tabs = new List<SideTab>();

            foreach (var tab in value)
            {
                tabs.Add(new SideTab() { Text = tab });
            }

            _SideTabs = tabs;
        }
    }

    public List<SideTab> _SideTabs
    {
        get { return base.GetValue(SideTabsProperty) as List<SideTab>; }
        set { base.SetValue(SideTabsProperty, value); }
    }
}

public class SideTab
{
    public string Text { get; set; }
}

CustomControl.xaml

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="App7.CustomControl"
                    BackgroundColor="Beige"
                    x:Name="this">
    <ContentView.Content>
        <StackLayout>
            <StackLayout Orientation="Vertical"
                                BindableLayout.ItemsSource="{Binding Source={x:Reference this}, Path=_SideTabs}">

                <BindableLayout.ItemTemplate>
                    <DataTemplate>
                        <ContentView WidthRequest="237"
                                            Margin="0"
                                            BackgroundColor="Blue"
                                            Padding="10">
                            <Label Text="{Binding Text}" TextColor="White" />
                        </ContentView>
                    </DataTemplate>
                </BindableLayout.ItemTemplate>
            </StackLayout>
        </StackLayout>
    </ContentView.Content>
</ContentView>

Notice the addition of a property _SideTabs. When SideTabs is set, it transforms the List<string> into a List<SideTab>.

How can I make this work? Here is the result from the above code changes...

enter image description here

1
  • You haven't changed your SideTabsProperty to reflect the data type change in your last example. Also if you are just interested in different appearance based on a value on the model you are binding. TemplateSelector might be a better way. Commented Jun 18, 2019 at 21:09

1 Answer 1

2

Try like this,

 public static readonly BindableProperty TabsListProperty = BindableProperty.Create(nameof(TabsList), typeof(List<TabItem>), typeof(ScrollableTabs), null, propertyChanged: (bindable, oldValue, newValue) =>
    {
        ((ScrollableTabs)bindable).InitializeTabs();
    });

    private void InitializeTabs()
    {
        //Write your logic here
    }


    public List<TabItem> TabsList
    {
        get
        {
            return (List<TabItem>)GetValue(TabsListProperty);
        }
        set
        {
            SetValue(TabsListProperty, value);

        }
    }
Sign up to request clarification or add additional context in comments.

1 Comment

This led me to the solution. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.