由于目标类型,在 WPF 中链接 IValueConverter 时出现问题

Issue in chaining IValueConvertes in WPF becauase of target type

我试图将转换器链接为 Town 在 Is there a way to chain multiple value converters in XAML??

中的回答

我也喜欢通过检查 targetType 来使单个转换器更严格:-

if (targetType != typeof(bool))
        throw new InvalidOperationException("The target must be a     
boolean");

但是链失败了,因为最终目标类型与每个阶段的目标不同。

我可以删除类型检查以降低在大多数 SO 示例中给出的严格程度,但我更喜欢一个也尊重每个转换器类型检查的链接。例如。为了更好的单元测试等

此外,IValueConverter 接口没有公开目标类型,我发现自己很难添加该检查。

 public class InverseBooleanConverter : IValueConverter
    {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("The target must be a boolean");

        if (!(value is bool))
            throw new ArgumentException("Argument 'value' must be of type bool");

        return !(bool)value;
        }
         ....
     }

[ValueConversion(typeof(bool), typeof(Visibility))]
public class VisibilityFromBoolConverter : IValueConverter
    {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
        if (targetType != typeof(Visibility))
            throw new InvalidOperationException("The target must be a Visibility");

        if (!(value is bool))
            throw new ArgumentException("Argument 'value' must be of type bool");

        var isVisible = (bool)value;
        return isVisible ? Visibility.Visible : Visibility.Collapsed;
        }
        ....
     }

复合就像:-

            <Converters:ValueConverterGroup x:Key="InvertAndVisible">
                  <Converters:InverseBooleanConverter />
                  <Converters:VisibilityFromBoolConverter />
            </Converters:ValueConverterGroup>

但我从 InverseBooleanConverter 得到异常 "The target must be a boolean",因为它期望目标是 bool 而不是 Visibility(链的最终目标)。

我想你可能误解了targetType参数。 According to the doco,它是 target 绑定的类型 属性。

这意味着对于您的 InverseBooleanConverter,目标类型将是 System.Visibility 类型。

对于这种检查,您应该检查传入(绑定)对象的类型:

if (value != null && value.GetType() != typeof(bool))
    throw new InvalidOperationException("The target must be a boolean");

但是.... 我强烈建议您不要从您的转换器中抛出异常 - 这会减慢 UI 渲染的速度,并且它们可能会令人难以置信当你有一屏好东西时很难追踪(例如,你有一个包含几千行的网格,其中一个模板化数据网格单元格抛出异常 - 你将如何识别它?)。如果您坚持抛出异常,那么至少用 #if DEBUG 定义将其包围,这样它就不会出现在您的发布代码中。相反,你应该 return DependencyProperty.UnsetValue if your converter cannot successfully convert a value. This ensures you don't get hard to track runtime exceptions, and it also ensures the binding subsystem can use things like the FallbackValue.

原始 ValueConverterGroup 代码将最终的 targetType 传递到每个阶段,这就是您的检查失败的原因。您需要做的就是修改该行为以改为传递下一个转换器 targetType:

[ValueConversion(typeof(bool), typeof(Visibility))]
public class ValueConverterGroup : List<IValueConverter>, IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        for (int i = 0; i < this.Count(); i++)
        {
            var targ = (i == this.Count() - 1) 
                ? targetType 
                : (this[i + 1].GetType().GetCustomAttributes(typeof(ValueConversionAttribute), false).First() as ValueConversionAttribute).SourceType;
            value = this[i].Convert(value, targ, parameter, culture);
        }
        if (value.GetType() != (this.GetType().GetCustomAttributes(typeof(ValueConversionAttribute), false).First() as ValueConversionAttribute).TargetType)
            throw new InvalidOperationException("Last target must be of type " + targetType.Name);
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion      
}