Studi kasus Windows Phone Silverlight ke UWP: Bookstore2

Studi kasus ini—yang dibangun berdasarkan info yang diberikan di Bookstore1—dimulai dengan aplikasi Windows Phone Silverlight yang menampilkan data yang dikelompokkan dalam LongListSelector. Dalam model tampilan, setiap instans penulis kelas mewakili grup buku yang ditulis oleh penulis tersebut, dan di LongListSelector, kita dapat melihat daftar buku yang dikelompokkan menurut penulis atau kita dapat memperkecil untuk melihat daftar lompat penulis. Daftar lompat mampu navigasi yang jauh lebih cepat daripada menggulir daftar buku. Kami menelusuri langkah-langkah porting aplikasi ke aplikasi Windows 10 Platform Windows Universal (UWP).

Catatan Saat membuka Bookstore2Universal_10 di Visual Studio, jika Anda melihat pesan "Pembaruan Visual Studio diperlukan", ikuti langkah-langkah untuk mengatur Versi Platform Target di TargetPlatformVersion.

Unduhan

Unduh aplikasi Bookstore2WPSL8 Windows Phone Silverlight.

Unduh aplikasi Bookstore2Universal_10 Windows 10.

Aplikasi Windows Phone Silverlight

Ilustrasi di bawah ini menunjukkan seperti apa Bookstore2WPSL8—aplikasi yang akan kita port—. Ini adalah LongListSelector yang digulirkan secara vertikal dari buku yang dikelompokkan menurut penulis. Anda dapat memperkecil ke daftar lompat, dan dari sana, Anda dapat menavigasi kembali ke grup mana pun. Ada dua bagian utama untuk aplikasi ini: model tampilan yang menyediakan sumber data yang dikelompokkan, dan antarmuka pengguna yang mengikat model tampilan tersebut. Seperti yang akan kita lihat, kedua port ini dengan mudah dari teknologi Windows Phone Silverlight ke Platform Windows Universal (UWP).

bagaimana bookstore2wpsl8 terlihat

Porting ke proyek Windows 10

Ini adalah tugas cepat untuk membuat proyek baru di Visual Studio, menyalin file ke dalamnya dari Bookstore2WPSL8, dan menyertakan file yang disalin dalam proyek baru. Mulailah dengan membuat proyek Aplikasi Kosong (Windows Universal) baru. Beri nama Bookstore2Universal_10. Ini adalah file untuk disalin dari Bookstore2WPSL8 ke Bookstore2Universal_10.

  • Salin folder yang berisi file PNG gambar sampul buku (foldernya adalah \Assets\CoverImages). Setelah menyalin folder, di Penjelajah Solusi, pastikan Tampilkan Semua File diaktifkan. Klik kanan folder yang Anda salin dan klik Sertakan Dalam Proyek. Perintah itu adalah apa yang kita maksud dengan "menyertakan" file atau folder dalam proyek. Setiap kali Anda menyalin file atau folder, klik Refresh di Penjelajah Solusi lalu sertakan file atau folder dalam proyek. Tidak perlu melakukan ini untuk file yang Anda ganti di tujuan.
  • Salin folder yang berisi file sumber model tampilan (foldernya adalah \ViewModel).
  • Salin MainPage.xaml dan ganti file di tujuan.

Kita dapat menyimpan App.xaml, dan App.xaml.cs yang dihasilkan Visual Studio untuk kita dalam proyek Windows 10.

Edit kode sumber dan file markup yang baru saja Anda salin dan ubah referensi apa pun ke namespace Bookstore2WPSL8 menjadi Bookstore2Universal_10. Cara cepat untuk melakukannya adalah dengan menggunakan fitur Replace In Files . Dalam kode imperatif dalam file sumber model tampilan, perubahan porting ini diperlukan.

  • Ubah System.ComponentModel.DesignerProperties ke DesignMode lalu gunakan perintah Atasi di atasnya. IsInDesignTool Hapus properti dan gunakan IntelliSense untuk menambahkan nama properti yang benar: DesignModeEnabled.
  • Gunakan perintah Atasi pada ImageSource.
  • Gunakan perintah Atasi pada BitmapImage.
  • Hapus using System.Windows.Media; dan using System.Windows.Media.Imaging;.
  • Ubah nilai yang dikembalikan oleh properti Bookstore2Universal_10.BookstoreViewModel.AppName dari "BOOKSTORE2WPSL8" menjadi "BOOKSTORE2UNIVERSAL".
  • Sama seperti yang kami lakukan untuk Bookstore1, perbarui implementasi properti BookSku.CoverImage (lihat Mengikat Gambar ke model tampilan).

