The things you are looking for are templates and one of the list controls (such as a ListBox). What you would do is create a class that represents the state of the hardware, and then have a class that holds a collection of these hardware state classes. Something like this:
public class HardwareState : INotifyPropertyChanged
{
private bool lightOn;
public bool LightOn
{
get { return lightOn; }
set
{
if (lightOn != value)
{
lightOn = value;
RaiseNotification("LightOn");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseNotification(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class HardwareStateManager {
public ObservableCollection<HardwareState> State { get; set; }
}
Now, you simply need to bind to this class in your view:
<Window.DataContext>
<vm:HardwareStateManager />
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Key="LightsTemplate">
<uc:MyLightControl />
</DataTemplate>
<Style TargetType="{x:Type ListBox}">
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<ScrollViewer Orientation="Horizontal">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding State}" ItemsTemplate="{StaticResource LightsTemplate}" />
</Grid>
Note - I've missed out the definition of the vm and uc namespace here - you would add these as xaml:vm="clr-namespace:...." references in the window declaration.
Finally, I just typed this out in the CP editor window - some of this might be 100% correct in the styling, as I'm just doing this from memory, but it should get you started.