仅当它是所需类型时绑定到接口(否则使用回退)?



我有以下属性在我的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的两个类类型之一的实例。其中只有一个具有IsAvailable属性。在实践中,这很好,我得到八个我的红色或绿色…或者一个灰色的,以防其他类型的设备处于活动状态。

问题是,每次GUI更新时,都会输出以下警告:

System.Windows。数据警告:40:BindingExpression路径错误:'IsAvailable'属性在'object'上找不到

如何避免这个问题?基本上,我想绑定到这个属性,只有当它是正确的类型。我可以想到两个解决方案,但我不是特别喜欢:

  1. 简单地将IsAvailable属性添加到其他类型并将其设置为null (BoolToColorConverter可以处理null值并返回深灰色):这可能是一个简单的bool,但在我的实际情况下,还有其他项目,这是相当类特定的。
  2. 在代码后面执行数据绑定:这可能有效。在启动时使用Loaded之类的事件,在运行时根据类型手动设置绑定。但是,这可能会给以后的调试带来麻烦,因为项目中的所有其他绑定都直接发生在xaml文件中。此外,Equipment可能在ViewModel的生命周期内发生变化,所以我必须以某种方式跟踪它。

Xaml不绑定到接口,它绑定到具体的类型。

如果你的类型有不同的属性,那么你需要不同的xaml来绑定它们。

使用datatemplate指定不同的xaml来显示每种类型。

如果您的IEquipment衍生物(这里以EquipmentOtherEquipment为例)的属性差异很大,并且没有共享公共接口,那么它们很可能在外观上有所不同。在这种情况下,每种类型都需要不同的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"/>

最新更新