WPF 借助 FuncValueConverter 实现可显示自定义文本的通用枚举项选择弹窗

WPF 借助 FuncValueConverter 实现可显示自定义文本的通用枚举项选择弹窗

WPF 借助 FuncValueConverter 实现可显示自定义文本的通用枚举项选择弹窗

独立观察员 2025 年 1 月 12 日

 

一、前言

首先来解释一下标题中的 FuncValueConverter ,它并不是 WPF 中自带的,而是 B 站 UP 主 “十月的寒流” 在文章《WPF 值转换器(ValueConverter)的一些实用技巧》中,仿照 Avalonia UI 实现的一个同名转换器,具体可见 “仿照 Avalonia UI 实现一个 FuncValueConverter” 一节:

Avalonia UI 中有一个有趣的 FuncValueConverter,它允许我们直接在代码后台简单地声明一个值转换器,而不需要额外写一个类。它地源代码可以在 GitHub 上看到。我们可以仿照这个实现一个类似的值转换器。

 

代码我已迁移到 “WPFTemplateLib” 中了(https://gitee.com/dlgcy/WPFTemplateLib/blob/master/WpfConverters/Core/FuncValueConverter.cs):

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;

namespace WPFTemplateLib.WpfConverters.Core
{
    /// <summary>
    /// Func 委托(带一个参数和一个返回值)值转换器类型。(可在 VM 中声明一个此类型的值转换器以供前台绑定)<para/>
    /// 来自:https://blog.coldwind.top/posts/valueconverter-tips-and-tricks/
    /// </summary>
    /// <example>
    /// <![CDATA[
    /// 声明:
    /// public static FuncValueConverter<string, int> StringToIntConverter { get; } = new(s => int.Parse(s));
    /// 绑定:
    /// Converter={x:Static local:MainViewModel.StringToIntConverter}
    /// ]]>
    /// </example>
    public sealed class FuncValueConverter<TIn, TOut> : IValueConverter
    {
        private readonly Func<TIn, TOut> _convert;

        public FuncValueConverter(Func<TIn, TOut> convert)
        {
            _convert = convert;
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value is not TIn t)
            {
                if(value is null)
                {
                    return default(TOut);
                }

                //能被内置类型转换器装换;
                if(TypeDescriptor.GetConverter(typeof(TIn)).CanConvertFrom(value.GetType()))
                {
                    t = (TIn)TypeDescriptor.GetConverter(typeof(TIn)).ConvertFrom(value);
                }
                else
                {
                    return Binding.DoNothing;
                }
            }

            return _convert(t);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Binding.DoNothing;
        }
    }
}

 

二、效果和调用方式

先展示一下效果,方便大家判断是否要阅读本文。

以下动图展示了绑定了同一个枚举类型的两个枚举项选择弹窗,一个弹窗中显示的是枚举的描述,另一个弹窗中显示的是枚举的自定义显示文本:

getImage

 

枚举定义如下:

getImage-2

 

自定义文本如下:

getImage-1

 

调用方式,可以看到,两个弹窗创建时都需要一个枚举列表参数和一个当前选中项参数,显示自定义文本的弹窗比显示枚举描述的弹窗多传一个自定义文本参数:

getImage-3

 

三、显示枚举描述的选择枚举弹窗

getImage-4

 

先来看看 .cs 代码:

getImage-5

 

也很简单,就是一个窗口类,然后有三个绑定属性(使用 Fody 简化,并在前端将 DataContext 设为自身):一个标题、一个 Enum 类型的集合作为候选项,一个 Enum 类型的选中项。

 

前端关键代码如下图(图中有具体解释,就不再赘述了),其中内容显示部分中用了一个获取枚举描述的转换器 GetEnumDescriptionConverter 将枚举描述显示出来:

getImage-6

 

四、显示自定义文本的选择枚举弹窗

getImage-7

 

后台其它部分和之前一样,多了一个静态的 FuncValueConverter 类型的转换器 ShowCustomTextConverter、一个键值对字符串字段、以及相应的赋值逻辑。其中,ShowCustomTextConverter 转换器的转换方法中调用了常规的 BindAsKeyFindValueInParaConverter 转换器(在 WPFTemplateLib 包中有),用于将绑定内容的字符串形式作为 Key 在参数中查找 Value 字符串:

getImage-8

 

Xaml 关键代码:

getImage-9

 

可以看出,主要还是靠 BindAsKeyFindValueInParaConverter 转换器(包中还有类似的 BindAsKeyFindValueInPropertyConverter )起作用, FuncValueConverter 只是起到一个中转的目的,那么为什么要这样呢?

实际上,显示选择的结果那里就是直接使用了 BindAsKeyFindValueInPropertyConverter ,并指定了一个特定的查找字符串(和调用弹窗时指定的一样):

getImage-10

 

然而我们这次的弹窗是通用弹窗,不能定死查找字符串。而无论是使用 BindAsKeyFindValueInParaConverter 时通过 ConverterParameter 传递参数,还是使用 BindAsKeyFindValueInPropertyConverter 时通过属性传递参数,它们都只能定死地传,不能动态地传,换句话说就是不能使用绑定,前者是因为不能绑定,后者是因为在其中创建不了依赖属性。所以看到之前有人在某个交流群中抱怨 WPF 转换器的 ConverterParameter 不能使用绑定,这确实是个遗憾,不过本文的方法应该可以曲线救国了。

 

五、资源

Demo 代码地址:https://gitee.com/dlgcy/DLGCY_WPFPractice/tree/Blog20250112 

getImage-11

 

其它出现的,无论提到或未提到的,都可在 WPFTemplateLib 项目(NuGet 包)中找到:

getImage-12

 

 

原创文章,转载请注明: 转载自 独立观察员(dlgcy.com)

本文链接地址: [WPF 借助 FuncValueConverter 实现可显示自定义文本的通用枚举项选择弹窗](https://dlgcy.com/wpf-use-funcvalueconverter-make-an-enum-item-select-dialog-which-can-show-custom-text/)

关注微信公众号 独立观察员博客(DLGCY_BLOG) 第一时间获取最新文章

%title插图%num

发表评论