2015-11-03 2 views
1

Ok Я попытаюсь объяснить мой шаг проблемы за шагом вместе с кодомUWP GridView Databinding не работает с методами асинхронных (наблюдаемая коллекция)

  1. Я попробовал шаблон данных с й: привязку и наблюдаемыми выдержанные для первого время
  2. , когда я пытаюсь получить эскизы набора файлов хранилища и отображать их вместе с их отображаемыми именами, он не работает.
  3. , когда я просто добавляю новые элементы в свою наблюдаемую коллекцию с именами этих файлов, не получая миниатюры и не ставя простую картинку вместо этого эскиза из активов, тогда она работает так, как должна, но я получаю активацию pic вместо мой эскиз. пожалуйста, помогите, ниже мой код плохо комментировать его, чтобы объяснить лучше. спасибо заранее ..

    //this is the xaml code of the gridview. 
    <GridView ItemsSource="{x:Bind VideoGridItems}"> 
        <GridView.ItemTemplate> 
         <DataTemplate x:DataType="data:VideoGridItem"> 
          <StackPanel> 
           <Image Source="{x:Bind i}" Width="190" Height="130"/> 
           <TextBlock Text="{x:Bind Name}" FontSize="24"/> 
          </StackPanel> 
         </DataTemplate> 
        </GridView.ItemTemplate> 
    </GridView> 
    

    // и это весь мой класс кода позади xaml.cs файла

    public sealed partial class HistoryV : Page 
    { 
    public HistoryV() 
    { 
        this.InitializeComponent(); 
        VideoGridItems = new ObservableCollection<VideoGridItem>(); 
        LoadHistory(); 
    } 
    
    
    
    public ObservableCollection<VideoGridItem> VideoGridItems { get; set; } 
    private async void LoadHistory() 
    { 
        var files = new List<StorageFile>(); 
        var TextFile = await Current.LocalFolder.CreateFileAsync("VideoHistory.txt", CreationCollisionOption.OpenIfExists); 
        var Lines = await FileIO.ReadLinesAsync(TextFile); 
        int i = Lines.Count - 1; 
        for (; i>-1; i--) 
        { 
         files.Add(await StorageApplicationPermissions.FutureAccessList.GetFileAsync(Lines[i])); 
        } 
        //I simply take each file and add new items with its name and 
        asset picture as image on gridview, this method works, but not what I want 
        foreach (var item in files) 
        { 
         VideoGridItems.Add(new VideoGridItem { Name = item.DisplayName, i = new BitmapImage(new Uri("ms-appx:///Assets//StoreLogo.png")) }); 
        } 
        //below the is code line i have commented because it is not working 
        this is the actual method which should work. 
        //VideoGridItems = await GetVideoItems(files); 
    } 
    

    }

Наконец ниже два класса ive, созданный с помощью метода GetVideoItems, чтобы получить ObservableCollection, который может быть привязан к gridview

public class VideoGridItem 
{ 
    public BitmapImage i { get; set; } 
    public string Name { get; set; } 
} 
class VideoGridItemManager 
{ 
    public static async Task<ObservableCollection<VideoGridItem>> GetVideoItems(List<StorageFile> files) 
    { 
     var newlist = new ObservableCollection<VideoGridItem>(); 
     foreach (var file in files) 
     { 
      var b = new BitmapImage(); 
      var thumb =await GetThumbnail(file); 
      if (thumb == null) { b = new BitmapImage(new Uri("ms-appx:///Assets//Square150x150Logo.scale-200.png")); } 
      else 
      { 
       if (thumb.ContentType == "image/bmp") 
       { 
        b = new BitmapImage(new Uri("ms-appx:///Assets//Square150x150Logo.scale-200.png")); 
       } 
       else 
       { 
        await b.SetSourceAsync(thumb); 
       } 
      } 
      newlist.Add(new VideoGridItem { Name = file.DisplayName, i=b }); 
     } 
     return newlist; 
    } 
    private static async Task<StorageItemThumbnail> GetThumbnail(StorageFile file) 
    { 
     var thumb = await file.GetThumbnailAsync(ThumbnailMode.VideosView, 190, ThumbnailOptions.UseCurrentScale); 
     return thumb; 
    } 
} 
+1

x: привязка по умолчанию к OneTime. Вы пробовали установить режим OneWay?Например: {x: Bind Mode = OneWay} – gregkalapos

+0

Я не думаю, что проблема, даже если это один раз, она все равно должна отображать результат в первый раз, какая-то проблема, похоже, из-за асинхронных задач и задач, методы, я думаю, как работает async, он выполняется в другом потоке и до тех пор, пока не получит результаты, данные уже связаны. Я не знаю много о async и жду:/ –

+0

Вы пробовали его с OneWay или нет? – gregkalapos

ответ

2

Ваш шаблон данных с x:bind является правильным, и он может работать с асинхронными методами. Проблема здесь связана с ObservableCollection. В вашем коде вы использовали VideoGridItems = await GetVideoItems(files);, чтобы обновить свой GridView, но замена ObservableCollection, как это, не приведет к уведомлению, GridView все еще привязан к старому. Самый простой способ решить эту проблему использует Add метод сообщать об изменении, как следующее:

VideoGridItems.Clear(); 
foreach (var item in await VideoGridItemManager.GetVideoItems(files)) 
{ 
    VideoGridItems.Add(item); 
} 

Я использовал KnownFolders.PicturesLibrary как простой тест на моей стороне:

private async void LoadHistory() 
{ 
    var files = await KnownFolders.PicturesLibrary.GetFilesAsync(); 

    VideoGridItems.Clear(); 
    foreach (var item in await VideoGridItemManager.GetVideoItems(files)) 
    { 
     VideoGridItems.Add(item); 
    } 
} 

Он хорошо работает.

[Update]

При использовании привязки, если вы хотите, обновление пользовательского интерфейса после изменили источник данных, необходимо поднять PropertyChanged событие. Если вы назначили целую новую наблюдаемую коллекцию существующей, это не вызовет никакого события PropertyChanged, поэтому ваш GridView не будет обновляться. Но если вы используете метод «Добавить», он поднимет событие PropertyChanged. Вы можете найти это в ObservableCollection's soure code.

protected override void InsertItem(int index, T item) 
    { 
     CheckReentrancy(); 
     base.InsertItem(index, item); 

     OnPropertyChanged(CountString); 
     OnPropertyChanged(IndexerName); 
     OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index); 
    } 

Если вы хотите, обновление пользовательского интерфейса после назначения целой новой наблюдаемой коллекции VideoGridItems, вы можете запустить событие PropertyChanged уведомить мнение о том, что коллекция была заменена.

public sealed partial class MainPage : Page, INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private ObservableCollection<VideoGridItem> _videoGridItems; 

    public ObservableCollection<VideoGridItem> VideoGridItems 
    { 
     get 
     { 
      return _videoGridItems; 
     } 

     set 
     { 
      _videoGridItems = value; 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs("VideoGridItems")); 
      } 
     } 
    } 

    public MainPage() 
    { 
     this.InitializeComponent(); 
     VideoGridItems = new ObservableCollection<VideoGridItem>(); 
     LoadHistory(); 
    } 
    ... 
} 

И в вашем XAML, вам нужно использовать ItemsSource="{x:Bind VideoGridItems, Mode=OneWay}" как сказал @gregkalapos.

+0

Я не понял причину, если я использую метод добавления и добавляю элементы один за другим, он будет работать? и если я присваиваю ему всю наблюдаемую коллекцию, он не будет работать, почему это так? вы можете прояснить, чтобы мои понятия были ясными :) –

+0

@Muhammad Touseef Я обновил свой ответ, чтобы уточнить его. Надеюсь, поможет. –

+0

Это потрясающе, спасибо! –

Смежные вопросы