Di MainPage.xaml, perubahan port awal ini diperlukan.

  • Ubah phone:PhoneApplicationPage ke Page (termasuk kemunculan dalam sintaks elemen properti).
  • phone Hapus deklarasi awalan namespace dan shell .
  • Ubah "clr-namespace" menjadi "using" dalam deklarasi awalan namespace yang tersisa.
  • Hapus SupportedOrientations="Portrait", dan Orientation="Portrait", dan konfigurasikan Potret dalam manifes paket aplikasi di proyek baru.
  • Hapus shell:SystemTray.IsVisible="True".
  • Jenis konverter item jump list (yang ada dalam markup sebagai sumber daya) telah dipindahkan ke namespace Windows.UI.Xaml.Controls.Primitives . Jadi, tambahkan deklarasi awalan namespace Windows_UI_Xaml_Controls_Primitives dan petakan ke Windows.UI.Xaml.Controls.Primitives. Pada sumber daya konverter item jump list, ubah awalan dari phone: ke Windows_UI_Xaml_Controls_Primitives:.
  • Sama seperti yang kami lakukan untuk Bookstore1, ganti semua referensi ke PhoneTextExtraLargeStyle gaya TextBlock dengan referensi ke SubtitleTextBlockStyle, ganti PhoneTextSubtleStyle dengan SubtitleTextBlockStyle, ganti PhoneTextNormalStyle dengan CaptionTextBlockStyle, dan ganti PhoneTextTitle1Style dengan HeaderTextBlockStyle.
  • Ada satu pengecualian dalam BookTemplate. Gaya TextBlock kedua harus mereferensikan CaptionTextBlockStyle.
  • Hapus atribut FontFamily dari TextBlock di dalam AuthorGroupHeaderTemplate dan atur Latar Belakang Batas ke referensi SystemControlBackgroundAccentBrush , bukan PhoneAccentBrush.
  • Karena perubahan yang terkait dengan tampilan piksel, tembus markup dan kalikan dimensi ukuran tetap (margin, lebar, tinggi, dll) sebesar 0,8.

Mengganti LongListSelector

Mengganti LongListSelector dengan kontrol SemanticZoom akan mengambil beberapa langkah, jadi mari kita mulai. LongListSelector mengikat langsung ke sumber data yang dikelompokkan, tetapi SemanticZoom berisi kontrol ListView atau GridView, yang mengikat secara tidak langsung ke data melalui adaptor CollectionViewSource. CollectionViewSource perlu ada dalam markup sebagai sumber daya, jadi mari kita mulai dengan menambahkannya ke markup di MainPage.xaml di dalam <Page.Resources>.

    <CollectionViewSource
        x:Name="AuthorHasACollectionOfBookSku"
        Source="{Binding Authors}"
        IsSourceGrouped="true"/>

Perhatikan bahwa pengikatan pada LongListSelector.ItemsSource menjadi nilai CollectionViewSource.Source, dan LongListSelector.IsGroupingEnabled menjadi CollectionViewSource.IsSourceGrouped. CollectionViewSource memiliki nama (catatan: bukan kunci, seperti yang mungkin Anda harapkan) sehingga kita dapat mengikatnya.

Selanjutnya, ganti phone:LongListSelector dengan markup ini, yang akan memberi kita preliminary SemanticZoom untuk bekerja dengan.

    <SemanticZoom>
        <SemanticZoom.ZoomedInView>
            <ListView
                ItemsSource="{Binding Source={StaticResource AuthorHasACollectionOfBookSku}}"
                ItemTemplate="{StaticResource BookTemplate}">
                <ListView.GroupStyle>
                    <GroupStyle
                        HeaderTemplate="{StaticResource AuthorGroupHeaderTemplate}"
                        HidesIfEmpty="True"/>
                </ListView.GroupStyle>
            </ListView>
        </SemanticZoom.ZoomedInView>
        <SemanticZoom.ZoomedOutView>
            <ListView
                ItemsSource="{Binding CollectionGroups, Source={StaticResource AuthorHasACollectionOfBookSku}}"
                ItemTemplate="{StaticResource ZoomedOutAuthorTemplate}"/>
        </SemanticZoom.ZoomedOutView>
    </SemanticZoom>

