views:

68

answers:

3

Currently, I use value converters to generate user-friendly strings for the GUI. As an example, I have a window that displays the number of available entities in the status bar. The Viewmodel simply has an int dependency property that the calling code can set, and then on the binding for the textbox that displays the number of entities, I specify the int dependency property and a value converter that changes "x" into "x entities available".

My code is starting to become littered with these converters, and I have a large number of annoying resource declarations in my XAML, and yet I like them because all the GUI-specific string formatting is being isolated in the converters and the calling code doesn't have to worry about it. But still, I wonder if this is not the purpose that value converters were made for.

+1  A: 

I generally do this kind of conversion in the view model. So the view model will have a string dependency property, which "decorates" the underlying int value.

It's not clear from your question how the int value gets updated in your scenario, so that may be a factor in choosing the right solution.

Using the view model for this is more expressive IMHO--you are binding directly to what is being displayed, and your display logic (which I what I would consider it) is not buried in a converter that you can only find by looking through the XAML.

Phil Sandler
+2  A: 

It's not "wrong" if you are using the valueconverter for what it is designed to do. Personally i use them to translate enum values to friendly strings, but rather than hard coding the string in to the value converter the VC uses the enum value to source the string from a resource file.

In the specific case you mention, i would do things a little differently to cut down on the amount of VC's you have - you can do it with just one. What you are doing is substituting/inserting the value straight into a known string. What you can do is start using the ConverterParameter that is available to you, and use it to pass the ID of a string in your resource file, the value that is passed in to the VC can then be inserted into the string specified by the VCs ConverterParameter. Here is a quick pseudo code example:

public class MyConverter : IValueConverter
{
    public MyConverter()
    {
        _rm = new ResourceManager("[my_assembly_name].Resources.strings", Assembly.GetExecutingAssembly());
    }

    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (parameter is string && !string.IsNullOrEmpty((string)parameter))
        {
            string z = _rm.GetString((string)parameter);
            if (z != null)
            {
                return string.Format(z, value);
            }
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion

    ResourceManager _rm;
}

And you would use this converter like this:

<TextBlock Text={Binding someNumericValue, Converter={StaticResource MyConverter}, ConverterParameter=[key_to_resource_string]} />

Also have a look at WPF4 - IIRC it has an ability to be able to specify a format string as part of the binding expression, this may help you as well.

slugster
Though the format string seems to be the easiest solution, the keyed-resource file is also a good idea. In both approaches, its also good to think about how to incorporate internationalization. I guess your approach would be the best, wherein depending on the culture, the VC could switch among different resource files corresponding to different cultures which all have the same keys.
tempy
+1  A: 

As @slugster mentioned, the StringFormat property can be specified in the Binding, although it is available as of .NET 3.5sp1. This is how I typically specify these types of formats:

<TextBlock Text="{Binding x, StringFormat={}{0} entities available.}" />

This enables your ViewModels to only specify the data that is required to display, and easily allows the view to format the data however it wants. IMO, this is the cleanest line of separation between the view and the viewmodel.

Note that the {} is required to escape the {0} as it is the first element after the StringFormat property.

Abe Heidebrecht
Exactly what I need! The syntax highlighting in VS2010 has a funny reaction to this, though it works perfectly.
tempy