I have two classes with different properties, but both inherit some other base class:
public class BaseClass { }
public class ClassA : BaseClass
{
public string PropertyA { get; set; }
}
public class ClassB : BaseClass
{
public string PropertyB { get; set; }
}
Code-behind:
public ObservableCollection<BaseClass> Items { get; set; }
public MainWindow()
{
Items = new ObservableCollection<BaseClass>
{
new ClassA {PropertyA = "A"},
new ClassB {PropertyB = "B"}
};
}
And my XAML looks like this:
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding PropertyA, FallbackValue=''}"/>
<GridViewColumn DisplayMemberBinding="{Binding PropertyB, FallbackValue={x:Null}}"/>
</GridView>
</ListView.View>
</ListView>
When running in debug mode, the output window shows this:
System.Windows.Data Warning: 40 : BindingExpression path error: 'PropertyB' property not found on 'object' ''ClassA' (HashCode=66437409)'. BindingExpression:Path=PropertyB; DataItem='ClassA' (HashCode=66437409); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Warning: 40 : BindingExpression path error: 'PropertyA' property not found on 'object' ''ClassB' (HashCode=2764078)'. BindingExpression:Path=PropertyA; DataItem='ClassB' (HashCode=2764078); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
Is there a better way of handling bindings like these? Are there any performance implications, and is it better to use FallbackValue='' or FallbackValue={x:Null}?
Personally I just ignore them. If an item doesn't exist, it gets displayed as an empty string, which is usually what I prefer.
They are warnings in the debug window because they are simply warnings, not errors. They're warning you of a possible problem, but nothing bad will happen if you ignore them.
If it really bothers you, you can probably use a Template Column and specify different DataTemplates for the different object types.
<DataTemplate TargetType="{x:Type local:ClassA}">
<TextBlock Text="{Binding PropertyA}" />
</DataTemplate>
<DataTemplate TargetType="{x:Type local:ClassB}">
<TextBlock Text="{Binding PropertyB}" />
</DataTemplate>
I will also sometimes use a Converter which returns typeof(value)
, and use that type in a DataTrigger
<Style.Triggers>
<DataTrigger Value="{x:Type local:ClassA}"
Binding="{Binding Converter={StaticResource ObjectToTypeConverter}}">
<Setter Property="Text" Value="{Binding PropertyA}" />
</DataTrigger>
<DataTrigger Value="{x:Type local:ClassB}"
Binding="{Binding Converter={StaticResource ObjectToTypeConverter}}">
<Setter Property="Text" Value="{Binding PropertyB}" />
</DataTrigger>
</Style.Triggers>