Ludovic Wagner
Ludovic Wagner

Reputation: 117

How to bind to different abstract class implementations with additional properties without binding failure in WPF

I implemented the classes UtilityElectricityConsumptionModel and UtilityNaturalGasConsumptionModel from the abstract class UtilityConsumptionModel. The UtilityNaturalGasConsumptionModel just has the extra ConversionCoefficient property added.

I bind to ConversionCoefficient in a DataGrid via the DataGridTemplateColumn and Trigger. I don't get any binding failure initially, but I get binding failures since I begin scrolling the DataGrid. Is there a way to avoid these binding failures?

<!--  Conversion Coefficient  -->
<DataGridTemplateColumn Width="100" Header="Conversion Coefficient">

    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>

            <TextBlock>

                <TextBlock.Style>

                    <Style TargetType="{x:Type TextBlock}">

                        <Setter Property="HorizontalAlignment" Value="Stretch" />
                        <Setter Property="Background" Value="{StaticResource PrimarySolidColorBrush}" />

                        <Style.Triggers>

                            <DataTrigger Binding="{Binding Source}" Value="{x:Static models:UtilitySource.NaturalGas}">

                                <Setter Property="Padding" Value="2,0,2,0" />
                                <Setter Property="HorizontalAlignment" Value="Right" />
                                <Setter Property="Background" Value="Transparent" />
                                <Setter Property="Text" Value="{Binding ConversionCoefficient, StringFormat='0.00'}" />

                            </DataTrigger>

                        </Style.Triggers>

                    </Style>

                </TextBlock.Style>

            </TextBlock>

        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>

</DataGridTemplateColumn>

Upvotes: 1

Views: 39

Answers (1)

IV.
IV.

Reputation: 9438

After testing the "quick mock" in my other post, it occurred to me that there is an improved approach that might answer your question:

Is there a way to avoid these binding failures?

Use a DataTemplateSelector in place of the DataTrigger stategy.


public class UtilityConsumptionTemplateSelector : DataTemplateSelector
{
    public DataTemplate? ElectricityTemplate { get; set; }
    public DataTemplate? NaturalGasTemplate { get; set; }

    public override DataTemplate? SelectTemplate(object item, DependencyObject container)
    {
        if (item is UtilityElectricityConsumptionModel)
        {
            return ElectricityTemplate;
        }
        if (item is UtilityNaturalGasConsumptionModel)
        {
            return NaturalGasTemplate;
        }
        return base.SelectTemplate(item, container);
    }
}

<Window x:Class="abstract_class_binding_issue.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:abstract_class_binding_issue"
        xmlns:models="clr-namespace:abstract_class_binding_issue.Models"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="400">
    <Window.Resources>
        <SolidColorBrush x:Key="PrimarySolidColorBrush" Color="LightGray"/>
        <DataTemplate x:Key="ElectricityTemplate">
            <TextBlock Text="Electricity" Background="{StaticResource PrimarySolidColorBrush}" HorizontalAlignment="Center"/>
        </DataTemplate>
        <DataTemplate x:Key="NaturalGasTemplate">
            <TextBlock Text="{Binding ConversionCoefficient, StringFormat='0.00'}"
                   Background="Transparent" HorizontalAlignment="Right" Padding="2,0,2,0"/>
        </DataTemplate>
        <local:UtilityConsumptionTemplateSelector 
            x:Key="UtilityTemplateSelector"
            ElectricityTemplate="{StaticResource ElectricityTemplate}"
            NaturalGasTemplate="{StaticResource NaturalGasTemplate}" />
        </Window.Resources>
        <Window.DataContext>
        <models:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <DataGrid ItemsSource="{Binding UtilityConsumptions}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTemplateColumn Width="100" Header="Conversion Coefficient"
                                    CellTemplateSelector="{StaticResource UtilityTemplateSelector}" />
                <DataGridTextColumn Header="Utility Type" Binding="{Binding Source}" Width="200"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Upvotes: 2

Related Questions