0

This is quite simple task but I am running short on ideas how to implement it. I have added FontAwesome to my app and would like to create a picker control that would display two different labels with different fonts side by side, but it looks like Picker control applies font on control level and it is not possible to display two different fonts for each item side by side. I need this so I could display icon from FontsAwesome and text with my default font. Are there any solutions to this?

Here is what I have tried so far:

 public class DualLabelPicker : Picker
 {
   public static readonly BindableProperty ItemsSourceProperty =
       BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(DualLabelPicker), null);

   public IEnumerable ItemsSource
   {
     get { return (IEnumerable)GetValue(ItemsSourceProperty); }
     set { SetValue(ItemsSourceProperty, value); }
   }

   public static readonly BindableProperty IconFontFamilyProperty =
       BindableProperty.Create(nameof(IconFontFamily), typeof(string), typeof(DualLabelPicker), default(string));

   public string IconFontFamily
   {
     get { return (string)GetValue(IconFontFamilyProperty); }
     set { SetValue(IconFontFamilyProperty, value); }
   }

   public static readonly BindableProperty TextFontFamilyProperty =
       BindableProperty.Create(nameof(TextFontFamily), typeof(string), typeof(DualLabelPicker), default(string));

   public string TextFontFamily
   {
     get { return (string)GetValue(TextFontFamilyProperty); }
     set { SetValue(TextFontFamilyProperty, value); }
   }

   protected override void OnPropertyChanged(string propertyName = null)
   {
     base.OnPropertyChanged(propertyName);

     if (propertyName == ItemsSourceProperty.PropertyName)
     {
       RefreshPickerItems();
     }
   }

   private void RefreshPickerItems()
   {
     Items.Clear();
     if (ItemsSource != null)
     {
       foreach (IconTextPickerItem item in ItemsSource)
       {
         FormattedString formattedString = new FormattedString();

         Span iconSpan = new Span { Text = item.Icon, FontFamily = IconFontFamily, FontAttributes = FontAttributes.Italic };
         formattedString.Spans.Add(iconSpan);

         Span textSpan = new Span { Text = " " + item.Text, FontFamily = TextFontFamily };
         formattedString.Spans.Add(textSpan);

         // Convert the FormattedString to a string and add it to the Items collection
         Items.Add(FormattedStringToString(formattedString));
       }
     }
   }

   private string FormattedStringToString(FormattedString formattedString)
   {
     StringBuilder stringBuilder = new StringBuilder();

     foreach (Span span in formattedString.Spans)
     {
       stringBuilder.Append(span.Text);
     }

     return stringBuilder.ToString();
   }
 }

Here is model

  public class IconTextPickerItem
  {
    public string Icon { get; set; }
    public string Text { get; set; }
  }

EDIT 1:

So I have created now this class to Platforms > Windows

using Microsoft.Maui.Handlers;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
using UWPDataTemplate = Microsoft.UI.Xaml.DataTemplate;

namespace Application.Windows
{
  public partial class PickerRowExHandler : PickerHandler
  {
    protected override ComboBox CreatePlatformView()
    {
      return new PickerComboBox();
    }

    protected override void ConnectHandler(ComboBox platformView)
    {
      base.ConnectHandler(platformView);
    }

    protected override void DisconnectHandler(ComboBox platformView)
    {
      base.DisconnectHandler(platformView);
    }
  }

  public class PickerComboBox : ComboBox
  {
    public PickerComboBox()
    {
      // Define the XAML markup for the DataTemplate
      string xaml = @"
                <DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                              xmlns:local='using:CalendarApplication.Models'>
                    <StackPanel Orientation='Horizontal'>
                        <TextBlock Text='{Binding Icon}' FontFamily='FontAwesomeSolid' FontSize='20' VerticalAlignment='Center' Margin='5'/>
                        <TextBlock Text='{Binding Text}' VerticalAlignment='Center' Margin='5'/>
                    </StackPanel>
                </DataTemplate>";

      // Load the XAML markup as the ItemTemplate
      ItemTemplate = (UWPDataTemplate)XamlReader.Load(xaml);
    }
  }
}

Then I have added this to generic Models folder

  public class PickerItem
  {
    public string Text { get; set; }
    public string Icon { get; set; } // Path to the icon or a resource identifier
  }

Then this to ViewModel

public MainViewModel()
{
  Items = new ObservableCollection<PickerItem>
    {
        new PickerItem { Text = "User", Icon = "\uf007" },
        new PickerItem { Text = "Cog", Icon = "\uf013" },
        new PickerItem { Text = "Home", Icon = "\uf015" },
    };
}

public ObservableCollection<PickerItem> Items { get; set; }

Then this to xaml

    <controls:PickerRowEx x:Name="MyPicker" Padding="0,0,0,0" 
                          BackgroundColor="Transparent" BorderColor="DarkBlue" HorizontalOptions="CenterAndExpand" 
                          HorizontalTextAlignment="Center" MinimumWidthRequest="200"
                          SelectedIndexChanged="MyPicker_SelectedIndexChanged" TextColor="Blue"
                          ItemsSource="{Binding Items}">
      <controls:PickerRowEx.ItemTemplate>
        <DataTemplate x:DataType="models:PickerItem">
          <StackLayout Orientation="Horizontal">
            <Label Text="{Binding Icon}" FontFamily="FontAwesomeSolid" FontSize="20" VerticalOptions="Center" Margin="5"/>
            <Label Text="{Binding Text}" VerticalOptions="Center" Margin="5"/>
          </StackLayout>
        </DataTemplate>
      </controls:PickerRowEx.ItemTemplate>
    </controls:PickerRowEx>

Currently problem is that I see there is correct amount of items in my combobox in UI, but I do not see any text. So I assume the problem is with bindings and that below can not assign correct x:DataType="models:PickerItem", but I do not know how to set it properly. Tried several options without success

  public class PickerComboBox : ComboBox
  {
    public PickerComboBox()
    {
      // Define the XAML markup for the DataTemplate
      string xaml = @"
                <DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                              xmlns:local='using:CalendarApplication.Models'>
                    <StackPanel Orientation='Horizontal'>
                        <TextBlock Text='{Binding Icon}' FontFamily='FontAwesomeSolid' FontSize='20' VerticalAlignment='Center' Margin='5'/>
                        <TextBlock Text='{Binding Text}' VerticalAlignment='Center' Margin='5'/>
                    </StackPanel>
                </DataTemplate>";

      // Load the XAML markup as the ItemTemplate
      ItemTemplate = (UWPDataTemplate)XamlReader.Load(xaml);
    }
  }
4
  • 1
    In my repo you can see how to manipulate native picker. Perhaps this is something you can use? Commented May 19, 2024 at 17:06
  • Ok, so you are basically using WinUi3 combobox in case of windows? I was actually checking this solution if this might be the way but had no time to test it. Thank you, I will try to test your code and might come back with additional questions. Commented May 19, 2024 at 20:30
  • I am not using WinUI 3 by choice, it is what MAUI use. Build Windows apps with .NET MAUI Commented May 20, 2024 at 7:33
  • @PeterWessberg I just had time to check your solution. Got it almost working, but not completely. If you have time, could you check my edited question with EDIT1 as a reference? So basically I am trying to put two strings side by side with different fonts. One fontawesome for icons and another one regular, for text. Commented Jun 7, 2024 at 20:20

0

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.