我的自定义值转换器导致 XAML 验证工具失败
My custom value converter causes XAML validation tool to fail
我创建了一个自定义转换器,它根据配置的映射执行值的转换。看起来像下面
public class UniversalConverter : List<ConverterItem>, IValueConverter
{
private bool useDefaultValue;
private object defaultValue;
public object DefaultValue
{
get { return defaultValue; }
set
{
defaultValue = value;
useDefaultValue = true;
}
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
foreach (var item in this)
if (Equals(item.From, value))
return item.To;
if (useDefaultValue)
return DefaultValue;
throw new ConversionException(string.Format("Value {0} can't be converted and default value is not allowed", value));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
foreach (var item in this)
if (Equals(item.To, value))
return item.From;
throw new ConversionException(string.Format("Value {0} can't be converted back", value));
}
}
public class ConverterItem
{
public object From { get; set; }
public object To { get; set; }
}
public class ConversionException : Exception
{
public ConversionException() { }
public ConversionException(string message) : base(message) { }
}
样本XAML如下
<core:UniversalConverter x:Key="ItemCountToVisiblityConverter" DefaultValue="{x:Static Visibility.Collapsed}">
<core:ConverterItem To="{x:Static Visibility.Visible}">
<core:ConverterItem.From>
<system:Int32>0</system:Int32>
</core:ConverterItem.From>
</core:ConverterItem>
</core:UniversalConverter>
现在一切正常,但如果我使用它 XAML Visual Studio 会用弯曲的蓝线强调整个文件并显示两种错误:
1) 如果转换器被放入 ResourceDictionary
并且被分配了一个 x:Key
属性,它显示 Missing key value on 'UniversalConverter' object
2) 如果我分配 DefaultValue
属性 任何值(例如 {x:Null}
),则消息是 XAML Node Stream: Missing EndMember for 'StuffLib.UniversalConverter.{http://schemas.microsoft.com/winfx/2006/xaml}_Items' before StartMember 'StuffLib.UniversalConverter.DefaultValue'
这些消息的原因是什么?我可以接受它们,但它们隐藏了所有其他编译器和 ReSharper 标记
这是因为它在设计时正在使用,但没有数据,所以我怀疑抛出了 NullReferenceException。尝试在 IValueConverter.Convert() 方法主体的顶部检查设计时模式,如下所示:
// Check for design mode.
if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue))
{
return false;
}
不要从列表继承,只需在转换器中创建项目 属性:
[ContentProperty("Items")]
public class UniversalConverter : IValueConverter
{
public ConverterItem[] Items { get; set; }
public object DefaultValue { get; set; }
//all other stuff goes here
}
和xaml:
<l:UniversalConverter x:Key="MyConverter">
<x:Array Type="l:ConverterItem">
<l:ConverterItem From="..." To="..." />
根据@Leiro 的回答
[ContentProperty("Items")]
public class UniversalConverter : IValueConverter
{
public UniversalConverter()
{
Items = new List<ConverterItem>();
}
public List<ConverterItem> Items { get; private set; }
//All other logic is the same
}
请注意,这样您就不需要在 XAML
中包装集合中的项目
结果XAML
<core:UniversalConverter x:Key="ItemCountToVisiblityConverter" DefaultValue="{x:Static Visibility.Collapsed}">
<core:ConverterItem To="{x:Static Visibility.Visible}">
<core:ConverterItem.From>
<system:Int32>0</system:Int32>
</core:ConverterItem.From>
</core:ConverterItem>
</core:UniversalConverter>
我创建了一个自定义转换器,它根据配置的映射执行值的转换。看起来像下面
public class UniversalConverter : List<ConverterItem>, IValueConverter
{
private bool useDefaultValue;
private object defaultValue;
public object DefaultValue
{
get { return defaultValue; }
set
{
defaultValue = value;
useDefaultValue = true;
}
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
foreach (var item in this)
if (Equals(item.From, value))
return item.To;
if (useDefaultValue)
return DefaultValue;
throw new ConversionException(string.Format("Value {0} can't be converted and default value is not allowed", value));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
foreach (var item in this)
if (Equals(item.To, value))
return item.From;
throw new ConversionException(string.Format("Value {0} can't be converted back", value));
}
}
public class ConverterItem
{
public object From { get; set; }
public object To { get; set; }
}
public class ConversionException : Exception
{
public ConversionException() { }
public ConversionException(string message) : base(message) { }
}
样本XAML如下
<core:UniversalConverter x:Key="ItemCountToVisiblityConverter" DefaultValue="{x:Static Visibility.Collapsed}">
<core:ConverterItem To="{x:Static Visibility.Visible}">
<core:ConverterItem.From>
<system:Int32>0</system:Int32>
</core:ConverterItem.From>
</core:ConverterItem>
</core:UniversalConverter>
现在一切正常,但如果我使用它 XAML Visual Studio 会用弯曲的蓝线强调整个文件并显示两种错误:
1) 如果转换器被放入 ResourceDictionary
并且被分配了一个 x:Key
属性,它显示 Missing key value on 'UniversalConverter' object
2) 如果我分配 DefaultValue
属性 任何值(例如 {x:Null}
),则消息是 XAML Node Stream: Missing EndMember for 'StuffLib.UniversalConverter.{http://schemas.microsoft.com/winfx/2006/xaml}_Items' before StartMember 'StuffLib.UniversalConverter.DefaultValue'
这些消息的原因是什么?我可以接受它们,但它们隐藏了所有其他编译器和 ReSharper 标记
这是因为它在设计时正在使用,但没有数据,所以我怀疑抛出了 NullReferenceException。尝试在 IValueConverter.Convert() 方法主体的顶部检查设计时模式,如下所示:
// Check for design mode.
if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue))
{
return false;
}
不要从列表继承,只需在转换器中创建项目 属性:
[ContentProperty("Items")]
public class UniversalConverter : IValueConverter
{
public ConverterItem[] Items { get; set; }
public object DefaultValue { get; set; }
//all other stuff goes here
}
和xaml:
<l:UniversalConverter x:Key="MyConverter">
<x:Array Type="l:ConverterItem">
<l:ConverterItem From="..." To="..." />
根据@Leiro 的回答
[ContentProperty("Items")]
public class UniversalConverter : IValueConverter
{
public UniversalConverter()
{
Items = new List<ConverterItem>();
}
public List<ConverterItem> Items { get; private set; }
//All other logic is the same
}
请注意,这样您就不需要在 XAML
中包装集合中的项目结果XAML
<core:UniversalConverter x:Key="ItemCountToVisiblityConverter" DefaultValue="{x:Static Visibility.Collapsed}">
<core:ConverterItem To="{x:Static Visibility.Visible}">
<core:ConverterItem.From>
<system:Int32>0</system:Int32>
</core:ConverterItem.From>
</core:ConverterItem>
</core:UniversalConverter>