VS2022中WPF的IValueConverter无法校验targetType为Visibility的问题
我有一个将null转换为Visible的IValueConverter,代码如下:
public class InverseNullToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (targetType != typeof(System.Windows.Visibility)) throw new InvalidOperationException("The target must be a Visibility"); if (value == null) return Visibility.Visible; return Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } }
该代码在Visual Studio 2019中运行正常,但升级到Visual Studio 2022后,所有使用该转换器的地方都出现错误,上述代码中的第一个if判断始终返回true。我使用的是.NET Framework 4.7.2,收到的错误码为XDG0066,错误信息为抛出的"The target must be a Visibility"。
转换器的使用示例如下:
<Rectangle x:Name="Back" Fill="{TemplateBinding Background}" Visibility="{TemplateBinding ImageBack, Converter={StaticResource InverseNullToVisibilityConverter}}"/>
请问为何VS2022中if (targetType != typeof(System.Windows.Visibility))判断失效?该如何修改才能正常工作?
原因
VS2022针对.NET Framework项目的XAML编译器进行了更新,在处理TemplateBinding时,传递给Convert方法的targetType会被包装为**可空类型(Nullable<Visibility>)**或通过类型包装器传递,直接使用typeof(System.Windows.Visibility)做严格相等判断会不匹配,导致条件始终为true,触发异常。而VS2019的旧版编译器没有这个行为差异,因此代码能正常运行。
修改方案
需要调整类型判断逻辑,兼容可空类型或类型包装的情况,有两种可行方案:
方案1:兼容可空类型
先获取可空类型的底层实际类型,再做判断:
var actualTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType; if (actualTargetType != typeof(System.Windows.Visibility)) throw new InvalidOperationException("The target must be a Visibility");
方案2:使用类型可分配性判断
利用Type.IsAssignableFrom判断目标类型是否兼容Visibility:
if (!typeof(System.Windows.Visibility).IsAssignableFrom(targetType)) throw new InvalidOperationException("The target must be a Visibility");
最终完整代码
推荐使用方案1,因为能明确处理可空类型场景,修改后的完整代码如下:
public class InverseNullToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var actualTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType; if (actualTargetType != typeof(System.Windows.Visibility)) throw new InvalidOperationException("The target must be a Visibility"); return value == null ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } }
修改后,转换器在VS2019和VS2022中都能正常工作,不会再触发XDG0066错误。
内容的提问来源于stack exchange,提问作者Kevin Uchiha

