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>
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>
Share
Improve this question
asked Jan 19 at 7:32
Ludovic WagnerLudovic Wagner
891 silver badge9 bronze badges
2 Answers
Reset to default 1After 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>
I tried to do a quick mock to reproduce your issue, and couldn't. Where did I go wrong? What did we do differently? It scrolls just fine on my end.
<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"/>
</Window.Resources>
<Window.DataContext>
<models:MainViewModel/>
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding UtilityConsumptions}" AutoGenerateColumns="False">
<DataGrid.Columns>
<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>
<DataGridTextColumn Header="Utility Type" Binding="{Binding Source}" Width="200"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
namespace abstract_class_binding_issue
{
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
}
namespace Models
{
class MainViewModel
{
public IList UtilityConsumptions { get; } = new ObservableCollection<UtilityConsumptionModel>();
public MainViewModel()
{
object animation = UtilitySource.Electricity;
var s = $"{animation.GetType().Name}.{animation}";
for (int i = 0; i < 100; i++) // Add enough items for scrolling
{
if (i % 2 == 0)
{
UtilityConsumptions.Add(new UtilityNaturalGasConsumptionModel { ConversionCoefficient = i * 1.5 });
}
else
{
UtilityConsumptions.Add(new UtilityElectricityConsumptionModel());
}
}
}
}
abstract class UtilityConsumptionModel : INotifyPropertyChanged
{
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public event PropertyChangedEventHandler? PropertyChanged;
}
class UtilityElectricityConsumptionModel : UtilityConsumptionModel
{
public UtilitySource Source => UtilitySource.Electricity;
}
class UtilityNaturalGasConsumptionModel : UtilityConsumptionModel
{
public UtilitySource Source => UtilitySource.NaturalGas;
public double ConversionCoefficient
{
get => _conversionCoefficient;
set
{
if (!Equals(_conversionCoefficient, value))
{
_conversionCoefficient = value;
OnPropertyChanged();
}
}
}
double _conversionCoefficient = default;
}
enum UtilitySource
{
Electricity,
NaturalGas
}
}
}