Click here to Skip to main content
15,891,529 members
Articles / Desktop Programming / WPF

WPF LED User Control

Rate me:
Please Sign up or sign in to vote.
2.50/5 (5 votes)
12 Jun 2018CPOL1 min read 19.6K   932   1   3
This article proposes a way to create a WPF LED UserControl which works from any number of bitmaps, each of them corresponding to a LED "state" (color in fact).

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 !

C#
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,
        // ... Etc ... As you want !

        unknown,
    }

    /// <summary>
    /// Interaction logic for LEDControl.xaml
    /// LEDControl is a WPF UserControl which permits to manage a LED with as many states as needed...
    ///  Each state is represented with a color
    /// </summary>
    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:

XML
<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):

XML
<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:

C#
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
{
    /// <summary>
    /// Interaction logic for TelecodageModuleView.xaml
    /// </summary>
    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:

C#
/// <summary>
/// This converter can be used to bing a LEDControl on a nullable bool (bool?)
///   - When the nullable bool is set to null, LED will stay gray
///   - When the nullable bool is set to true, LED will become green
///   - When the nullable bool is set to false, LED will become red
/// </summary>
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):

XML
<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) :

C#
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
{
    /// <summary>
    /// Interaction logic for SeveralLEDsNullableBoolControl.xaml
    /// </summary>
    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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionDerive from Control Pin
Clifford Nelson13-Jun-18 6:33
Clifford Nelson13-Jun-18 6:33 
Question[My vote of 1] My Vote Of 1 Pin
Kevin Marois12-Jun-18 11:13
professionalKevin Marois12-Jun-18 11:13 
AnswerRe: [My vote of 1] My Vote Of 1 Pin
Graeme_Grant12-Jun-18 14:35
mvaGraeme_Grant12-Jun-18 14:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.