WPF - 通用 IValueConverter?

发布于 2024-09-18 15:12:52 字数 823 浏览 3 评论 0原文

我需要转换许多不同的对象,并且我想避免为每个对象编写转换器类。每个对象都继承自一个基类,我需要使用 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 表示该类的转换器。有没有一种方法可以从 IValueConverter.Convert 的 targetType 输入派生该类,而不必基本上复制并粘贴该类两打?

预先感谢,
桑尼

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 = string.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,
Sonny

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

攒眉千度 2024-09-25 15:12:52

这个答案是泛型的替代方案。

您可以使用代码生成器一次性创建所有类来帮助加快速度。创建一个空白的“TT”文件(您不会在新项目列表中看到它,只需手动键入扩展名。)在警告对话框上单击“确定”,然后将其粘贴到其中。从那里开始尝试,直到输出文件看起来正确为止。每次保存 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
    }

<# } #>
}

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

<# } #>
}
亣腦蒛氧 2024-09-25 15:12:52

是的,您可以使用反射调用 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);

如果您经常使用该方法,也许您会希望为每个 targetType 缓存 concreteMethod 实例,反射可能会很昂贵的性能。

编辑:当方法重载时,为了匹配特定的重载;使用 GetMethod 重载,它允许您指定确切的参数,传入一个空数组(因为您要调用的重载没有参数)。代码示例已更新。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文