Reputation: 23
I am trying to simulate LED indicators in my WPF App (around 16). I get 2 bytes from serial port, and based on the bits, I need to turn ON/OFF the LED indicators on my App window. Example: 0xFF, 0xFE => all but the last LED are ON. I am using labels with a dark background color to indicate an OFF LED, and a bright background color for an ON LED. If I have an array of labels, then I could possibly do something like this:
for(i = 0; i < 16; i++)
{
if(bitArray[i] == true)
lblLED[i].Background = Brushes.Pink;
else
lblLED[i].Background = Brushes.Maroon;
}
Any suggestions on whats the best way to do this? A sample code which can show how this would work will be helpful. Thanks!
Upvotes: 1
Views: 5433
Reputation: 31586
The concepts covered are INotifyPropertyChanges (in .net 4.5 (minimal changes for other versions but same concept)), ItemsControl and finally style triggers.
My first step is to put INotifyPropertyChanges on our mainwindow to notify the WPF controls of any changes automatically. You will convert your bit array to a list and simply drop it in (maybe on a timer?) when needed. Note it doesn't matter how many there are...the control will expand.
public partial class MainWindow : Window, INotifyPropertyChanged
{
private List<bool> _LedStates;
public List<bool> LedStates
{
get { return _LedStates; }
set
{
_LedStates = value;
NotifyPropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
LedStates = new List<bool>() {true, false, true};
}
#region INotifyPropertyChanged
/// <summary>
/// Event raised when a property changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises the PropertyChanged event.
/// </summary>
/// <param name="propertyName">The name of the property that has changed.</param>
protected virtual void NotifyPropertyChanged( [CallerMemberName] String propertyName = "" )
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler( this, new PropertyChangedEventArgs( propertyName ) );
}
}
#endregion
}
Then in the WPF xaml we will bind to the list of bools and use an item template (think a generic mini view for each data item found). Within that template we will show a color of red or green depending on the state of the boolean.
No converter needed because we setup a style trigger which is attune to a target value. If the Textblocks text is "True" we will show Green and when "False" we will trigger/show red.
<Window x:Class="WPFBindToArray.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ItemsControl x:Name="icBitViewer"
ItemsSource="{Binding LedStates}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel HorizontalAlignment="Stretch"
IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Grid.Column="0">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="Text" Value="True">
<Setter Property="Background" Value="Green" />
</Trigger>
<Trigger Property="Text" Value="False">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
When this program is run here is the result:
Upvotes: 1
Reputation: 856
I'm sure you could figure out how to do what you're asking, but let's consider the tools at hand? You have an array of bool, it seems. As was suggested, an ItemsControl can handle them just wonderfully. First, let's do some code-behind to transform our bool's into brushes to set the background of our items.
using System;
using System.Windows.Media;
using System.Windows.Data;
using System.Globalization;
namespace MyNamespace
{
public class BoolToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// return a Pink SolidColorBrush if true, a Maroon if false
return (bool)value ? Brushes.Pink : Brushes.Maroon;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (SolidColorBrush)value == Brushes.Pink;
}
}
}
This will allow you to translate your bool[] bitArray
into a series of brushes when bound to an ItemsControl
. Now for some Xaml :
First, make sure you declare your local namespace (which contains the converter we just defined) in the xmlns attributes as well as the System Core Library (see the xmlns attributes).
<Window x:Class="MyNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<!-- our local namespace -->
xmlns:my="clr-namespace:MyNamespace"
<!-- system core library -->
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="600" Width="900">
<Grid>
<ItemsControl Name="LEDPanel"> <!-- Need to Name this Control in order to set the ItemsSource Property at startup -->
<ItemsControl.Resources>
<my:BoolToBrushConverter x:Key="LEDConverter" /> <!-- Here we define our converter for use, note the preceding my: namespace declaration -->
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" /> <!-- this will make the items defined in the ItemTemplate appear in a row -->
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type sys:Boolean}"> <-- We will be binding our ItemsControl to a bool[] so each Item will be bound to a bool -->
<Border Margin="3" CornerRadius="10" Height="20" Width="20" BorderThickness="2" BorderBrush="Silver" Background="{Binding Converter={StaticResource LEDConverter}}" />
<!-- This is where we describe our item. I'm drawing a round silver border and then binding the Background to the item's DataContext (implicit) and converting the value using our defined BoolToBrushConverter -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
Edit: I forgot the DataBinding. In your Window's constructor:
public MainWindow()
{
InitializeComponent();
LEDPanel.ItemsSource = bitArray;
}
Upvotes: 2
Reputation: 8459
Try this. It's clearly just an example, I advice you to use the features of WPF and maybe use a different control than a Label
.
Func<ushort, bool[]> getBits = s =>
{
var bools = new bool[sizeof (ushort)*8];
for (var i = 0; i < bools.Length; i++)
bools[i] = (s & 1 << i) > 0;
return bools;
};
var bits = getBits(2);
var labels = new Label[sizeof (ushort)*8];
for (var i = 0; i < labels.Length; i++)
{
var label = new Label {Background = bits[i] ? Brushes.Green : Brushes.Red};
labels[i] = label;
}
//Do something with the Label array
Upvotes: 0