只有当它是需要的类型时才绑定到接口(否则使用回退)?
Binding to interface only if it is the needed type (use fallback otherwise)?
我的 ViewModel
中有以下 属性
public IEquipment Equipment
{
get
{
return equipment;
}
set
{
if (equipment != value)
{
equipment = value;
InvokePropertyChanged("Equipment");
}
}
}
这个项目本身有一个bool
属性,它绑定到我的视图中的一个Ellipse
,我想将其用作指示项目:
<Ellipse Width="10" Height="10" Fill="{Binding Equipment.IsAvailable, Converter={StaticResource BoolToColorConverter}, FallbackValue=DarkGray}" Margin="1"/>
BoolToColorConverter
只是将颜色转换为绿色 (true
) 或红色 (false
)。在运行时 Equipment
可以是继承自 IEquipment
的两种 class 类型之一的实例。其中只有一个 IsAvailable
属性。在实践中,这很好用,我得到了红色或绿色的八倍……或者灰色,以防其他类型的设备处于活动状态。
问题是,每次 GUI 更新时,都会输出以下警告:
System.Windows.Data Warning: 40 : BindingExpression path error: 'IsAvailable' property not found on 'object'
如何避免这个问题?基本上我想绑定到这个 属性 只有当它是正确的类型时。
我可以想到两个解决方案,我不是特别喜欢:
- 只需将
IsAvailable
属性 添加到其他类型并将其设置为空值(BoolToColorConverter
可以处理空值和 returns 深灰色):这可能是对一个简单的 bool
没问题,但在我的实际情况下还有其他项目,这些项目非常 class 具体。
- 在代码隐藏中进行数据绑定:这可能有效。在启动时使用
Loaded
之类的事件在运行时根据类型手动设置绑定。但是,这对于后面的调试来说可能会很麻烦,因为项目中的所有其他 Bindings 都直接发生在 xaml 文件中。此外,Equipment
可能会在 ViewModel 的生命周期内发生变化,因此我必须以某种方式跟踪它。
Xaml 不绑定到接口,它绑定到具体类型。
如果您的类型具有不同的属性,那么您需要不同的 xaml 来绑定它们。
使用DataTemplates指定不同的xaml显示每种类型。
如果 IEquipment
的派生属性(此处以 Equipment
和 OtherEquipment
为例)差异很大并且不共享通用接口,则它们很可能在外貌。在这种情况下,每种类型都需要不同的 DataTemplate
。这是 ContentControl
的示例,但它与自动应用的隐式数据模板(不是 x:Key
,而是 DataType
)在 ItemsContol
中的工作方式相同。
<ContentControl Content="{Binding Equipment}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:Equipment}">
<Ellipse Width="10" Height="10" Fill="{Binding IsAvailable, Converter={StaticResource BoolToColorConverter}, FallbackValue=DarkGray}" Margin="1"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:OtherEquipment}">
<Ellipse Width="10" Height="10" Fill="DarkGray" Margin="1"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
针对您的特定问题的解决方法可能是编写自定义的专用值转换器。
public class EquipmentAvailabilityToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Equipment equipment)
return equipment.IsAvailable ? Brushes.Green : Brushes.Red;
return (Brush)parameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
<Ellipse Width="10" Height="10" Fill="{Binding Equipment, Converter={StaticResource EquipmentAvailabilityToColorConverter}, ConverterParameter={x:Static Brushes.DarkGray}}" Margin="1"/>
我的 ViewModel
中有以下 属性public IEquipment Equipment
{
get
{
return equipment;
}
set
{
if (equipment != value)
{
equipment = value;
InvokePropertyChanged("Equipment");
}
}
}
这个项目本身有一个bool
属性,它绑定到我的视图中的一个Ellipse
,我想将其用作指示项目:
<Ellipse Width="10" Height="10" Fill="{Binding Equipment.IsAvailable, Converter={StaticResource BoolToColorConverter}, FallbackValue=DarkGray}" Margin="1"/>
BoolToColorConverter
只是将颜色转换为绿色 (true
) 或红色 (false
)。在运行时 Equipment
可以是继承自 IEquipment
的两种 class 类型之一的实例。其中只有一个 IsAvailable
属性。在实践中,这很好用,我得到了红色或绿色的八倍……或者灰色,以防其他类型的设备处于活动状态。
问题是,每次 GUI 更新时,都会输出以下警告:
System.Windows.Data Warning: 40 : BindingExpression path error: 'IsAvailable' property not found on 'object'
如何避免这个问题?基本上我想绑定到这个 属性 只有当它是正确的类型时。 我可以想到两个解决方案,我不是特别喜欢:
- 只需将
IsAvailable
属性 添加到其他类型并将其设置为空值(BoolToColorConverter
可以处理空值和 returns 深灰色):这可能是对一个简单的bool
没问题,但在我的实际情况下还有其他项目,这些项目非常 class 具体。 - 在代码隐藏中进行数据绑定:这可能有效。在启动时使用
Loaded
之类的事件在运行时根据类型手动设置绑定。但是,这对于后面的调试来说可能会很麻烦,因为项目中的所有其他 Bindings 都直接发生在 xaml 文件中。此外,Equipment
可能会在 ViewModel 的生命周期内发生变化,因此我必须以某种方式跟踪它。
Xaml 不绑定到接口,它绑定到具体类型。
如果您的类型具有不同的属性,那么您需要不同的 xaml 来绑定它们。
使用DataTemplates指定不同的xaml显示每种类型。
如果 IEquipment
的派生属性(此处以 Equipment
和 OtherEquipment
为例)差异很大并且不共享通用接口,则它们很可能在外貌。在这种情况下,每种类型都需要不同的 DataTemplate
。这是 ContentControl
的示例,但它与自动应用的隐式数据模板(不是 x:Key
,而是 DataType
)在 ItemsContol
中的工作方式相同。
<ContentControl Content="{Binding Equipment}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:Equipment}">
<Ellipse Width="10" Height="10" Fill="{Binding IsAvailable, Converter={StaticResource BoolToColorConverter}, FallbackValue=DarkGray}" Margin="1"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:OtherEquipment}">
<Ellipse Width="10" Height="10" Fill="DarkGray" Margin="1"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
针对您的特定问题的解决方法可能是编写自定义的专用值转换器。
public class EquipmentAvailabilityToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Equipment equipment)
return equipment.IsAvailable ? Brushes.Green : Brushes.Red;
return (Brush)parameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
<Ellipse Width="10" Height="10" Fill="{Binding Equipment, Converter={StaticResource EquipmentAvailabilityToColorConverter}, ConverterParameter={x:Static Brushes.DarkGray}}" Margin="1"/>