2014-12-08 9 views
9

Wdrażam listę, która może z łatwością zawierać 10 000 małych zdjęć. Rzeczywisty przypadek użycia pokazuje listę miniatur wideo, dzięki czemu możesz przewijać wideo klatka po klatce. Wstawiam miniaturę wideo na listę co 2/3 sekundy filmu. Potrzebuję obsługiwać bardzo długie filmy wideo (np. 1 godz. Wideo).Wirtualizacja danych swobodnego dostępu dla ListView w systemie Windows Runtime

Więc wirtualizacji opcje:

http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh780657.aspx

Próbowałem „Przyrostową wirtualizacji danych” i że zużywa zbyt dużo pamięci dla mnie, ponieważ obrazy mogą być określone tylko przez strumienie, a ja w końcu otwarcie 10000 strumienie. To spowodowałoby awarię aplikacji Windows Phone z powodu braku pamięci.

Teraz chciałbym spróbować "Wirtualizacja danych o dostępie swobodnym". Widzę, jak zaimplementować interfejsy IObservableVector<object>, INotifyCollectionChanged (tak <object> b/c <T> nie działa). Najtrudniejsze jest to, jak mogę pozbyć się obrazów i załadować obrazy. Ładowanie obrazów to metoda asynchroniczna.

Dodatkowo uważam, że to rozwiązanie powinno zawierać symbole zastępcze, tak jak mówi dokument MSFT. "Przykład tego typu wirtualizacji danych jest często spotykany w aplikacjach do przeglądania zdjęć. Zamiast czekać na pobranie wszystkich zdjęć z albumu, Aplikacja pokazuje obrazy zastępcze. Po pobraniu każdego obrazu aplikacja zastępuje element zastępczy dla tego obrazu renderowaniem rzeczywistego zdjęcia. Mimo że wszystkie obrazy nie zostały pobrane i wyświetlone, użytkownik może nadal przesuwać i wchodzić w interakcje z kolekcja."

Przeglądanie próbki MSFT dla elementów zastępczych - użycie "ContainerContentChanging" wydaje się być ważną ścieżką. Zgaduję, że istnieje sposób na pozbycie się obrazu w tym wydarzeniu i także załadowanie obrazu. https://code.msdn.microsoft.com/windowsapps/ListViewSimple-d5fc27dd

wrzenia to w dół na pytanie - Gdzie jest to możliwe, aby wyrzucać strumienia obrazu i rozpocząć obciążenie obrazu na liście wirtualizacji dostępie swobodnym? Jest to bardzo często spotykany scenariusz w aplikacjach fotograficznych i jest bardzo łatwy do zrobienia w iOS, ale wydaje się, że nikt jeszcze nie zrobił tego w środowisku wykonawczym Windows.

Odpowiedz

0

Musisz dostosować implementację VirtualizingCollection, sprawdź następujący artykuł: http://www.codeproject.com/Articles/34405/WPF-Data-Virtualization.

Napisałem przykładową aplikację za pomocą adaptacji VirtualizingCollection dla aplikacji Windows Phone 8.1 Runtime.

public class ThumbnailItem 
{ 
    public Uri ImageUri { get; set; } 
} 

Później wpisz dostawcę ThumbnailItem.

public class ThumbnailProvider : IItemsProvider<ThumbnailItem> 
{ 
    private readonly int _itemsCount; 

    public ThumbnailProvider(int itemsCount) 
    { 
     _itemsCount = itemsCount; 
    } 

    public int FetchCount() 
    { 
     return _itemsCount; 
    } 

    public IList<ThumbnailItem> FetchRange(int startIndex, int count) 
    { 
     var items = new List<ThumbnailItem>(); 
     while (count-- > 0) 
     { 
      items.Add(new ThumbnailItem() 
      { 
       ImageUri = new Uri("ms-appx:///Assets/Square71x71Logo.scale-240.png") 
      }); 
     } 
     return items; 
    } 
} 

Następnie wewnątrz ViewModel, musisz utworzyć właściwość IList i ustawić wartość za implementację VirtualizingCollection. Sugeruję użycie AsyncVirtualizingCollection.

Items = new AsyncVirtualizingCollection<ThumbnailItem>(new ThumbnailProvider(1000000), 100); 

Wreszcie, na widoku należy ustawić obiekt DataContext używając instancję Twojej ViewModel i Twój ListView powinien wyglądać podobnie do:

<ListView 
    ItemsSource="{Binding Items,Mode=OneWay}" 
    VirtualizingStackPanel.VirtualizationMode="Recycling"> 
<ListView.ItemsPanel> 
    <ItemsPanelTemplate> 
     <WrapGrid Orientation="Horizontal"/> 
    </ItemsPanelTemplate> 
</ListView.ItemsPanel> 

<ListView.ItemTemplate> 
    <DataTemplate> 
     <Grid Margin="0 0 20 20"> 
      <Image Source="{Binding ImageUri,Mode=OneTime}" 
        Width="72" Height="72"/> 
     </Grid> 
    </DataTemplate> 
</ListView.ItemTemplate> 

oczywiście logika Dostawca musi zostać zmieniony zgodnie z wymaganiami, kod, który napisałem, jest tylko próbką.

Proszę oznaczyć jako odpowiedź, jeśli ci pomożemy.

poważaniem, Denys

EDIT Friend @Quincy, napisałem prosty przykład, można go dostosować. Może dla twojej aplikacji klasa ThumbnailItem będzie zawierać właściwość Filename wskazującą nazwę pliku IsolateStorageFile. W takim przypadku musisz utworzyć powiązanie z konwerterem, więc musisz zaimplementować obiekt IValueConverter, aby utworzyć instancję BitmapImage przy użyciu pliku IsolateStorageFile.

Obraz Bitmap image = new BitmapImage(); image.SetSource (sourceFile); obraz powrotu;

O zamknięciu obrazu VirtualizingCollection zdefiniował domyślnie rozmiar strony 100. Twój IsolateStorageFiles zostanie użyty jednorazowo do utworzenia BitmapImage w twoim obiekcie IValueConverter. Później VirtualizingCollection usunie stare strony, jeśli nie są one używane (nie są wyświetlane, sprawdź implementację VirtualizingCollection), a ostatecznie GC zamknie się & pozbywając się BitmapImage.

Portowanie VirtualizingCollection jest łatwe, pamiętam, że właśnie wprowadziłem zmiany w klasie AsyncVirtualizingCollection. Moje rozwiązanie było proste:

Zamień ThreadPool.QueueUserWorkItem dla ThreadPool.RunAsync.

Zastąp ciąg śledzenia debugowania (tylko debugowanie komunikatów, nie bardzo ważne).

Wymień SynchronizationContext metody wywołania za pomocą:

(dla aplikacji Windows Phone) CoreApplication.MainView.CoreWindow.Dispatcher.

(dla aplikacji Windows) CoreApplication.MainView.Dispatcher.

Mam nadzieję, że ci to pomoże.

+0

W tym przypadku nie ładujesz obrazu samodzielnie, co muszę zrobić. Twoje właśnie użycie identyfikatora URI. Muszę otworzyć strumień i zamknąć go ostatecznie – Quincy

+0

Czy cały ten kod nie jest zależny od WPF? AsyncVirtualizingCollection nie jest dostępny w winrt – Quincy

+0

@Quincy Edytowałem swoją odpowiedź. Sprawdź to jeszcze raz. – dbvega

Powiązane problemy