4.4.11

Bypass the colon - DRY your WPF/XAML label string resources with an Attached Property

DRY, like KISS (Keep It Simple Stupid), is one of those acronyms that one is unlikely to forget once you get the gist. It stands for Don’t Repeat Yourself and I have long been an adherent to this philosophy, but only recently was acquainted with the acronymic tie.
While working in WPF/XAML, I have see one such repetition battleground emerge: String resources in a .resx file.
Consider:
<data name="UserName" xml:space="preserve">
    <value>User Name</value>
</data>
Versus:
<data name="UserNameLabel" xml:space="preserve">
    <value>User Name:</value>
</data>
The latter might be intended to be used in XAML like:
<TextBlock Text="{x:Static res:Resources.UserNameLabel}" />
But now we can see the problem. If and when you take steps to internationalize, you have to translate both resources. And if you refactor, you have to manage both instances.  While I have seen a couple solutions to this problem, I happened upon an alternative idea, an Attached Property:
<TextBlock ns:Attached.LabelText="{x:Static res:Resources.UserName}" />
At this point, we have handily done away with the “colonated” version of the label (or hyphenated, etc.) in favor of the real, underlying resource. Now we have become more DRY (If I may use this sense).
The implementation is shockingly simple:
public class Attached
{
    public static string GetLabelText(DependencyObject obj)
    {
        return (string)obj.GetValue(LabelTextProperty);
    }
 
    public static void SetLabelText(DependencyObject obj, string value)
    {
        TextBlock textBlock = obj as TextBlock;
        if (textBlock != null)
        {
            textBlock.Text = string.Format("{0} :", value);
            //TODO: Make the string format a localizable resource
        }
        obj.SetValue(LabelTextProperty, value);
    }
    public static readonly DependencyProperty LabelTextProperty =
        DependencyProperty.RegisterAttached("LabelText",
            typeof(string),
            typeof(TextBlock),
            new UIPropertyMetadata("DefaultLabel"));
}
So where does that leave us? We should now be able to use this Attached Property to avoid string resource repetition, and that is a good thing. A similar approach will work for other Controls, text decorations, etc. Let me know if it works out for you.

0 comments:

Post a Comment