0

I will explain my problem in simplest way. I have been dealing with both listview and gridview and binding for a long time, but now I am having a unexplanable problem, so i really need some help.

Below is the xaml code of my listview.

 <ListView Name="OtherVideosList"  ItemsSource="{x:Bind VideoFiles}" SelectionChanged="OtherVideosList_SelectionChanged">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="data:VideoFile">
            <StackPanel Orientation="Horizontal">
                <Image Source="{x:Bind Thumbnail}"/>
                <StackPanel>
                    <TextBlock Text="{x:Bind FileName}"/>
                    <TextBlock Text="{x:Bind Duration}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

I am binding it to a ObservableCollection below is the datatype class for it.

public class VideoFile
{
    public string FileName { get; set; }
    public string Duration { get; set; }
    public StorageFile File { get; set; }
    public BitmapImage Thumbnail { get; set; }
}

using this class I am creating the item source

public ObservableCollection<VideoFile> VideoFiles { get; set; }

I use a button to open multiple files and then put them to item source, to play them later on the media element. below is the code for the event handler.

private async void OpenClick(object sender, RoutedEventArgs e)
    {
        try
        {
            var p = new FileOpenPicker();
            foreach (var item in videoTypes)
            {
                p.FileTypeFilter.Add(item);
            }
            //Curentplayingfiles is IReadOnlyList<StorageFiles>
            CurrentlyPlayingFiles = await p.PickMultipleFilesAsync();
            if (CurrentlyPlayingFiles.Count != 0)
            {
                if (CurrentlyPlayingFiles.Count == 1)
                {   //this if block works absolutely fine
                    CurrentlyPlayingFile = CurrentlyPlayingFiles[0];
                    var s = await CurrentlyPlayingFile.OpenReadAsync();
                    ME.SetSource(s, CurrentlyPlayingFile.ContentType);
                }
                else
                {
                    VideoFiles = new ObservableCollection<VideoFile>();
                    foreach (var file in CurrentlyPlayingFiles)
                    {
                        //Thumbnail and GetDuration are my own static methods to get thumbnail
                        //and duration property of the file respectively
                        VideoFiles.Add(new VideoFile { Thumbnail = await Thumbnail(file), Duration = await GetDuration(file), File = file, FileName = file.DisplayName });
                    }
                    //exception occurs on this very line below, because here OtherVideosList has zero items.
                    OtherVideosList.SelectedIndex = 0;
                }

            }

        }
        catch (Exception s){ var dr = s.Message; }
    }

I have mentioned the key points in the comments for you guyx. any help would be highly appreciated, thanks a lot..

Muhammad Touseef
  • 4,357
  • 4
  • 31
  • 75

3 Answers3

1

It looks like in your code you are bound to an observable collection videofiles. Do not set it to new before adding the items. If the collection is already bound this will break your binding. Clear all the items from the list instead

Ken Tucker
  • 4,126
  • 1
  • 18
  • 24
1

So, your page doesn't implement InotifyPropertyChanged, you can fix it in 2 ways:

  1. You can initialize your VideoFiles collection in costructor and all will be work.

  2. The other way, to implement INotifyPropertyChanged interface. By the way, the default x:Bind mode is OneTime so in this step you need to change Mode to OneWay.

C#

    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        private ObservableCollection<VideoFile> _videoFiles { get; set; }

        public MainPage()
        {
            this.InitializeComponent();
        }

        public ObservableCollection<VideoFile> VideoFiles
        {
            get
            {
                return _videoFiles;
            }
            set
            {
                if (_videoFiles != value)
                {
                    _videoFiles = value;
                    RaisePropertyChanged(nameof(VideoFiles));
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OpenClick(object sender, RoutedEventArgs e)
        {
            VideoFiles = new ObservableCollection<VideoFile>();
            VideoFiles.Add(new VideoFile()
            {
                Duration = "02:00",
                FileName = "file name",
                Thumbnail = new BitmapImage(new Uri("http://s.ill.in.ua/i/news/630x373/298/298656.jpg"))
            });

        }

        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

XAML:

<ListView Name="OtherVideosList"  
          ItemsSource="{x:Bind VideoFiles, Mode=OneWay}">
Andrii Krupka
  • 4,276
  • 3
  • 20
  • 41
  • thanks a lot, this also helped me understand the problem, I have another question regarding this, How can I access non static binding property public 'ObservableCollection VideoFiles { get; set; }' outside of my Page class? – Muhammad Touseef Mar 21 '16 at 13:26
1

You are only listening for CollectionChanged events and not a change of the VideoFiles property itself. Try this instead:

// Assuming you're using C# 6. If not, assign it in constructor
public ObservableCollection<VideoFile> VideoFiles { get; set; } = new ObservableCollection<VideoFile>();

Then in the else clause:

else
{
    VideoFiles.Clear();
    foreach (var file in CurrentlyPlayingFiles)
    {
        //Thumbnail and GetDuration are my own static methods to get thumbnail
        //and duration property of the file respectively
        VideoFiles.Add(new VideoFile { Thumbnail = await Thumbnail(file), Duration = await GetDuration(file), File = file, FileName = file.DisplayName });
    }
    //exception occurs on this very line below, because here OtherVideosList has zero items.
    OtherVideosList.SelectedIndex = 0;
}

When you assign a new collection to VideoFiles it breaks the binding and you will not receive any further notifications that the contents have changed.

Jon G Stødle
  • 3,844
  • 1
  • 16
  • 22
  • I have another question regarding this, How can I access non static binding property public 'ObservableCollection VideoFiles { get; set; }' outside of my Page class? – Muhammad Touseef Mar 21 '16 at 13:25
  • You need to keep a reference to the page in some way. But I'm guessing you want to add items to the collection from another page (or some other operation). The best way to that is to have some kind of class which handles data sources and which is avaiable throughout the application. It could for example be a Singleton – Jon G Stødle Mar 21 '16 at 14:13
  • I am not getting wht exactly are you proposing, can you clarify it with some code please? thanks. P.S : I tried making a static public property and assigned that private collection to it. And then I made changes to it, but changes only occur in that static property, and my ListView items are not being updated. P.S: that public static property is availble throughout the application – Muhammad Touseef Mar 21 '16 at 15:17
  • Not sure if x:Bind works with static properties, but that might be your problem. You can take a look at this as an example: http://codepaste.net/ddtff5 It should work for your case – Jon G Stødle Mar 22 '16 at 12:42