Gagasan LongListSelector tentang mode daftar datar dan daftar lompat dijawab dalam gagasan SemanticZoom dari tampilan yang diperbesar dan diperkecil. Tampilan yang diperbesar adalah properti, dan Anda mengatur properti tersebut ke instans ListView. Dalam hal ini, tampilan zoomed-out juga diatur ke ListView, dan kedua kontrol ListView terikat ke CollectionViewSource kami. Tampilan yang diperbesar menggunakan templat item, templat header grup, dan pengaturan HideEmptyGroups yang sama (sekarang bernama HidesIfEmpty) seperti yang dilakukan daftar datar LongListSelector. Dan tampilan zoomed-out menggunakan templat item sangat mirip dengan yang ada di dalam gaya jump list LongListSelector (AuthorNameJumpListStyle). Perhatikan juga bahwa tampilan yang diperkecil mengikat properti khusus CollectionViewSource bernama CollectionGroups, yang merupakan koleksi yang berisi grup daripada item.

Kita tidak lagi membutuhkan AuthorNameJumpListStyle, setidaknya tidak semua itu. Kita hanya memerlukan templat data untuk grup (yang merupakan penulis di aplikasi ini) dalam tampilan yang diperkecil. Jadi, kami menghapus AuthorNameJumpListStyle gaya dan menggantinya dengan templat data ini.

   <DataTemplate x:Key="ZoomedOutAuthorTemplate">
        <Border Margin="9.6,0.8" Background="{Binding Converter={StaticResource JumpListItemBackgroundConverter}}">
            <TextBlock Margin="9.6,0,9.6,4.8" Text="{Binding Group.Name}" Style="{StaticResource SubtitleTextBlockStyle}"
            Foreground="{Binding Converter={StaticResource JumpListItemForegroundConverter}}" VerticalAlignment="Bottom"/>
        </Border>
    </DataTemplate>

Perhatikan bahwa, karena konteks data templat data ini adalah grup daripada item, kami mengikat properti khusus bernama Grup.

Anda dapat membuat dan menjalankan aplikasi sekarang. Berikut tampilannya di emulator seluler.

aplikasi uwp di ponsel dengan perubahan kode sumber awal

Model tampilan dan tampilan yang diperbesar dan diperkecil bekerja sama dengan benar, meskipun satu masalahnya adalah kita perlu melakukan sedikit lebih banyak pekerjaan gaya dan templat. Misalnya, gaya dan kuas yang benar belum digunakan, sehingga teks tidak terlihat pada header grup yang dapat Anda klik untuk memperkecil tampilan. Jika Anda menjalankan aplikasi di perangkat desktop, maka Anda akan melihat masalah kedua, yaitu aplikasi belum menyesuaikan antarmuka penggunanya untuk memberikan pengalaman dan penggunaan ruang terbaik pada perangkat yang lebih besar di mana jendela dapat berpotensi jauh lebih besar daripada layar perangkat seluler. Jadi, di beberapa bagian berikutnya (Gaya dan templat awal, Antarmuka Pengguna Adaptif, dan Gaya akhir), kami akan memperbaiki masalah tersebut.

Gaya dan templat awal

Untuk memberi spasi header grup dengan baik, edit AuthorGroupHeaderTemplate dan atur Margin"0,0,0,9.6" di Batas.

Untuk meluaskan ruang item buku dengan baik, Edit BookTemplate dan atur Margin ke "9.6,0" pada kedua TextBlocks.

Untuk menjabarkan nama aplikasi dan judul halaman sedikit lebih baik, di dalam TitlePanel, hapus Margin atas pada TextBlock kedua dengan mengatur nilai ke "7.2,0,0,0". Dan dengan TitlePanel sendirinya, atur margin ke 0 (atau nilai apa pun yang terlihat bagus untuk Anda)

Ubah LayoutRootLatar Belakang menjadi "{ThemeResource ApplicationPageBackgroundThemeBrush}".

