1
votes

I have this project where I would like to set some images to my screen by adding a custom control (inSignalLight) to a listbox (or some other control, I would just like to line them up). I have set the images in the custom controls and added them to a "ObservableCollection", but nothing shows up. Im really new to WPF, so not quite sure if the xaml is corrent... If there is a better way to do it then in a listbox, please tell me so too.

inSignalLights = new ObservableCollection<inSignalLight>();

Here is the xaml in the page that I would like to show the pictures in.

<Page x:Class="Project.Pages.MainPicView"
  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" 
  mc:Ignorable="d" 

  HorizontalAlignment="Stretch"
  VerticalAlignment="Stretch"
  Background="Beige"
Title="MainPicView" d:DesignHeight="343" d:DesignWidth="676">

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Label Content="Label" Height="30" HorizontalAlignment="Left" Margin="61,195,0,0" Name="label1" VerticalAlignment="Top" Width="164" />
    <ListBox ItemsSource="{Binding Path=inSignalLights}" Width="400" Height="25" Margin="0,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Grid>
</Page>

Edit:

This is the xaml for the custom control

<UserControl x:Class="Project.CustomControls.inSignalLight"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="16" d:DesignWidth="16">
<Grid>
    <Image Height="16" HorizontalAlignment="Left" Margin="0,0,0,0" Name="signalImage" Stretch="Fill" VerticalAlignment="Top" Width="16" />
</Grid>
</UserControl>

Edit:

for (int i = 0; i < inpins; i++)
        {
            InPin ip = iFace.getInPin(i);
            parent.insertNewSignalLight(ip);
        }

public void insertNewSignalLight(InPin ip)
    {
        inSignalLight isl = new inSignalLight(ip);
        isl.setLightOff();
        this.inSignalLights.Add(isl.signalImage);
    }
public void setLightOff()
    {
        setThreadSafeImage(signalImage);
    }

    private void gotLightSignal(InPin pin, EventArgs e)
    {
        Thread.CurrentThread.Join(200);
        if (pin.PinState == 1)
            setLightOn();
        else
            setLightOff();
    }
    public void setThreadSafeImage(Image iS)
    {
        string strUri2 = String.Format(@"pack://application:,,,/;component/Images/Signal_Gron_16.png");
        BitmapImage img = new BitmapImage(new Uri(strUri2));
        img.Freeze();

        iS.Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                        new Action(() => iS.Source = img));

    }
2

2 Answers

1
votes

You should have ObservableCollection<ImageSource> Images in your ViewModel. I think your UserControl with Image is unnecessary.

You must define ItemTemplate in ListBox:

<ListBox ItemsSource="{Binding Path=Images}" Width="400" Height="25" Margin="0,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel IsItemsHost="True"/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Image Height="16" HorizontalAlignment="Left" Margin="0,0,0,0" Stretch="Fill" VerticalAlignment="Top" Width="16" Source="{Binding}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

And how to fill collection Images? It's very easy. Add BitmapImage instances in loop like:

BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(@"/Images/image_file.png", UriKind.RelativeOrAbsolute);
bi.EndInit();
1
votes

Well actually in your case (if your control stays that simple), you don't need a CustomControl, btw your example is IMHO called UserControl, anyways.

You can simply declare a DataTemplate. E.g.

<ListBox ItemsSource="{Binding YourCollectionInDataContext}"...>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Image Source="{Binding SomePropertyOfYourItemVm1}"/>
                <TextBlock Text="{Binding SomePropertyOfYourItemVm2}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

For more information please refer here.

UserControls (composition of controls) and CustomControls (extend an existing control) should only be used, if there is no other possibility to implement the desired feature. This is a good articel about both types of controls.