Alan2
Alan2

Reputation: 24572

How can I create a template / class that will allow me to simplify some my Xaml where there are multiple elements into just one?

Here's an example of what I need to do now. Sometimes I have one span, sometimes more.

Note that this post is similar to that of another question. For the other question I had only one comment to use a custom control with no more advice offered and one answer to use JavaScript. I tried to add a second bounty to that question but it gave me the option of only adding a bounty of 500 points. The question is now so old that I doubt anyone will see it any more and as I cannot add a bounty (unless it's 500 points) I cannot give it more visibility.

Here's what I would like to simplify:

<Label>
   <Label.FormattedText>
      <FormattedString>
         <Span Text="Hello " />
         <Span Text="Hello " />
         <Span Text=" Some more text." />
      </FormattedString>
   </Label.FormattedText>
</Label>

Here's what I would like to do instead of typing in <Label><Label.FormattedText><FormattedString> I would like to get some way to do this with only entering in <template:FormattedLabel>

<template:FormattedLabel>
   <Span Text="Hello " />
   <Span Text="Hello " />
   <Span Text=" Some more text." />
</template:FormattedLabel>

or

<template:FormattedLabel>
   <Span Text="Hello " />
</template:FormattedLabel>

Note that I have looked into custom controls but as far as I see I cannot find a way to make these accept some inside content which in this case would be one or more spans.

I have an example of something similar which could perhaps be used but I am not sure how to apply it. What I was hoping for was a template like this in the XAML below which is does something similar to what I need but for content pages:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
   xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
   xmlns:local="clr-namespace:Japanese;assembly=J" 
   xmlns:t="clr-namespace:J.Templates" 
   x:Class="Japanese.Templates.ContentScrollable" 
   x:Name="ContentPage" >
   <ContentPage.Content>
       <t:Stack Orientation="Vertical">
          <ScrollView x:Name="scroll">
             <ContentView Content="{Binding Source={x:Reference ContentPage}, Path=InnerContent}" 
                         Margin="{DynamicResource PageMargin}" />
          </ScrollView>
       </t:Stack>
   </ContentPage.Content>
</ContentPage>

With its C# back end:

public partial class ContentScrollable : ContentPage
{

    public static readonly BindableProperty InnerContentProperty = BindableProperty.Create(nameof(InnerContent), typeof(View), typeof(ContentScrollable));

    public View InnerContent
    {
        get => (View)this.GetValue(InnerContentProperty);
        set => this.SetValue(InnerContentProperty, value);
    }

    public ContentScrollable()
    {
        InitializeComponent();
    }
}

How can I accomplish what I am looking for?

Upvotes: 4

Views: 210

Answers (1)

You can do the following:

<!-- FormattedLabel.xaml -->
<?xml version="1.0" encoding="UTF-8"?>
<Label 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="YourNamespaceForTemplates.FormattedLabel" />
// FormattedLabel.xaml.cs
[ContentProperty(nameof(Spans))]
public partial class FormattedLabel : Label
{
    private readonly ObservableCollection<Span> _spans;
    public IList<Span> Spans => _spans;

    public FormattedLabel()
    {
        _spans = new ObservableCollection<Span>();
        _spans.CollectionChanged += OnSpansChanged;

        InitializeComponent();
    }

    private void OnSpansChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        FormattedText?.Spans?.Clear();
        FormattedText = FormattedText ?? new FormattedString();
        Spans.ForEach(FormattedText.Spans.Add);
    }
}

Basically, in this extension of Label we define the content to be a list of Span items, which will allow you to define them in XAML inside <FormattedLabel></FormattedLabel>. To make it work, we pass these items down to this.FormattedText.Spans.

To use it:

<template:FormattedLabel>
    <Span Text="Hello " />
    <Span Text="Hello " />
    <Span Text=" Some more text." />
</template:FormattedLabel>

I have just checked it and it works perfectly. I hope this helps!

Upvotes: 4

Related Questions