首页 > 解决方案 > 字符串格式和格式化字符串

问题描述

我正在尝试格式化字符串让我们说

“你好,乔治,你好吗?”

我只想要红色的“乔治”。有什么办法可以并排使用String.FormatFormattedString

我尝试使用:

var text = new FormattedString();
text.Spans.Add(new Span { 
    Text = Localize.GetString("irs", String.Empty), 
    ForegroundColor = Colors.RedColor 
});
label.FormattedText = String.Format(
    Localize.GetString("instructions", String.Empty), 
    text
);

但是,这不起作用。有什么正确的方法可以实际做到这一点。我想要本地化,所以我不想将文本拆分为多个本地化字符串。

标签: c#xamarin.formsstring-formatting

解决方案


您可以在string.Format.

出于说明的目的,我选择 XAML 格式作为输出,然后将其转换为FormattedString(但也可以使用更简洁的格式,如 JSON)。

首先,让我们实现拦截提供程序 - 它将您string.Format的输出转换为Span(s):

public class InterceptProvider : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
        if (formatType == typeof(ICustomFormatter))
            return this;
        else
            return null;
    }

    public string Format(String format, Object obj, IFormatProvider provider)
    {
        string spanText;

        // Use default for all other formatting.
        if (obj is IFormattable)
            spanText = ((IFormattable)obj).ToString(format, System.Globalization.CultureInfo.CurrentCulture);
        else
            spanText = obj.ToString();

        return $"</Span><Span ForegroundColor=\"Red\">{spanText}</Span><Span>";
    }
}

添加扩展方法以将拦截器与string.Format.

public static class FormatExtensions
{
    static ColorTypeConverter _typeConverter = new ColorTypeConverter();
    static InterceptProvider _interceptor = new InterceptProvider();

    public static string InterceptFormat(this string sourceStr, params object[] args)
    {
        return $"<FormattedString><Span>{string.Format(_interceptor, sourceStr, args)}</Span></FormattedString>";
    }

FormattedString最后是一个将 XAML 转换为对象的辅助方法。

    public static FormattedString ToFormattedString(this string xamlStr)
    {
        var toReturn = new FormattedString();

        if (string.IsNullOrWhiteSpace(xamlStr))
            return toReturn;

        Span span = null;
        using(var strReader = new StringReader(xamlStr))
        {
            using(var xmlReader = XmlReader.Create(strReader))
            {
                while (xmlReader.Read())
                {

                    if (xmlReader.IsStartElement())
                    {
                        switch (xmlReader.Name)
                        {
                            case "Span":
                                span = new Span();

                                while (xmlReader.MoveToNextAttribute())
                                {
                                    switch (xmlReader.Name)
                                    {
                                        case "ForegroundColor":
                                            var color = xmlReader.Value;
                                            if (!string.IsNullOrEmpty(color))
                                                span.ForegroundColor = (Color)_typeConverter.ConvertFromInvariantString(color);
                                            break;
                                    }
                                }

                                if (xmlReader.IsStartElement() || xmlReader.MoveToContent() == XmlNodeType.Element)
                                {
                                    span.Text = xmlReader.ReadString();
                                    toReturn.Spans.Add(span ?? new Span());
                                }    

                                break;
                        }
                    }
                }
            }    
        }

        return toReturn;
    }

用法:

label.FormattedText = Localize.GetString("instructions", String.Empty)
                          .InterceptFormat(text).ToFormattedString();

或者,

lbl.FormattedText = "{0} It is now {1:d} at {1:t}"
                        .InterceptFormat("Morning!", DateTime.Now)
                        .ToFormattedString();

在此处输入图像描述


推荐阅读