Introduction
I saw many articles about WPF LED Control, but I never found one which is as simple as this one ;-D
LEDControl UserControl Principle
This is the WPF LEDControl
code: we can see that the LEDState enum
type contains all "states" which corresponds in fact to colors. For each of these states, an image resource should be added: LED-gray.png image for gray LEDState
, LED-green.png for green state, etc. You can imagine as many states as you need !
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CommonGuiWpf.Controls
{
public enum LEDState
{
gray,
green,
red,
yellow,
unknown,
}
public partial class LEDControl : UserControl, INotifyPropertyChanged
{
private const string IMAGES_LOCATION = "/CommonGuiWpf;component/Images/";
private const string LED_IMAGES_PREFIX = "LED-";
private const string IMAGES_EXTENSION = ".png";
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string name = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
public LEDControl()
{
InitializeComponent();
}
static private void LEDControl_PropertyChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LEDControl lc = d as LEDControl;
if (lc != null)
lc.RaisePropertyChanged("ImageResName");
}
public static readonly DependencyProperty StateProperty =
DependencyProperty.Register("State", typeof(LEDState),
typeof(LEDControl), new UIPropertyMetadata(LEDState.gray, LEDControl_PropertyChanged));
public LEDState State
{
get { return (LEDState)GetValue(StateProperty); }
set
{
SetValue(StateProperty, value);
RaisePropertyChanged("ImageResName");
}
}
public string ImageResName
{
get
{
return IMAGES_LOCATION + LED_IMAGES_PREFIX + State.ToString() + IMAGES_EXTENSION;
}
}
}
And the corresponding XAML code is this one:
<UserControl x:Class="CommonGuiWpf.Controls.LEDControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Simudiag.Common.Controls"
mc:Ignorable="d"
d:DesignHeight="24" d:DesignWidth="24"
Width="24" Height="24"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Image Source="{Binding ImageResName}" />
</Grid>
</UserControl>
LEDControl Use
This is an example of another XAML UserControl
(called SeveralLEDsControl
) which is using it (excuse me if it doesn't work as is, I just copied a piece of my real UserControl
just to show an example of the use):
<UserControl x:Class="Example.SeveralLEDsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Simulator.Module.Telecodage"
xmlns:cguiwpfctrls="clr-namespace:CommonGuiWpf.Controls;assembly=CommonGuiWpf"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="1300"
x:Name="SeveralLEDsControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<cguiwpfctrls:LEDControl Grid.Row="0" Grid.Column="0" Margin="2"
State="{Binding LED1State, ElementName=SeveralLEDsControl}"/>
<TextBlock Text="{DynamicResource LED1Text}" VerticalAlignment="Center"
Grid.Row="0" Grid.Column="1" Margin="2"/>
<cguiwpfctrls:LEDControl Grid.Row="1" Grid.Column="0" Margin="2"
State="{Binding LED2State, ElementName=SeveralLEDsControl}}"/>
<TextBlock Text="{DynamicResource LED2Text}" VerticalAlignment="Center"
Grid.Row="1" Grid.Column="1" Margin="2"/>
<cguiwpfctrls:LEDControl Grid.Row="2" Grid.Column="0" Margin="2"
State="{Binding LED3State, ElementName=SeveralLEDsControl}}"/>
<TextBlock Text="{DynamicResource LED3Text}" VerticalAlignment="Center"
Grid.Row="2" Grid.Column="1" Margin="2"/>
</Grid>
</UserControl>
In this example, LEDControl
State is binded with the original property type (LEDState
): Corresponding code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CommonGuiWpf.Controls;
namespace Example
{
public partial class SeveralLEDsControl : UserControl, INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string name = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
public SeveralLEDsControl()
{
InitializeComponent();
}
protected LEDState _LED1State
LEDState LED1State
{
get { return _LED1State; }
set
{
if (_LED1State != value)
{
_LED1State = value;
RaisePropertyChanged();
}
}
}
protected LEDState _LED2State
LEDState LED2State
{
get { return _LED2State; }
set
{
if (_LED2State != value)
{
_LED2State = value;
RaisePropertyChanged();
}
}
}
protected LEDState _LED3State
LEDState LED3State
{
get { return _LED3State; }
set
{
if (_LED3State != value)
{
_LED3State = value;
RaisePropertyChanged();
}
}
}
}
Bind the LEDControl on nullable bool Properties to Simulate OK, KO or OFF
Often, a LED is used to show "OK" (green), "KO" (red), or "OFF" (gray)... That was my need, and so I wrote a WPF Converter to be able to bind a nullable bool
on my LEDControl UserControl
. This is the code of the converter:
public class NullableBool2LEDStateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value == null)
return LEDState.gray;
if (value is bool?)
{
if (((bool?)value).Value == true)
return LEDState.green;
else
return LEDState.red;
}
return LEDState.unknown;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value is LEDState)
{
if ((LEDState)value == LEDState.gray)
return null;
else if ((LEDState)value == LEDState.green)
return true;
else if ((LEDState)value == LEDState.red)
return false;
}
return null;
}
}
That way, the use of the LED control can be realized by this new UserControl
(binding is using the converter):
<UserControl x:Class="Example.SeveralLEDsNullableBoolControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Simulator.Module.Telecodage"
xmlns:cguiwpfctrls="clr-namespace:CommonGuiWpf.Controls;assembly=CommonGuiWpf"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="1300"
x:Name="SeveralLEDsControl">
<Grid>
<Grid.Resources>
<cguiwpfctrls:NullableBool2LEDStateConverter x:Key="NullableBool2LEDStateConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<cguiwpfctrls:LEDControl Grid.Row="0" Grid.Column="0" Margin="2"
State="{Binding LED1State, ElementName=SeveralLEDsControl,
Converter={StaticResource NullableBool2LEDStateConverter}}"/>
<TextBlock Text="{DynamicResource LED1Text}" VerticalAlignment="Center"
Grid.Row="0" Grid.Column="1" Margin="2"/>
<cguiwpfctrls:LEDControl Grid.Row="1" Grid.Column="0" Margin="2"
State="{Binding LED2State, ElementName=SeveralLEDsControl,
Converter={StaticResource NullableBool2LEDStateConverter}}"/>
<TextBlock Text="{DynamicResource LED2Text}" VerticalAlignment="Center"
Grid.Row="1" Grid.Column="1" Margin="2"/>
<cguiwpfctrls:LEDControl Grid.Row="2" Grid.Column="0" Margin="2"
State="{Binding LED3State, ElementName=SeveralLEDsControl,
Converter={StaticResource NullableBool2LEDStateConverter}}"/>
<TextBlock Text="{DynamicResource LED3Text}" VerticalAlignment="Center"
Grid.Row="2" Grid.Column="1" Margin="2"/>
</Grid>
</UserControl>
With this code (property types are nullable bool
) :
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CommonGuiWpf.Controls;
namespace Example
{
public partial class SeveralLEDsNullableBoolControl : UserControl, INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string name = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
public SeveralLEDsControl()
{
InitializeComponent();
}
protected bool? _LED1State
bool? LED1State
{
get { return _LED1State; }
set
{
if (_LED1State != value)
{
_LED1State = value;
RaisePropertyChanged();
}
}
}
protected bool? _LED2State
bool? LED2State
{
get { return _LED2State; }
set
{
if (_LED2State != value)
{
_LED2State = value;
RaisePropertyChanged();
}
}
}
protected bool? _LED3State
bool? LED3State
{
get { return _LED3State; }
set
{
if (_LED3State != value)
{
_LED3State = value;
RaisePropertyChanged();
}
}
}
}
Demo Screenshot
This is what you obtain when using the example with the 3 LEDs:
History
- 12th June, 2018: Article creation