WPF - Generic IValueConverter?
I have a need to convert a number of different objects and I'd like to avoid writing a converter class for each one. Each of the objects inherits from a base class and I need to use the Id to get the Description (which is handled in my call to my CacheManager).
For each class (I have about 30 of them) I have the following code written:
object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Dictionary<int, string> codes = CacheManager.CodeLookup<CourtEventCode>();
int id = 0;
string result = str开发者_开发知识库ing.Empty;
if (int.TryParse(value.ToString(), out id) && id > 0)
{
if (codes.ContainsKey(id))
{
result = codes[id];
}
else
{
result = "Unknown";
}
}
return result;
}
In the above example, CourtEventCode
represents the converter for this one class. Is there a way I can derive that class from the targetType input of IValueConverter.Convert instead of having to essentially copy-and-paste this class two dozen times?
Thanks in advance,
SonnyThis answer is an alternative to generics.
You could use a code generator to help speed things up by creating all the classes in one go. Create a blank 'TT' file, (You won't see it in the new item list, just type the extension in manually.) click OK on the warning dialog, and paste this into it. From there, play around until the output file looks right. The output file will be recreated each time you save the TT file.
// The code in this CS file is auto-generated.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
namespace WpfApplication
{
<#
string[] classes = new string[]
{"CourtEventCode", "SomeOtherCode", "WhatElseIsThere"};
foreach (string classname in classes)
{
#>
public class <#= classname #>ValueConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Dictionary<int, string> codes = CacheManager.CodeLookup< <#= classname #> >();
int id = 0;
string result = string.Empty;
if (int.TryParse(value.ToString(), out id) && id > 0)
{
if (codes.ContainsKey(id))
{
result = codes[id];
}
else
{
result = "Unknown";
}
}
return result;
}
// Implement the rest of IValueConverter
}
<# } #>
}
Yes, you can call CacheManager.CodeLookup using reflection.
Based on the code you've shared, it will be something like this:
Type containingType = typeof (CacheManager);
var method = containingType.GetMethod("CodeLookup",
BindingFlags.Static | BindingFlags.Public, null, new Type[0], new ParameterModifier[0]);
var concreteMethod = method.MakeGenericMethod(targetType);
Dictionary<string,int> codes = (Dictionary<string,int>)concreteMethod.Invoke(null, null);
Perhaps you will want to cache the concreteMethod
instance for each targetType if you are using the method a lot, reflection can be costly in terms of performance.
Edit: When the method is overloaded, in order to match a specific overload; use the GetMethod overload that allows you to specify the exact parameters, an pass in an empty array (since the overload you want to call has no parameters). Code example has been updated.
精彩评论