简体   繁体   中英

Update WPF Images from a list

I have 40 images in a single window that I need to change. I thought that easiest way to check if any of these 40 images need to be changed on a timer is to put them into a List<ImgInfo> , where ImgInfo contains a System.Windows.Controls.Image .

The code I have updates the List, but does not change the current image on the Window.

I am very new to manipulating images in WPF. Should I be binding these images to a property in the code? Right now the xaml just sets the source to a single image. What is required to bind these images to an item in the list?

// xaml:
 <Image x:Name="comp01" Height="75" Source="img/comp-offline.png" Stretch="Fill" Margin="5"/>

// When the application starts:
ImgInfoList= new List<ImgInfo>();
ImgInfoList.Add(new ImgInfo{ CurrentImage = comp01, MachineName = "" });
ImgInfoList.Add(new ImgInfo{ CurrentImage = comp02, MachineName = "" });
// ... etc for 40 images

// ImgInfo class:
public class ImgInfo
{
    public string MachineName { get; set; }
    public Image CurrentImage { get; set; }
}

public void MainTimer_Tick(object sender, EventArgs e)
{
    foreach(var imgInfo in ImageInfoList)
    {
        if(//conditions are true) 
        {
            Image imgTmp = new Image();
            BitmapImage bi3 = new BitmapImage();
            bi3.BeginInit();
            bi3.UriSource = new Uri(LoadBitmapURIFromResource("img/img-1.png"));
            bi3.EndInit();
            imgTmp.Stretch = Stretch.Fill;
            imgTmp.Source = bi3;
            imgInfo.CurrentImage = imgTmp;
        }
        // else if... img/img-2.png, etc.
    }
}

//LoadBitmapURIFromResource just returns Convert.ToString(new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component/" + pathInApplication, UriKind.Absolute));

To handle multiple images in WPF, you should use an ObservableCollection for the Images (containing only the file names) and use this as the ItemsSource for a ListBox. The ItemTemplate would be your image, that binds to the filename.

    <ListBox ItemsSource="{Binding ImgList}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding}" ... />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

ImgList has to be a property in your DataContext. If you need a different layout for the ListBox, you can change the ItemsPanel of the ListBox.

To change an image, simply replace the string. Just be aware that the image component by default caches the images. If you want to reload the image from the same file, you have to disable caching.

Edit:

As promised, I want to show how to use bindings to display the images at a specific position on a <Canvas/> . At first, we need to modify your ImgInfo class. It now contains the path, the position and the size of the image to display:

public class ImgInfo
{
    public string Path { get; set; }
    public double X { get; set; }
    public double Y { get; set; }
    public double Width { get; set; }
    public double Height { get; set; }
}

The <ListBox/> will be extended in the following way:

    <ListBox ItemsSource="{Binding ImgList}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding Path}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
                <Setter Property="Canvas.Left" Value="{Binding X}"/>
                <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                <Setter Property="Width" Value="{Binding Width}"/>
                <Setter Property="Height" Value="{Binding Height}"/>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>

As ItemsPanel , we use a <Canvas/> -Element. To make sure that the Items are displayed on a specific location, we modify the ItemContainerStyle to bind the corresponding properties to our ImgInfo instance.

Now you can add new items or replace them in the ImgList and the changes will be reflected in the <ListBox/> . If you want to modify ImgInfo -Items directly, you will have to implement INotifyPropertyChanged in this class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM