字符串格式和格式化字符串

时间:2018-09-26 07:04:28

标签: c# xamarin.forms string-formatting

我正在尝试格式化一个可以说的字符串

  

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

我只想要红色的“乔治”。有什么办法可以并排使用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
);

但是,这不起作用。是否有任何适当的方法来实际执行此操作。我想要本地化,所以我不想将文本拆分成多个本地化字符串。

1 个答案:

答案 0 :(得分:1)

您可以在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>";
    }

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

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

enter image description here