How to render a text conditionally, based on a value form a list?

I’m using a ListBox to display a list in my C# user control. This is my list:

private ObservableCollection<AlarmInfo> _widgetData = new ObservableCollection<AlarmInfo>() {
    new AlarmInfo
    {
        AlarmType = "warning",
        AlarmLabel = "PLC Alarm 1",
        AlarmTimeStamp = new DateTime()
    },
    new AlarmInfo
    {
        AlarmType = "error",
        AlarmLabel = "Vision Error A",
        AlarmTimeStamp = new DateTime()
    },
    new AlarmInfo
    {
        AlarmType = "warning",
        AlarmLabel = "PLC Alarm 2",
        AlarmTimeStamp = new DateTime()
    },
    new AlarmInfo
    {
        AlarmType = "warning",
        AlarmLabel = "PLC Alarm 3",
        AlarmTimeStamp = new DateTime()
    },
};

I want to display the letter W if the AlarmType is warning and display the letter E if the AlarmType is error.

This is my XAML file. Right now it’s only showing the alarm type itself.

<ListBox Margin="20" ItemsSource="{Binding Path=WidgetData}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <!--I want to the conditional rendering here-->
                <TextBlock Text="{Binding AlarmType}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

I’m really new to this tech stack. Can anyone help me with this?

Answer

You can use DataTriggers to check for the values and set the Text accordingly.

<TextBlock DataContext="{Binding AlarmType}">
   <TextBlock.Style>
      <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
         <Setter Property="Text" Value="{x:Static system:String.Empty}"/>
         <Style.Triggers>
            <DataTrigger Binding="{Binding}" Value="warning">
               <Setter Property="Text" Value="W"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding}" Value="error">
               <Setter Property="Text" Value="E"/>
            </DataTrigger>
         </Style.Triggers>
      </Style>
   </TextBlock.Style>
</TextBlock>

Alternatively, you can use a value converter (this one could even be two-way if needed).

public class AlarmTypeConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      if (!(value is string alarmType))
         return null;

      switch (alarmType)
      {
         case "warning": return "W";
         case "error": return "E";
         default: return null;
      }
   }

   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
      throw new NotImplementedException("Not needed right now.");
   }
}

In XAML you can create an instance of the converter and use it for the Text binding.

<DataTemplate>
   <DataTemplate.Resources>
      <local:AlarmTypeConverter x:Key="AlarmTypeConverter"/>
   </DataTemplate.Resources>
   <StackPanel Orientation="Horizontal">
      <TextBlock Text="{Binding AlarmType, Converter={StaticResource AlarmTypeConverter}}"/>
   </StackPanel>
</DataTemplate>

As a general note on your AlarmType property. Consider creating string constants for each type of alarms if you really need to use strings here, so you reduce the risk of errors due to typos. Even better would be to create a dedicated enum that convers all alarm types.

public enum AlarmType
{
   Warning,
   Error
}

Leave a Reply

Your email address will not be published. Required fields are marked *