0
votes

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.Cheesebaron

1 Answers

1
votes

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);

        }
    }