Introduction
I had a case where I needed to have a string
that included data from XAML resources in WPF since I would not be allowed to specify resources in the string
. I immediately thought that maybe I could use the MarkupExtension
for this, but was not sure exactly how. I did some searching and I was not the only one that was interested in trying to do this. I found that Martin Grech had posted some answers that allowed creating a string
with a string
part concatenated with a binding. His MarkupExtension
had a string
property and a Binding
property, and this was very easy. I have included his code in the sample for reference.
With this, I immediately started working with something that was totally different since I needed to get XAML resources and I wanted to the capability to have multiple XAML resources in the string
. I did consider having multiple properties but decided instead to take a leaf from something that was recently added to C#, string interpolation, and using the same format with the resource names within curly brackets. I could have gone through and manually extract the resource names from the string
, but figured that RegEx would be better to solve the problem.
I did a dirty solution first using a foreach
loop, but was sure that was not the best option, so shared the code on CodeProject and asked if there was a better way. -*/Sure enough there was, and Richard Deeming pointed the way.
The Code
The code is derived from MarkupExtenson
and adds a single property for the string
that is to be interpreted:
public class ConcatExtension : MarkupExtension
{
private static readonly Regex Pattern = new Regex("{[^}]+}", RegexOptions.Compiled);
public string String { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
DependencyObject dep = new DependencyObject();
if (!DesignerProperties.GetIsInDesignMode(dep))
{
return Pattern.Replace(String, match =>
{
string newMatch = match.Groups[1].Value;
serviceProvider.TryProvideValue(newMatch, out object value);
return Convert.ToString(value);
});
}
return String;
}
}
A check was added, check for if in design mode to keep errors from occurring that would prevent the design time view from showing because of an error. A regular expression is used to find all instances where text is between two curly brackets, which have to be used to indicate where there are resource references. The RegEx
Replace
method with the MatchEvaluator
is used to replace the resource names and associated brackets with the resource string
value.
Within the MatchEvaluator
code, a TryProvideValue
extension method that I used with the IServiceProvider
to find resources and to handle errors when a resource is not found, the method having an out
argument and returning true
if the resource is found. If the resource cannot be found, the out
-argument details that the resource with that name could not be found and returns false
:
public static class ExtensionMethods
{
public static bool TryProvideValue(this IServiceProvider serviceProvider, string key,
out object value)
{
try
{
value = new StaticResourceExtension(key).ProvideValue(serviceProvider); ;
return true;
}
catch
{
value = $"{{\"{key}\" could not be found}}";
return false;
}
}
}
The Sample
The sample is a simple Window
with two TextBlock
controls whose Text
DependencyPropery
uses the Concat
ExtensionMethod
, one containing a valid resource name within curly brackets:
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="15"
Text="{local:Concat String='This is a test to see if the Concat MarkupExtension " +
"really does find the resource TestString: TestString = {TestString}'}"
TextWrapping="Wrap" />
and the other an invalid resource name within curly brackets.
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="15"
Text="{local:Concat String='This is a test to see what happens when the Concat " +
"MarkupExtension does not find the resource TestString: TestString = {TestString1}'}"
TextWrapping="Wrap" />
There is only a single resource:
<system:String x:Key="TestString">Testing</system:String>
Here is what the Window looks like in design mode:
Here is what the Window looks like in run mode:
Enhancements
There is the possibility that this could be enhanced to allow a lot more flexibility, such as allowing the use of Binding
, but will have to investigate this possibility.
History
- 03/04/2018: Initial version