WPF - универсальный IValueConverter? - PullRequest
4 голосов
/ 08 сентября 2010

Мне нужно преобразовать несколько различных объектов, и я бы хотел избежать написания класса конвертера для каждого из них. Каждый из объектов наследуется от базового класса, и мне нужно использовать Id, чтобы получить описание (которое обрабатывается при моем вызове моего CacheManager).

Для каждого класса (у меня их около 30) написан следующий код:

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 = string.Empty;

    if (int.TryParse(value.ToString(), out id) && id > 0)
    {
        if (codes.ContainsKey(id))
        {
            result = codes[id];
        }
        else
        {
            result = "Unknown";
        }
    }

    return result;
}

В приведенном выше примере CourtEventCode представляет преобразователь для этого одного класса. Есть ли способ, которым я могу получить этот класс из ввода targetType IValueConverter.Convert вместо необходимости по существу копировать и вставлять этот класс два десятка раз?

Заранее спасибо,
Sonny

Ответы [ 2 ]

2 голосов
/ 08 сентября 2010

Этот ответ является альтернативой универсальным.

Вы можете использовать генератор кода, чтобы ускорить процесс, создав все классы за один раз.Создайте пустой файл 'TT', (Вы не увидите его в новом списке элементов, просто введите расширение вручную.) Нажмите OK в диалоговом окне предупреждения и вставьте его в него.Оттуда поиграйте, пока выходной файл не будет выглядеть правильно.Выходной файл будет воссоздан при каждом сохранении файла TT.

// 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
    }

<# } #>
}
1 голос
/ 08 сентября 2010

Да, вы можете вызвать CacheManager.CodeLookup, используя отражение.

На основании кода, которым вы поделились, это будет примерно так:

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);

Возможно, вы захотите кэшировать экземпляр concreteMethod для каждого targetType, если вы часто используете метод, отражение может быть дорогостоящим с точки зрения производительности.

Редактировать : когда метод перегружен, чтобы соответствовать определенной перегрузке; используйте перегрузку GetMethod, которая позволяет вам указать точные параметры, проход в пустой массив (так как перегрузка, которую вы хотите вызвать, не имеет параметров). Пример кода обновлен.

...