Antarmuka pengguna adaptif

Karena kami mulai dengan aplikasi telepon, tidak mengherankan bahwa tata letak UI aplikasi port kami benar-benar hanya masuk akal untuk perangkat kecil dan jendela sempit pada tahap ini dalam prosesnya. Tapi, kami sangat ingin tata letak UI beradaptasi dengan sendirinya dan memanfaatkan ruang dengan lebih baik ketika aplikasi berjalan di jendela lebar (yang hanya dimungkinkan pada perangkat dengan layar besar), dan untuk itu hanya menggunakan UI yang kita miliki saat ini ketika jendela aplikasi sempit (yang terjadi pada perangkat kecil, dan juga dapat terjadi pada perangkat besar).

Kita dapat menggunakan fitur Visual State Manager adaptif untuk mencapai hal ini. Kita akan mengatur properti pada elemen visual sehingga, secara default, UI ditata dalam status sempit menggunakan templat yang kita gunakan sekarang. Kemudian, kita akan mendeteksi kapan jendela aplikasi lebih lebar dari atau sama dengan ukuran tertentu (diukur dalam satuan piksel yang efektif), dan sebagai responsnya, kita akan mengubah properti elemen visual sehingga kita mendapatkan tata letak yang lebih besar, dan lebih luas. Kami akan menempatkan perubahan properti tersebut dalam status visual, dan kami akan menggunakan pemicu adaptif untuk terus memantau dan menentukan apakah akan menerapkan status visual tersebut, atau tidak, tergantung pada lebar jendela dalam piksel yang efektif. Kami memicu lebar jendela dalam hal ini, tetapi dimungkinkan untuk memicu pada tinggi jendela juga.

Lebar jendela minimum 548 epx sesuai untuk kasus penggunaan ini karena itulah ukuran perangkat terkecil yang ingin kita tampilkan tata letak lebarnya. Ponsel biasanya lebih kecil dari 548 epx, jadi pada perangkat kecil seperti itu, kita akan tetap dalam tata letak sempit default. Pada PC, jendela akan diluncurkan secara default cukup lebar untuk memicu sakelar ke keadaan lebar, yang akan menampilkan item berukuran 250x250. Dari sana, Anda akan dapat menyeret jendela cukup sempit untuk menampilkan minimal dua kolom dari 250x250 item. Setiap yang lebih sempit dari itu dan pemicu akan dinonaktifkan, status visual lebar akan dihapus, dan tata letak sempit default akan berlaku.

