Search code examples
xamlmaui

Why are my values empty in object[] values when using IMultiValueConverter, but seems to have values when used without it in the View?


Please help me understand this. I have the following in my View:

<Label 
    x:Name="communityAndUserLabel"
    Grid.Row="2"
    Grid.Column="1"
    FontAttributes="None"
    VerticalOptions="End">
    <Label.Text>
        <MultiBinding StringFormat="{}{0} • {1}">
            <Binding Path="CommunityName" />
            <Binding Path="Username" />
        </MultiBinding>
    </Label.Text>
    <Label.TextColor>
        <MultiBinding Converter="{StaticResource CommunityTextColorConverter}">
            <Binding Path="CommunityName" 
                Source="x:Reference communityAndUserLabel" />
            <Binding Path="Username" 
                Source="x:Reference communityAndUserLabel" />
        </MultiBinding>
    </Label.TextColor>
</Label>

When the application runs, the CommunityName and Username appear formatted as they should as specified by Label.Text StringFormat; however, no color change is taking place when criteria is met. I've found that this is because object[] values doesn't seem to getting any data into the CommunityTextColorConvertor.cs file at the start, so everything evaluates as null/empty.

The CommunityTextColorConverter.cs:

using System.Globalization;

namespace Disc.Converters
{
    public class CommunityTextColorConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        { // Check if the values are valid if (values == null || values.Length != 2) return Colors.Black;

            // Get the community name and username from the values array
            string CommunityName = values[0] as string;

            // Check if the community name and username are not null or empty
            if (string.IsNullOrEmpty(CommunityName))
            {
                return Colors.PowderBlue; //default color when unset
            }

            // Define some colors for different communities
            Color red = Color.FromRgb(255, 0, 0);
            Color green = Color.FromRgb(0, 255, 0);
            Color blue = Color.FromRgb(0, 0, 255);

            // Return a different color based on the community name
            switch (CommunityName.ToLower())
            {
                case "nintendo":
                    return red;
                case "xbox":
                    return green;
                case "playstation":
                    return blue;
                case "pcgaming":
                    return Colors.Purple;
                case "news":
                    return Colors.Pink;
                default:
                    return Colors.PowderBlue;
            }
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            // Not implemented
            throw new NotImplementedException();
        }
    }
}

Thing I have tried:

  • setting Binding Path="Text" in the Label.TextColor elements
  • setting Binding Path="CommunityName" in the Label.TextColor element (and Username on the other)
  • running it again without changing anything at all hoping it will magically work this time

Solution

  • I was able to get the values pulling in, which technically was my question - so I guess I should post the 'solution' as the answer? Julian's mention of the binding source being wrong set me on the right path. It's still not working quite like I'm attempting to do (Can only get the whole string displaying as a single color), but the updated (semi) working code is here:

    NameColorMultiConverter.cs

    using System.Globalization;
    
    namespace Disc.Converters
    {
        public class NameColorMultiConverter : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                Console.WriteLine("CommunityName: " + values[0]);
                Console.WriteLine("Username: " + values[1]);
                // Check if the input values are strings
                if (values[0] is not string community || values[1] is not string username)
                    return Colors.Black;
    
                // Define an array of known community names
                string[] communities = new[] 
                { 
                    "PlayStation", 
                    "Xbox", 
                    "PCGaming", 
                    "Nintendo",
                    "Discuit"
                };
    
                // Define a switch expression to map community names to colors
                Color communityColor = community switch
                {
                    "PlayStation" => Colors.Blue,
                    "Xbox" => Colors.Green,
                    "PCGaming" => Colors.Purple,
                    "Nintendo" => Colors.Red,
                    "Discuit" => Colors.Purple,
                    // Add more cases as needed
                    _ => Colors.Aqua // Default case
                };
    
                // Define an array of known usernames
                string[] usernames = new[]
                {
                    "Previnder",
                    "ReticentRobot",
                    "TestAccountPlsIgnore",
                    "RenegadeBAM",
                    "gsurfer04"
                };
    
                // Define a switch expression to map usernames to colors
                Color usernameColor = username switch
                {
                    "Previnder" => Colors.Red,
                    "ReticentRobot" => Colors.Orange,
                    "TestAccountPlsIgnore" => Colors.Yellow,
                    "RenegadeBAM" => Colors.Green,
                    "gsurfer04" => Colors.Blue,
                    // Add more cases as needed
                    _ => Colors.Pink // Default case
                };
    
                // Return the color for the community name or the username based on the parameter value
                return parameter switch
                {
                    "community" => communityColor,
                    "username" => usernameColor,
                    _ => Colors.AntiqueWhite // Default case
                };
            }
    
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                // This converter does not support converting back
                throw new NotImplementedException();
            }
        }
    }
    

    Accompanying XAML

    <Label 
        x:Name="communityAndUserLabel"
        Grid.Row="2"
        Grid.Column="1"
        FontAttributes="None"
        VerticalOptions="End">
        <Label.Text>
            <MultiBinding StringFormat="{}{0} • {1}" Mode="TwoWay">
                <Binding Path="CommunityName" />
                <Binding Path="Username" />
            </MultiBinding>
        </Label.Text>
        <Label.TextColor>
            <MultiBinding Converter="{StaticResource nameColorMulti}" ConverterParameter="community">
                <Binding Path="CommunityName" />
                <Binding Path="Username" />
            </MultiBinding>
        </Label.TextColor>
    </Label>