Reputation: 4586
I am trying to format a string lets say
"Hello george, how are you?"
I just want "george" in red color. Is there any way I can use String.Format
and FormattedString
side by side?
I tried using:
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
);
However this does not work. Is there any proper way to actually do this. I want localization so I don't want to split the text into multiple localization strings.
Upvotes: 1
Views: 2109
Reputation: 13601
You can use an intercept provider in string.Format
.
For illustrative purposes, I choose XAML format as output, and then convert it into FormattedString
(but more concise formats like JSON can also be used).
First, let's implement the intercept provider - which will convert your string.Format
's output into 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>";
}
}
Add an extension method to integrate the interceptor with 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>";
}
And, finally an helper method that converts XAML to FormattedString
object.
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();
Or,
lbl.FormattedText = "{0} It is now {1:d} at {1:t}"
.InterceptFormat("Morning!", DateTime.Now)
.ToFormattedString();
Upvotes: 2