Sebelum mengatasi bagian Visual State Manager adaptif, pertama-tama kita perlu merancang status luas dan itu berarti menambahkan beberapa elemen visual dan templat baru ke markup kita. Langkah-langkah ini menjelaskan cara melakukannya. Dengan cara penamaan konvensi untuk elemen visual dan templat, kita akan menyertakan kata "lebar" dalam nama elemen atau templat apa pun yang untuk status luas. Jika elemen atau templat tidak berisi kata "lebar", maka Anda dapat berasumsi bahwa itu untuk status sempit, yang merupakan status default dan yang nilai propertinya diatur sebagai nilai lokal pada elemen visual di halaman. Hanya nilai properti untuk status lebar yang diatur melalui Status Visual aktual dalam markup.

  • Buat salinan kontrol SemanticZoom di markup dan atur x:Name="narrowSeZo" pada salinan. Pada aslinya, atur x:Name="wideSeZo" dan atur Visibility="Collapsed" juga sehingga lebar tidak terlihat secara default.
  • Di wideSeZo, ubah ListViews ke GridViewdalam tampilan yang diperbesar dan tampilan yang diperkecil.
  • Buat salinan ketiga sumber daya AuthorGroupHeaderTemplateini , , ZoomedOutAuthorTemplatedan tambahkan BookTemplate kata Wide ke kunci salinan. Selain itu, perbarui wideSeZo sehingga mereferensikan kunci sumber daya baru ini.
  • Ganti konten AuthorGroupHeaderTemplateWide dengan <TextBlock Style="{StaticResource SubheaderTextBlockStyle}" Text="{Binding Name}"/>.
  • Ganti isi ZoomedOutAuthorTemplateWide dengan:
    <Grid HorizontalAlignment="Left" Width="250" Height="250" >
        <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}"/>
        <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
          <TextBlock Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}"
              Style="{StaticResource SubtitleTextBlockStyle}"
            Height="80" Margin="15,0" Text="{Binding Group.Name}"/>
        </StackPanel>
    </Grid>
  • Ganti isi BookTemplateWide dengan:
    <Grid HorizontalAlignment="Left" Width="250" Height="250">
        <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}"/>
        <Image Source="{Binding CoverImage}" Stretch="UniformToFill"/>
        <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
            <TextBlock Style="{StaticResource SubtitleTextBlockStyle}"
                Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}"
                TextWrapping="NoWrap" TextTrimming="CharacterEllipsis"
                Margin="12,0,24,0" Text="{Binding Title}"/>
            <TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{Binding Author.Name}"
                Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" TextWrapping="NoWrap"
                TextTrimming="CharacterEllipsis" Margin="12,0,12,12"/>
        </StackPanel>
    </Grid>
  • Untuk status lebar, grup dalam tampilan diperbesar akan membutuhkan lebih banyak ruang pernapasan vertikal di sekitarnya. Membuat dan mereferensikan templat panel item akan memberi kita hasil yang kita inginkan. Berikut tampilan markupnya.
   <ItemsPanelTemplate x:Key="ZoomedInItemsPanelTemplate">
        <ItemsWrapGrid Orientation="Horizontal" GroupPadding="0,0,0,20"/>
    </ItemsPanelTemplate>
    ...

    <SemanticZoom x:Name="wideSeZo" ... >
        <SemanticZoom.ZoomedInView>
            <GridView
            ...
            ItemsPanel="{StaticResource ZoomedInItemsPanelTemplate}">
            ...
  • Terakhir, tambahkan markup Visual State Manager yang sesuai sebagai anak pertama dari LayoutRoot.
    <Grid x:Name="LayoutRoot" ... >
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState x:Name="WideState">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="548"/>
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="wideSeZo.Visibility" Value="Visible"/>
                        <Setter Target="narrowSeZo.Visibility" Value="Collapsed"/>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

    ...

Gaya akhir

Semua yang tersisa adalah beberapa penyesuaian gaya akhir.

  • Di AuthorGroupHeaderTemplate, atur Foreground="White" pada TextBlock sehingga terlihat benar saat berjalan pada keluarga perangkat seluler.
  • Tambahkan FontWeight="SemiBold" ke TextBlock di dan AuthorGroupHeaderTemplateZoomedOutAuthorTemplate.
  • Dalam narrowSeZo, header grup dan penulis dalam tampilan yang diperkecil diratakan kiri alih-alih direntangkan, jadi mari kita kerjakan. Kita akan membuat HeaderContainerStyle untuk tampilan yang diperbesar tampilannya dengan HorizontalContentAlignment diatur ke Stretch. Dan kita akan membuat ItemContainerStyle untuk tampilan zoomed-out yang berisi Setter yang sama. Inilah yang terlihat seperti.
   <Style x:Key="AuthorGroupHeaderContainerStyle" TargetType="ListViewHeaderItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    </Style>

    <Style x:Key="ZoomedOutAuthorItemContainerStyle" TargetType="ListViewItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    </Style>

    ...

    <SemanticZoom x:Name="narrowSeZo" ... >
        <SemanticZoom.ZoomedInView>
            <ListView
            ...
                <ListView.GroupStyle>
                    <GroupStyle
                    ...
                    HeaderContainerStyle="{StaticResource AuthorGroupHeaderContainerStyle}"
                    ...
        <SemanticZoom.ZoomedOutView>
            <ListView
                ...
                ItemContainerStyle="{StaticResource ZoomedOutAuthorItemContainerStyle}"
                ...

Urutan operasi gaya terakhir membuat aplikasi terlihat seperti ini.

aplikasi windows 10 port yang berjalan di perangkat desktop, tampilan yang diperbesar tampilannya, dua ukuran jendela

Aplikasi Windows 10 yang di-port berjalan di perangkat Desktop, tampilan yang diperbesar tampilannya, dua ukuran jendela aplikasi windows 10 port yang berjalan di perangkat desktop, tampilan zoomed-out, dua ukuran jendela

