Search code examples
c#xamlwin-universal-appraspberry-pi2windows-10-iot-core

Windows 10 IoT Xaml dynamically add images to flipview


I have a folder included in my project which contains images. These images should be loaded into a flipview-Control, which displays them and shows the next one after 3 seconds. The switching already works, but I have problems to display the images.

public MainPage()
{
    this.InitializeComponent();
    String path = Directory.GetCurrentDirectory() + @"\Imports";
    foreach (String imgurl in Directory.GetFiles(path))
    {
        String filename = Path.GetFileName(imgurl);
        Uri uri = new Uri("ms-appx:///" + filename);
        var image = new Image
        {
            Source = new BitmapImage(uri)
        };
        // fv is my flipview
        fv.Items.Add(image);
    }

    timer = new DispatcherTimer()
    {
        Interval = TimeSpan.FromSeconds(3)
    };
    timer.Tick += ChangeImage;
    timer.Start();
}

private void ChangeImage(object sender, object o)
{
    var totalItems = fv.Items.Count;
    var newItemIndex = (fv.SelectedIndex + 1) % totalItems;
    fv.SelectedIndex = newItemIndex;
}

My XAML-Code looks like this:

<FlipView x:Name="fv" HorizontalAlignment="Left" VerticalAlignment="Top" Width="1280" Height="720" SelectionChanged="flipView_SelectionChanged"></flipview>

As I said, the Sliding works, but the Images are not shown. What am I missing? Also,

fv.Items.Count();

always shows me, that it contains twice the amount of images I have in the "imports" folder. Why?

edit:

private readonly DispatcherTimer timer;

    public MainPage()
    {
        this.InitializeComponent();

        String path = Directory.GetCurrentDirectory() + @"\Imports";
        fv.ItemsSource = Directory.GetFiles(path);

        timer = new DispatcherTimer()
        {
            Interval = TimeSpan.FromSeconds(3)
        };
        timer.Tick += ChangeImage;
        timer.Start();
    }

    private void ChangeImage(object sender, object o)
    {
        var totalItems = fv.Items.Count;
        var newItemIndex = (fv.SelectedIndex + 1) % totalItems;
        fv.SelectedIndex = newItemIndex;

    }

Solution

  • You'll have to add an ItemTemplate for it show the images:

    <FlipView x:Name="fv" HorizontalAlignment="Left" VerticalAlignment="Top" Width="1280" Height="720" SelectionChanged="flipView_SelectionChanged">
        <FlipView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Image Source="{Binding PathToImage}" Stretch="UniformToFill" />
                </Grid>
            </DataTemplate>
        </FlipView.ItemTemplate>
    </FlipView>
    

    The Source only needs a path to the image to work. That means you can do this in the code-behind:

    String path = Directory.GetCurrentDirectory() + @"\Imports";
    fv.ItemsSource = Directory.GetFiles(path);
    

    For the unexpected return value of fv.Items.Count();: Do you have a dump of the items in the collection? Something along the lines of

    foreach(var item in fv.Items.Count()) System.Diagnostics.Debug.WriteLine(item);
    

    Alternatively you can add all the images to a new List<> and set that list as the ItemsSource

    String path = Directory.GetCurrentDirectory() + @"\Imports";
    var newSource = new List<Image>();
    foreach (String imgurl in Directory.GetFiles(path))
    {
        String filename = Path.GetFileName(imgurl);
        Uri uri = new Uri("ms-appx:///" + filename);
        var image = new Image
        {
            Source = new BitmapImage(uri)
        };
        // fv is my flipview
        newSource.Add(image);
    }
    fv.ItemsSource = newSource;
    

    When you set the ItemsSource of the ListView, the ListView will generate one item per object. Each of these items will have the object set as it's DataContext. When you use Binding expressions you tell the XAML to load the of the given Property from the current DataContext. {Binding PathToIMage} will get the value of PathToImage from the object that is set as DataContext. (As a side note: Specifying no path and just writing {Binding} gets the whole object. So if a string is set as the DataContext, {Binding} will return the value of the string.)

    You can read about DataBinding here.

    I think the following line should work by just pasting it into your code:
    Change this...

    String path = Directory.GetCurrentDirectory() + @"\Imports";
    foreach (String imgurl in Directory.GetFiles(path))
    {
        String filename = Path.GetFileName(imgurl);
        Uri uri = new Uri("ms-appx:///" + filename);
        var image = new Image
        {
            Source = new BitmapImage(uri)
        };
        // fv is my flipview
        fv.Items.Add(image);
    }
    

    ...to this..

    String path = Directory.GetCurrentDirectory() + @"\Imports";
    fv.ItemsSource = Directory.GetFiles(path).Select(p => "ms-appx:///" + p);
    

    ...and this...

    <Image Source="{Binding PathToImage}" Stretch="UniformToFill" />
    

    ...to this

    <Image Source="{Binding}" Stretch="UniformToFill" />