Aplikasi Windows 10 yang di-port berjalan di perangkat Desktop, tampilan yang diperkecil, dua ukuran jendela

aplikasi windows 10 port yang berjalan di perangkat seluler, tampilan yang diperbesar tampilannya

Aplikasi Windows 10 yang di-port berjalan di perangkat Seluler, tampilan yang diperbesar tampilannya

aplikasi windows 10 port yang berjalan di perangkat seluler, tampilan yang diperkecil

Aplikasi Windows 10 yang di-port berjalan di perangkat Seluler, tampilan yang diperkecil

Membuat model tampilan lebih fleksibel

Bagian ini berisi contoh fasilitas yang terbuka bagi kami karena telah memindahkan aplikasi kami untuk menggunakan UWP. Di sini, kami menjelaskan langkah-langkah opsional yang dapat Anda ikuti untuk membuat model tampilan Anda lebih fleksibel saat diakses melalui CollectionViewSource. Model tampilan (file sumber berada di ViewModel\BookstoreViewModel.cs) yang kami port dari aplikasi Windows Phone Silverlight Bookstore2WPSL8 berisi kelas bernama Penulis, yang berasal dari Daftar<T>, di mana T adalah BookSku. Itu berarti bahwa kelas Penulis adalah sekelompok BookSku.

Ketika kami mengikat CollectionViewSource.Source ke Penulis, satu-satunya hal yang kami komunikasikan adalah bahwa setiap Penulis dalam Penulis adalah sekelompok sesuatu. Kami menyerahkannya ke CollectionViewSource untuk menentukan bahwa Penulis, dalam hal ini, sekelompok BookSku. Itu berfungsi: tetapi tidak fleksibel. Bagaimana jika kita ingin Penulis menjadi sekelompok BookSku dan sekelompok alamat tempat penulis tinggal? Penulis tidak boleh menjadi kedua grup tersebut. Tetapi, Penulis dapat memiliki sejumlah grup. Dan itulah solusinya: gunakan pola has-a-group alih-alih , atau selain itu, pola is-a-group yang kita gunakan saat ini. Berikut caranya:

  • Ubah Penulis agar tidak lagi berasal dari Daftar<T>.
  • Tambahkan bidang ini ke
  • Tambahkan properti ini ke
  • Dan tentu saja kita dapat mengulangi dua langkah di atas untuk menambahkan grup sebanyak mungkin ke Penulis sesuai kebutuhan.
  • Ubah implementasi metode AddBookSku menjadi this.BookSkus.Add(bookSku);.
  • Sekarang penulis memiliki setidaknya satu grup, kita perlu berkomunikasi ke CollectionViewSource yang mana dari grup yang harus digunakannya. Untuk melakukannya, tambahkan properti ini ke CollectionViewSource: ItemsPath="BookSkus"

Perubahan tersebut membuat aplikasi ini secara fungsional tidak berubah, tetapi Anda sekarang tahu bagaimana Anda dapat memperluas Penulis, dan CollectionViewSource, jika Perlu. Mari kita buat satu perubahan terakhir pada Penulis sehingga, jika kita menggunakannya tanpa menentukan CollectionViewSource.ItemsPath, grup default yang kita pilih akan digunakan:

    public class Author : IEnumerable<BookSku>
    {
        ...

        public IEnumerator<BookSku> GetEnumerator()
        {
            return this.BookSkus.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.BookSkus.GetEnumerator();
        }
    }

Dan sekarang kita dapat memilih untuk menghapus ItemsPath="BookSkus" jika kita suka dan aplikasi masih akan berulah dengan cara yang sama.

Kesimpulan

Studi kasus ini melibatkan antarmuka pengguna yang lebih ambisius daripada yang sebelumnya. Semua fasilitas dan konsep Windows Phone Silverlight LongListSelector—dan banyak lagi—ditemukan tersedia untuk aplikasi UWP dalam bentuk SemanticZoom, ListView, GridView, dan CollectionViewSource. Kami menunjukkan cara menggunakan kembali, atau menyalin dan mengedit, baik kode imperatif maupun markup dalam aplikasi UWP untuk mencapai fungsionalitas, UI, dan interaksi yang disesuaikan agar sesuai dengan faktor bentuk perangkat Windows tersempit dan terluas serta semua ukuran di antaranya.