国产精品青草久-国产精品情侣愉拍-国产精品区网红主-国产精品区一区二-国产精品热久久-国产精品热热热-国产精品人aⅴ-国产精品人成在线-国产精品人妻人伦-国产精品人人

金喜正规买球

Xamarin Forms的Prism第二部分:基本導航和依賴注入(Dependency Injection)模式

原創|使用教程|編輯:黃竹雯|2016-09-18 18:01:27.000|閱讀 1777 次

概述:本系列的第2部分展示了Prism如何在一個MVVM應用程序中啟動導航。

# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>

相關鏈接:

前一篇文章中,我們已經開始介紹在Xamarin Forms應用程序中如何利用Prism(6.2)的新版本來實現MVVM模式的基本概念。到目前為止,我們還沒有看到什么特別的東西是我們用另一個框架做不到的:我們在上一篇文章中創建了一個視圖(View)、一個視圖模型(ViewModel),然后我們通過綁定連接它們。在這篇文章中,我們將看到Prism如何幫助處理一個在MVVM應用程序中很難處理的非常常見的場景:導航和頁面的生命周期。

Xamarin Forms的Prism第二部分:基本導航和依賴注入(Dependency Injection)模式

正如我們在前一篇文章中提到的,我們要為TrackSeries——一個提供電視節目信息的網站,創建一個簡單的客戶端。該應用程序將顯示當前的頂級系列,將允許用戶發現更多關于它的內容。為了實現這一目標,我們可以用一組網站提供的REST服務,這是非常簡單的使用和處理REST服務的遵循標準的最佳實踐:你調用一個使用HTTP命令的URL,接收返回一個JSON響應結果。

舉個例子,如果你想知道哪些是頂級系列,你可以執行一個HTTP GET請求到以下URL:。服務將返回給你一個JSON響應,包含頂級系列的所有細節:

[
   {
      "id":121361,
      "name":"Game of Thrones",
      "followers":10230,
      "firstAired":"2011-04-17T21:00:00-04:00",
      "country":"us",
      "overview":"Seven noble families fight for control of the mythical land of Westeros. Friction between the houses leads to full-scale war. All while a very ancient evil awakens in the farthest north. Amidst the war, a neglected military order of misfits, the Night's Watch, is all that stands between the realms of men and the icy horrors beyond.",
      "runtime":55,
      "status":"Continuing",
      "network":"HBO",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt0944947",
      "tvdbId":121361,
      "tmdbId":1399,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/121361-49.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/121361-15.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/121361-g22.jpg"
      },
      "genres":[
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":5,
            "name":"Fantasy"
         }
      ],
      "added":"2014-08-08T13:30:46.227",
      "lastUpdated":"2016-08-18T03:03:50.05",
      "followedByUser":false,
      "slugName":"game-of-thrones"
   },
   {
      "id":257655,
      "name":"Arrow",
      "followers":7517,
      "firstAired":"2012-10-10T20:00:00-04:00",
      "country":"us",
      "overview":"Oliver Queen and his father are lost at sea when their luxury yacht sinks. His father doesn't survive. Oliver survives on an uncharted island for five years learning to fight, but also learning about his father's corruption and unscrupulous business dealings. He returns to civilization a changed man, determined to put things right. He disguises himself with the hood of one of his mysterious island mentors, arms himself with a bow and sets about hunting down the men and women who have corrupted his city.",
      "runtime":45,
      "status":"Continuing",
      "network":"The CW",
      "airDay":"Wednesday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt2193021",
      "tvdbId":257655,
      "tmdbId":1412,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/257655-8.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/257655-47.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/257655-g9.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         }
      ],
      "added":"2014-08-08T13:37:00.133",
      "lastUpdated":"2016-08-15T03:11:32.013",
      "followedByUser":false,
      "slugName":"arrow"
   },
   {
      "id":153021,
      "name":"The Walking Dead",
      "followers":7185,
      "firstAired":"2010-10-31T21:00:00-04:00",
      "country":"us",
      "overview":"The world we knew is gone. An epidemic of apocalyptic proportions has swept the globe causing the dead to rise and feed on the living. In a matter of months society has crumbled. In a world ruled by the dead, we are forced to finally start living. Based on a comic book series of the same name by Robert Kirkman, this AMC project focuses on the world after a zombie apocalypse. The series follows a police officer, Rick Grimes, who wakes up from a coma to find the world ravaged with zombies. Looking for his family, he and a group of survivors attempt to battle against the zombies in order to stay alive.\n",
      "runtime":50,
      "status":"Continuing",
      "network":"AMC",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt1520211",
      "tvdbId":153021,
      "tmdbId":1402,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/153021-38.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/153021-77.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/153021-g44.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":6,
            "name":"Horror"
         },
         {
            "id":20,
            "name":"Suspense"
         }
      ],
      "added":"2014-08-08T13:31:18.617",
      "lastUpdated":"2016-08-18T03:04:00.28",
      "followedByUser":false,
      "slugName":"the-walking-dead"
   },
   {
      "id":279121,
      "name":"The Flash (2014)",
      "followers":7069,
      "firstAired":"2014-10-07T20:00:00-04:00",
      "country":"us",
      "overview":"After a particle accelerator causes a freak storm, CSI Investigator Barry Allen is struck by lightning and falls into a coma. Months later he awakens with the power of super speed, granting him the ability to move through Central City like an unseen guardian angel. Though initially excited by his newfound powers, Barry is shocked to discover he is not the only \"meta-human\" who was created in the wake of the accelerator explosion – and not everyone is using their new powers for good. Barry partners with S.T.A.R. Labs and dedicates his life to protect the innocent. For now, only a few close friends and associates know that Barry is literally the fastest man alive, but it won't be long before the world learns what Barry Allen has become... The Flash.",
      "runtime":45,
      "status":"Continuing",
      "network":"The CW",
      "airDay":"Tuesday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt3107288",
      "tvdbId":279121,
      "tmdbId":60735,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/279121-37.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/279121-23.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/279121-g7.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         }
      ],
      "added":"2014-08-08T13:45:59.087",
      "lastUpdated":"2016-08-17T03:09:18.7",
      "followedByUser":false,
      "slugName":"the-flash-2014"
   },
   {
      "id":80379,
      "name":"The Big Bang Theory",
      "followers":6922,
      "firstAired":"2007-09-25T20:00:00-04:00",
      "country":"us",
      "overview":"What happens when hyperintelligent roommates Sheldon and Leonard meet Penny, a free-spirited beauty moving in next door, and realize they know next to nothing about life outside of the lab. Rounding out the crew are the smarmy Wolowitz, who thinks he's as sexy as he is brainy, and Koothrappali, who suffers from an inability to speak in the presence of a woman.",
      "runtime":25,
      "status":"Continuing",
      "network":"CBS",
      "airDay":"Monday",
      "airTime":"8:00 PM",
      "contentRating":"TV-PG",
      "imdbId":"tt0898266",
      "tvdbId":80379,
      "tmdbId":1418,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/80379-43.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/80379-38.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/80379-g28.jpg"
      },
      "genres":[
         {
            "id":3,
            "name":"Comedy"
         }
      ],
      "added":"2014-08-08T13:27:13.18",
      "lastUpdated":"2016-08-18T03:03:10.947",
      "followedByUser":false,
      "slugName":"the-big-bang-theory"
   },
   {
      "id":176941,
      "name":"Sherlock",
      "followers":6387,
      "firstAired":"2010-07-25T20:30:00+01:00",
      "country":"gb",
      "overview":"Sherlock is a British television crime drama that presents a contemporary adaptation of Sir Arthur Conan Doyle's Sherlock Holmes detective stories. Created by Steven Moffat and Mark Gatiss, it stars Benedict Cumberbatch as Sherlock Holmes and Martin Freeman as Doctor John Watson.",
      "runtime":90,
      "status":"Continuing",
      "network":"BBC One",
      "airDay":"Sunday",
      "airTime":"8:30 PM",
      "contentRating":"TV-14",
      "imdbId":"tt1475582",
      "tvdbId":176941,
      "tmdbId":19885,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/176941-11.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/176941-3.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/176941-g5.jpg"
      },
      "genres":[
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":16,
            "name":"Mystery"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:32:27.247",
      "lastUpdated":"2016-08-17T03:07:09.747",
      "followedByUser":false,
      "slugName":"sherlock"
   },
   {
      "id":263365,
      "name":"Marvel's Agents of S.H.I.E.L.D.",
      "followers":5372,
      "firstAired":"2013-09-24T22:00:00-04:00",
      "country":"us",
      "overview":"Phil Coulson (Clark Gregg, reprising his role from \"The Avengers\" and \"Iron Man\" ) heads an elite team of fellow agents with the worldwide law-enforcement organization known as SHIELD (Strategic Homeland Intervention Enforcement and Logistics Division), as they investigate strange occurrences around the globe. Its members -- each of whom brings a specialty to the group -- work with Coulson to protect those who cannot protect themselves from extraordinary and inconceivable threats, including a formidable group known as Hydra.",
      "runtime":45,
      "status":"Continuing",
      "network":"ABC (US)",
      "airDay":"Tuesday",
      "airTime":"10:00 PM",
      "contentRating":"TV-PG",
      "imdbId":"tt2364582",
      "tvdbId":263365,
      "tmdbId":1403,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/263365-16.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/263365-26.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/263365-g7.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":5,
            "name":"Fantasy"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         }
      ],
      "added":"2014-08-08T13:39:45.967",
      "lastUpdated":"2016-08-18T03:05:30.987",
      "followedByUser":false,
      "slugName":"marvels-agents-of-shield"
   },
   {
      "id":81189,
      "name":"Breaking Bad",
      "followers":5227,
      "firstAired":"2008-01-20T21:00:00-04:00",
      "country":"us",
      "overview":"Walter White, a struggling high school chemistry teacher, is diagnosed with advanced lung cancer. He turns to a life of crime, producing and selling methamphetamine accompanied by a former student, Jesse Pinkman, with the aim of securing his family's financial future before he dies.",
      "runtime":45,
      "status":"Ended",
      "network":"AMC",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt0903747",
      "tvdbId":81189,
      "tmdbId":1396,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/81189-10.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/81189-21.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/81189-g21.jpg"
      },
      "genres":[
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":20,
            "name":"Suspense"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:27:33.917",
      "lastUpdated":"2016-08-13T03:01:47.063",
      "followedByUser":false,
      "slugName":"breaking-bad"
   },
   {
      "id":247808,
      "name":"Suits",
      "followers":4835,
      "firstAired":"2011-06-24T21:00:00-04:00",
      "country":"us",
      "overview":"Suits follows college drop-out Mike Ross, who accidentally lands a job with one of New York's best legal closers, Harvey Specter. They soon become a winning team with Mike's raw talent and photographic memory, and Mike soon reminds Harvey of why he went into the field of law in the first place.",
      "runtime":45,
      "status":"Continuing",
      "network":"USA Network",
      "airDay":"Wednesday",
      "airTime":"9:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt1632701",
      "tvdbId":247808,
      "tmdbId":37680,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/247808-27.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/247808-43.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/247808-g17.jpg"
      },
      "genres":[
         {
            "id":4,
            "name":"Drama"
         }
      ],
      "added":"2014-08-08T13:33:45.423",
      "lastUpdated":"2016-08-18T03:04:21.37",
      "followedByUser":false,
      "slugName":"suits"
   },
   {
      "id":274431,
      "name":"Gotham",
      "followers":4718,
      "firstAired":"2014-09-23T20:00:00-04:00",
      "country":"us",
      "overview":"An action-drama series following rookie detective James Gordon as he battles villains and corruption in pre-Batman Gotham City.",
      "runtime":45,
      "status":"Continuing",
      "network":"FOX (US)",
      "airDay":"Monday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt3749900",
      "tvdbId":274431,
      "tmdbId":60708,
      "language":"en",
      "images":{
         "poster":"//static.trackseries.tv/banners/posters/274431-17.jpg",
         "fanart":"//static.trackseries.tv/banners/fanart/original/274431-22.jpg",
         "banner":"//static.trackseries.tv/banners/graphical/274431-g6.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:44:55.4",
      "lastUpdated":"2016-08-17T03:08:55.473",
      "followedByUser":false,
      "slugName":"gotham"
   }
]

為了使用這些應用程序中的API,我用一組方法創建了一個稱為TsApiService的類,通過.NET框架和流行的JSON.NET庫的HttpClient類,負責下載JSON,解析它并返回一組可以使用C#很容易地操縱的對象。為了更好地構成我的解決方案, 我已經決定把所有的通信相關類與REST API (如服務和實體)放置在另一個叫做InfoSeries.Core的便攜式類庫(Portable Class Library)中,這是一個與實際Xamarin Forms應用程序的相比不同的PCL。

這就是負責解析之前的JSON的方法返回一個C#對象列表:

public async Task<List<SerieFollowersVM>> GetStatsTopSeries()
{
    using (HttpClient client = new HttpClient())
    {
        try
        {
            var response = await client.GetAsync("//api.trackseries.tv/v1/Stats/TopSeries");
            if (!response.IsSuccessStatusCode)
            {
                var error = await response.Content.ReadAsAsync<TrackSeriesApiError>();
                var message = error != null ? error.Message : "";
                throw new TrackSeriesApiException(message, response.StatusCode);
            }
            return await response.Content.ReadAsAsync<List<SerieFollowersVM>>();
        }
        catch (HttpRequestException ex)
        {
            throw new TrackSeriesApiException("", false, ex);
        }
        catch (UnsupportedMediaTypeException ex)
        {
            throw new TrackSeriesApiException("", false, ex);
        }
    }
}

HttpClient類的GetAsync() 方法執行GET請求到URL,返回結果包含JSON響應的字符串。這個結果存儲在響應的Content 屬性:如果請求成功(我們使用IsSuccessStatusCode 屬性檢查這種情況),我們使用Content 屬性公開的ReadAsAsync< T >方法自動轉換為JSON導致SerieFollowersVM 對象的集合。SerieFollowersVM 無非是一個映射JSON響應的每個屬性的類 (如namecountryruntime)到一個C#屬性:

public class SerieFollowersVM
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Followers { get; set; }
    public DateTimeOffset FirstAired { get; set; }
    public string Country { get; set; }
    public string Overview { get; set; }
    public int Runtime { get; set; }
    public string Status { get; set; }
    public string Network { get; set; }
    public DayOfWeek? AirDay { get; set; }
    public string AirTime { get; set; }
    public string ContentRating { get; set; }
    public string ImdbId { get; set; }
    public int TvdbId { get; set; }
    public string Language { get; set; }
    public ImagesSerieVM Images { get; set; }
    public ICollection<GenreVM> Genres { get; set; }
    public DateTime Added { get; set; }
    public DateTime LastUpdated { get; set; }
    public string SlugName { get; set; }
}

在GitHub的完整示例(為了方便各位讀者,小編已經為大家整理了,請點擊這里下載)中你會發現很多這樣的類(映射各種被TrackSeries API返回的JSON響應)。此外,TsApiService 將實現另外的方法,一個用于我們想在我們的應用程序中利用的每個API的方法。我不會詳細解釋每個方法,因為這將超出本文的范圍,你可以在GitHub上看到所有的細節。對于這篇文章的目的,你只需要知道服務只是公開了一組方法,我們可以在各種ViewModels中使用來檢索可用的電視節目的信息。

注意:默認情況下,HttpClient 類沒有提供一個ReadAsAsync< T >方法,能夠自動對JSON響應為C#對象進行反序列化。為了獲得該擴展方法,我們需要添加Microsoft.AspNet.WebApi.Client NuGet包到便攜類庫(Portable Class Library)。為了讓它正常工作,你需要將這個包添加到解決方案的每個項目(Xamarin Forms PCL、Core PCL和所有特定于平臺的項目)。

然而,為了正確利用依賴注入(dependency injection),我們需要一個接口來描述TsApiService 類提供的操作。這就是我們的接口的樣子:

public interface ITsApiService
{
    Task<List<SerieFollowersVM>> GetStatsTopSeries();
    Task<SerieVM> GetSerieByIdAll(int id);
    Task<SerieInfoVM> GetSerieById(int id);
    Task<List<SerieSearch>> GetSeriesSearch(string name);
    Task<SerieFollowersVM> GetStatsSerieHighlighted();
}

現在我們有了一個服務,我們可以學習(多虧Prism)我們可以如何注冊到它的依賴容器,它會自動注入在我們的ViewModels。實際上,從這個角度來看,沒有什么特別強調:這與其他MVVM框架使用的方法是相同的,利用依賴注入的方法。首先,我們需要注冊我們想要在容器中使用的接口和實現之間的協會。在Prism的情況下,我們需要用App類的RegisterTypes()方法,通過使用Container對象和RegisterType< T, Y >()方法(其中T 是接口,Y是具體實現):

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterType<ITsApiService, TsApiService>();
}

MainPage TsApiService 都在容器注冊了,我們可以在ViewModel獲得它,只需添加一個參數在公共構造函數,就像以下示例:

public class MainPageViewModel : BindableBase
{
    private readonly ITsApiService _apiService;
    public MainPageViewModel(ITsApiService apiService)
    {
        _apiService = apiService;
    }
}

MainPageViewModel 類將被加載時,我們已經在容器注冊的ITsApiService實現(在我們的例子中是TsApiService 類)將自動注入構造函數的參數,允許我們以我們將在ViewModel創建的所有其他的方法和屬性來使用它。使用這種方法,我們將容易改變服務的實現,以防我們需要它:它將足以改變App類的注冊類型,并且每個ViewModel將自動開始使用新的版本。

處理導航的生命周期

現在我們有一個服務,它提供了一種方法來檢索頂級系列的列表,在ViewModel加載時我們需要調用它。我們的目標是顯示(在應用程序的主頁)最熱門的電視節目列表。但是,我們即將面對使用MVVM模式時的一個常見的問題:檢索頂級系列列表的方法是異步的,但是隨著當前實現,唯一我們可以執行數據加載的地方就是ViewModel的構造函數,它不能執行異步調用(在C#中,事實上,一個類的構造函數不能用async關鍵字,因此,你不能用等待前綴的方法)。在non-MVVM應用程序中,這個問題很容易解決,因為導航的生命周期方法是由每一個平臺基本提供的。Xamarin Forms毫無例外,我們可以利用(在XAML頁面類的后面的代碼)OnAppearing()OnDisappearing()方法:因為它們是事件,我們可以沒有問題地調用異步代碼。

為了解決這個問題,Prism提供一個稱為INavigationAware的接口,我們可以在ViewModels實現。當我們實現它,我們可以訪問OnNavigatedTo()OnNavigatedFrom()事件,我們可以使用它們來執行數據加載或清理操作。這就是實現這個接口后我們的MainPageViewModel 的樣子:

public class MainPageViewModel : BindableBase, INavigationAware
{
    private readonly TsApiService _apiService;
    private ObservableCollection<SerieFollowersVM> _topSeries;
    public ObservableCollection<SerieFollowersVM> TopSeries
    {
        get { return _topSeries; }
        set { SetProperty(ref _topSeries, value); }
    }
    public MainPageViewModel(TsApiService apiService)
    {
        _apiService = apiService;
    }
    public void OnNavigatedFrom(NavigationParameters parameters)
    {
    }
    public async void OnNavigatedTo(NavigationParameters parameters)
    {
        var result = await _apiService.GetStatsTopSeries();
        TopSeries = new ObservableCollection<SerieFollowersVM>(result);
    }
}

正如你所看到的,現在我們實現了一個稱為OnNavigatedTo()的方法,我們可以安全地執行異步調用和加載數據。我們調用TsApiService類的GetStatsTopSeries()方法,我們封裝結果集合到ObservableCollection屬性。這是我們要連接的屬性,通過綁定到一個ListView 控件,為了在主頁顯示電視節目列表。

出于完整性的考慮,這是MainPage的XAML的樣子:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="//xamarin.com/schemas/2014/forms"
             xmlns:x="//schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="InfoSeries.Views.MainPage"
             Title="Info Series">
  <ContentPage.Resources>
    <ResourceDictionary>
      <DataTemplate x:Key="TopSeriesTemplate">
        <ViewCell>
          <ViewCell.View>
            <Grid>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="2*" />
              </Grid.ColumnDefinitions>
              <Image Source="{Binding Images.Poster}" Grid.Column="0" x:Name="TopImage" />
              <StackLayout Grid.Column="1" Margin="12, 0, 0, 0" VerticalOptions="Start">
                <Label Text="{Binding Name}" FontSize="18" TextColor="#58666e" FontAttributes="Bold" />
                <StackLayout Orientation="Horizontal">
                  <Label Text="Runtime: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Runtime}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Air day: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding AirDay}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Country: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Country}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Network: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Network}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
              </StackLayout>
            </Grid>
          </ViewCell.View>
        </ViewCell>
      </DataTemplate>
    </ResourceDictionary>
  </ContentPage.Resources>
  <ListView ItemTemplate="{StaticResource TopSeriesTemplate}"
            ItemsSource="{Binding Path=TopSeries}" RowHeight="200"/>
</ContentPage>

如果你已經知道Xamarin Forms(或一般的XAML),你應該會覺得這段代碼很容易理解:頁面包含一個ListView 控件、一個描述單個電視節目的模板。我們展示節目的海報,還有一些其他信息,如標題、運行時、生產國家等等。因為(根據命名約定)MainPageViewModel 類已經設置為頁面的BindingContext ,我們可以通過綁定ListViewItemsSource屬性和我們之前在ViewModel填充的TopSeries集合進行簡單地連接。

導航與參數

我們已經看到了如何利用OnNavigatedTo()方法來執行數據加載,但通常這種方法在另一個場景中也是有用的:檢索參數通過前一頁,這通常需要了解當前的上下文(在我們的示例中,在我們的應用程序的詳細信息頁面,我們需要理解用戶已經選擇的電視節目)。

Prism支持這個特性是由于一個稱為NavigationParameters的類稱,可以作為NavigationServiceNavigationAsync()方法的一個可選參數傳遞,它被自動包括作為OnNavigatedTo()OnNavigatedFrom()事件的參數。讓我們看看如何通過向我們的應用程序添加詳細信息頁面利用這個特性,顯示選擇的節目的一些額外的信息。

第一步是同時添加一個新頁面到Views 文件夾中(稱為DetailPage.xaml)和一個新類到ViewModels文件夾中(稱為DetailPageViewModel.cs)。你需要記住,每一頁都需要在App類的容器中注冊,在OnRegisterTypes()方法內:

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterTypeForNavigation<DetailPage>();
    Container.RegisterType<ITsApiService, TsApiService>();
}

由于命名約定,我們不需要做任何特別的操作:新頁面和新ViewModel已經連接。現在我們需要通過ListView控件中所選條目到新頁面。讓我們先看看如何在主頁處理選擇。通過使用由我親愛的朋友Corrado Cavalli創建的庫,我們會得到一些幫助,它允許你在Xamarin Forms應用程序實現行為。可用的行為中的EventToCommand允許我們連接暴露于控件的任何事件與ViewModel中定義的命令。我們要用它來連接ListView 控件的ItemTapped 事件(當用戶點擊列表中的一個項目時會觸發)與我們要在MainPageViewModel中創建來觸發導航到詳細頁面的命令。

你可以從NuGet安裝由Corrado創建的套包,它的名字叫Corcav.Behaviors。使用它你需要添加一個額外的名稱空間到MainPage的root,像下面這個示例:

<ContentPage xmlns="//xamarin.com/schemas/2014/forms"
             xmlns:x="//schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             xmlns:behaviors="clr-namespace:Corcav.Behaviors;assembly=Corcav.Behaviors"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="InfoSeries.Views.MainPage"
             Title="Info Series">
    ...
</ContentPage>

然后你可以申請ListView 控件的行為,就像你在普通Windows應用程序中會做的一樣:

<ListView ItemTemplate="{StaticResource TopSeriesTemplate}"
          ItemsSource="{Binding Path=TopSeries}" RowHeight="200">
  <behaviors:Interaction.Behaviors>
    <behaviors:BehaviorCollection>
      <behaviors:EventToCommand EventName="ItemTapped" Command="{Binding GoToDetailPage}" />
    </behaviors:BehaviorCollection>
  </behaviors:Interaction.Behaviors>
</ListView>

由于這種行為,我們已經連接了ListView 控件的ItemTapped 事件與我們要在ViewModel定義的稱為GoToDetailPage 的命令。從一個框架的角度,Prism沒有做任何不尋常的事幫助開發者實現命令:它只是提供了一個稱為DelegateCommand的類,這允許你定義操作來執行調用命令和可選的條件來啟動命令。如果你有一些MVVM Light以往的經驗,它會以RelayCommand 類那樣完全相同的方式運作。以下是我們的命令在MainPageViewModel 類的樣子:

private DelegateCommand<ItemTappedEventArgs> _goToDetailPage;
public DelegateCommand<ItemTappedEventArgs> GoToDetailPage
{
    get
    {
        if (_goToDetailPage == null)
        {
            _goToDetailPage = new DelegateCommand<ItemTappedEventArgs>(async selected =>
            {
                NavigationParameters param = new NavigationParameters();
                param.Add("show", selected.Item);
                await _navigationService.NavigateAsync("DetailPage", param);
            });
        }
        return _goToDetailPage;
    }
}

我們已經創建了的命令是一個參數化命令;事實上,屬性類型是DelegateCommand< ItemTappedEventArgs >:這種方式,在方法內部,我們獲得存儲在Item 屬性中的選中的條目。命令觸發時調用的方法展示了如何用參數的工作原理導航:首先我們創建一個新的NavigationParameters對象,最后,只不過是一個你可以存儲鍵/值對的字典。因此,我們只需添加一個新項,作為關鍵,關鍵字show ,作為值,選中的項的類型是SerieFollowersVM。這是與我們在App類中看到的導航的唯一的區別:其余的都是一樣的,這意味著我們調用NavigationServicetheNavigateAsync()方法,傳遞標識詳細信息頁面(DetailPage)和參數的關鍵參數。

重要事項!App類中,我們能夠自動使用NavigationService ,因為它繼承自PrismApplication 類。如果我們要在ViewModel中使用NavigationService (像在這種情況下),我們需要使用基于依賴注入(dependency injection)的傳統方法。NavigationService 實例已經在Prism容器注冊,所以我們只需要添加一個INavigationService 參數到MainPageViewModel的公共構造函數:

public MainPageViewModel(TsApiService apiService, INavigationService navigationService)
{
    _apiService = apiService;
    _navigationService = navigationService;
}

既然我們已經完成了導航到詳細頁面,我們就需要檢索DetailPageViewModel 類的參數。第一步,像我們為MainPageViewModel做的那樣,讓它從INavigationAware 接口繼承,除了BindableBase 類。通過這種方式,我們可以訪問OnNavigatedTo()事件:

public class DetailPageViewModel : BindableBase, INavigationAware
{
    private SerieFollowersVM _selectedShow;
    public SerieFollowersVM SelectedShow
    {
        get { return _selectedShow; }
        set { SetProperty(ref _selectedShow, value); }
    }
    public DetailPageViewModel()
    {
    }
    public void OnNavigatedFrom(NavigationParameters parameters)
    {
    }
    public void OnNavigatedTo(NavigationParameters parameters)
    {
        SelectedShow = parameters["show"] as SerieFollowersVM;
    }
}

前面的代碼顯示了如何處理我們從主頁收到的參數:同一個我們通過的MainPageViewModel對象到作為 OnNavigatedTo()方法的參數傳遞的NavigateAsync()方法。因此,我們可以用show 鍵簡單的檢索先前存儲的項。在這種情況下,因為我們預計SerieFollowersVM類型的對象,我們可以執行一個計算并將其存儲到稱為SelectedShow的ViewModel的屬性中。多虧了這個屬性,我們可以利用綁定到選擇顯示的各種信息連接到XAML頁面的空間。以下是DetailPage.xaml的樣子:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="//xamarin.com/schemas/2014/forms"
             xmlns:x="//schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             Title="{Binding Path=SelectedShow.Name}"
             x:Class="InfoSeries.Views.DetailPage">
  <StackLayout>
    <Image x:Name="InfoPoster"
           Source="{Binding Path=SelectedShow.Images.Fanart}" Aspect="AspectFill" />
    <Label Text="{Binding Path=SelectedShow.Overview}" LineBreakMode="WordWrap" FontSize="13" TextColor="#98a6ad" Margin="15" />
  </StackLayout>
</ContentPage>

內容很簡單:我們顯示show的圖片(存儲在SelectedShow.Images.Fanart屬性)和一段簡要描述(存儲在SelectedShow.Overview屬性)。

結束語

在這篇文章中,我們已經看到在用Prism 作為MVVM框架創建的Xamarin Forms應用程序中處理導航和依賴注入的一些基本概念。在下一篇文章中,我們將看到幾個高級場景,有關導航和特定于平臺的代碼的處理。你能在GitHub存儲庫找到這篇文章使用的示例應用程序(為了方便各位讀者,小編已經為大家整理了,請點擊這里下載)。

本文翻譯自:

 

PS: 關于移動開發,這些產品你可以關注>>
關于移動開發的最新資訊和產品推薦,請<>!

標簽:移動開發導航控件Xamarin

本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn


為你推薦

  • 推薦視頻
  • 推薦活動
  • 推薦產品
  • 推薦文章
  • 慧都慧問
掃碼咨詢


添加微信 立即咨詢

電話咨詢

客服熱線
023-68661681

TOP
国产啪精品视 | 91桃色永久免费福利版下载 | 精品人妻伦一二三区久久 | 日韩午夜影院在线观看 | 欧美日韩久久久久久精品 | 国产高清黄网站全免费 | 日本最新最全无码不卡免费 | 性欧美长视频免费观看不卡 | 欧美日韩aⅴ一区二区三区 欧美日韩变态另类在线观看 | 丰满人妻一区二区三区视频 | 国产精品18久久久久久vr | 欧美精品第欧美第12页 | 国产又黄又 | 天天干天天操天天摸 | 99久久国产综合精品 | 中文精品久久久久国产网址 | 福利姬液液酱喷水网站在线观看 | 亚洲av无码一区二区三区在线高 | 亚洲午夜无码一级 | 亚洲国产成人久久 | 亚洲av无码影视久久乐第一区 | 特级做a爰片毛片免费69 | 亚洲av无码不卡一区二区三区 | 日本精品啪啪一区二区三区 | 波多野结衣乳巨码无在线观看 | 日韩经典欧美一区二区三区 | 亚洲一区二区+在线播放 | 国产欧美va天 | 波多野たの结衣在线播放 | 一区二区视频在线观看 | 果冻传媒国产午夜av密臀 | 成人精品www在线观看 | 97碰碰碰人妻无码视频免费 | 欧美日韩在线观看免费 | 亚洲精品国产品国语原创 | 午夜dj在线观看免费动漫大全 | 国产精品黄色大 | 精品人妻大屁股白浆无码下载 | 精品国产91久久久久久无码 | 国产免费观看久久黄av片 | 日韩午夜精品免费理论片 | 亚洲乱妇熟| 亚洲国产日韩精品在线观看色欲视 | 国产熟女真实 | 香蕉久久夜色精品国产app | 国产成人综合亚洲亚洲欧美 | 久久福利青草精品资源 | 91精品亚洲影视在线观看 | 国产成人三级视频在线观看播放 | 亚洲最大av无码网址 | 成人综合高清久久亚洲中文字幕精 | 蜜臀av国内精品久久久 | 国产伦精品一区二区三区视频痴 | 日韩超薄丝袜无码视频下载网站 | 性欧美欧美巨大69 | 亚洲乱码国产乱码精品精大量 | 99久久国语露脸精品国产 | 午夜在线观看亚洲国产欧洲 | 日本韩高清视频一区二区三区免费式 | 亚洲h动漫网 | 天天插天天干 | 亚洲av无码专区亚洲av伊甸园 | 午夜视频在线会员国产 | 亚洲日韩天堂网中文字幕 | 国产av中文字幕乱码高清 | 精品无码国产免费网站视频 | 国产在线拍揄自揄拍无码 | 91精品欧美激情在线播放 | 国产精品人成在线观看 | 国产欧美一区二区精品久 | 91在线无码精品秘入口果冻 | 91免费网址 | 在线看性爱av网站 | 精品无码区 | 91情侣在线精品国产 | 一区二区视频 | 精品欧美一区视频在线观看 | 国产成人精品无码免费播放 | 日韩av综合一区 | 午夜成人精品视频观看 | 国产在线播放永久免费 | 激情91 | 人人做人人爽 | 成人拍拍拍在线观看 | 亚洲精品国产自在现线99这里 | 欧美精品一区二区三区久久久精品 | av中文在线播放 | 国产91高潮流白浆在线播放un | 国产成人无码a区在线播放 国产成人无码a区在线观看导航 | 91青青草视频在线观看 | 国产一区二区三区不卡在线观看 | 国产精品久 | 欧美精品日韩精品一卡 | 亚洲欧美日韩久久 | 亚洲熟妇无 | 中文性按摩1区2区3区 | 国产美女在线精品免费观看 | 亚洲av无码成h人在线观看 | 伊人天堂av无码av日韩av | 久久不见久久见免费影院www日本 | 高潮未删减手机高清在线观看 | 国产在线精品一区二区夜色 | 中文自拍 | av无码不卡在线观看免费 | 亚洲成av人网站在线播放 | 中文字幕人成乱码在线观看 | 超碰在线观看97青草国产 | 国产蜜臀一区二区三区亚洲 | 三区四区五区高 | 99久久99久久免费精品小说 | 国产一级毛片在线 | 国产精品国产免费无码专区不卡 | 特级毛片a级毛片100免费播放 | 99久久婷婷国产综合精品电影 | 国产一区二区在线影院 | 日韩精品无码一区二区三区视频 | 伊人网综合 | 国产蜜桃一区二区三区在线观看 | 97精品精品一区二区 | 精品久久久一区无码av野花影视 | 91九色国产porny| 亚洲av无码久久精品色欲 | 国产精品欧美一区喷水 | 97制片厂爱豆传媒 | 欧美牲交a欧美牲交aⅴ | 精品探花在线 | 欧美日韩一卡2卡3卡4卡国色天香 | 亚洲成av人片在一线观看 | 国产丰满大乳奶水在线视频 | 精品国产免费人成电影 | 亚洲精品高清国产一线久久 | 91在线无码精品社区 | 欧美性高清bbbbbbxxxxx | 97久久天天综合色天天综合色h | 精品91| av综合在线综合导航 | 欧美日韩中文在线字幕视频 | 最新国产福利在线观看精品 | 成人精品视频 | 日韩欧美一本书道一区二区 | 91香蕉app下载 | 国产精品91天 | 中文字幕+乱码+中文乱码www | 91污视频 | 欧美中文综合在线观看 | 偷拍久久国产视频免费2025 | 日本欧美一二三区色视频 | 91在线网站 | 国产在线视频在线观看 | 日本女优久久久啊的黄色视频 | 国产白丝在线观看 | 亚洲暴爽av人 | 午夜天堂av免费在线观看 | 亚洲成在人线av壁咚影院 | 久久国产91成人免费网站 | 性做久久久久久久久不卡 | 国产亚洲一区二区三区 | 福利姬液液酱喷水网站在线观看 | 91在线国语自产拍在线观看 | 97久久久精品网站 | 日韩在线精品免費資訊 | 99久久精品无码一区二区毛片免费 | 人人干在 | 国产乱码精品一区二区三区四川人 | 成全影院大全在线观看国语 | 精品成人av一区二区三区 | 亚洲综合亚洲综合网成人 | 日韩精品亚洲精 | av狼论坛电视剧在线观看 | 91色窝窝国产蝌蚪在线观看 | 欧美日韩加勒比精品一区 | 精品麻豆色欲色欲色欲w | 99影视网| 少妇被躁爽到高潮无码久久 | 亚洲中文字幕精品无码一区 | 国产无遮挡又黄又爽网站 | 亚洲av无码成人精品区天堂 | 黄色视频 | 波多野结 | 成年女人免费视频拍拍拍 | 欧美精品在线一区 | 在线观看一区二区精品视频 | 毛片无码午夜国产视频 | 国产日韩新片无码 | 亚洲av福利天堂一区二区三 | 日韩高清在线观看永久 | 日韩福利短片在线观看 | 亚洲无码视频一区二区三区 | 亚洲一区精品在线影视 | 偷拍激情视频一区 | 亚洲va中文在线播放69 | 日夜夜天天人 | 91影视安卓最新版下载 | 亚洲欧美国产一 | 91精品天美精东蜜桃传媒入口 | 黄色免费国产小视频 | 日韩人妻无码一区二区三区久久 | 99久久精品费精品国产一区二 | 97精品国产高清久久久久蜜芽 | 中文无码肉感爆乳在线观看 | 91精产国品一二三产区 | 国产剧情调教在线 | 亚洲国产精品日韩av不卡在线 | 亚洲av永久无码精品 | 亚洲av日韩av综合在线观看 | 国产资源精品一区二区免费 | 国产精品亚洲欧美大片在线观看 | www.91看片| 亚洲av无码一区二区三区人 | 在线精品国自产拍中文字幕 | 日本一区二区三区视频免费看 | 国产综合精品久久亚洲 | 精品福利视频导航 | 欧美视频精品二区 | 加勒比东京热无码中文字幕 | 三级黄色视频 | 精品一区二区三区国产在线观看 | 日产学生妹在线观看 | 亚洲大片精品永久免费看网站 | 麻豆成人久久精品二区三区免费 | 中文国产高清综合乱色视频在线播放 | 黑人巨大无码中文字幕无码 | 亚洲熟女少妇一区二区三区视频 | 黄网站色视频大全免费看 | 国产精品无码v在线观看 | 国产很色很黄很大爽的视频 | 午夜伦情电午夜伦情电影 | 成年永久一区二区三区免费视频 | 国产一级淫片免费大片 | 97色爱| 日本一区二区在线播放 | 国产av无码片毛片 | 无码成年人电影免费看 | αv在线视频免费观看男人 а√天堂8资源中文在线 | 亚洲av无码国产精品色午友在线 | 天天躁夜夜躁狠狠久久 | 97久久天天躁夜夜躁狠狠 | 精品久久久无码人妻中 | 午夜福利在线观看一区 | 成人毛片视频在线免费观看 | 无码人妻一区二区三区在线 | 中文字幕无码久久久久久 | 97视频人人看人人做首页一97碰 | 九一国产精品视频 | 国产精品一区蜜臀91 | 国产初高中系列视频在线 | 麻豆国产在线 | 91国内自产精华天堂 | 97亚洲精品无码久久久久久久 | 国产微拍精品一区二区 | 亚洲一区免费观看 | 国内免费无码自拍视频网 | 99ri在线 | 97无码免费人妻超级碰 | 精品亚洲aⅴ在线观看 | 在线精品国精品91 | 欧美亚洲另类综 | 91小妖国产在线播放 | 精人妻无码一区二区三区 | 99re热这里只有精品 | 91精品在线播放视频大全在线观看 | 国产精品无码无卡在线播放 | 亚洲伊人精品国产午夜欧美 | 高清无码在线观看了a | 亚洲中文字幕无码爆乳app | 成人毛片18女人毛片免费看 | 日本女优久久久啊的黄色视频 | 精品成人日韩欧美软件 | 亚洲综合无码一区二区 | 久久不见久久见中文字幕免费 | 99精品久 | 99精品久久毛片a片 99精品免费在线观看 | 日韩成人毛片高清视频免费看 | 99精品国产高清一区二区三区香蕉 | 亚洲国产精品一卡在线观看 | 国产精品原巨作av无遮挡 | 欧美一区二 | 精品国产在天天在线 | 激情另类小说区 | 91网站免费看 | 成全视频高清免费观看电视 | 欧美大片在线视频黑粗硬大 | 亚洲首页国产精品丝袜 | 国产办公室秘书无码精品 | 欧美亚洲宗合另类在线观看 | 亚洲男人的天堂在线va拉文 | 丰满人妻熟妇乱又伦 | 欧美97色伦欧美一区二区日韩 | 国产成年码av片在线观看 | 中文字幕日韩哦哦 | 黄色网页大全在线免费观看啊啊啊啊 | 自拍偷亚洲成在线观看 | 91嫩草私人成人亚洲影院 | 国产欧美久久久精品影院 | 日本午夜免a费看大片中文4 | 亚洲精品熟女国产 | 欧美一区二区三区精品不卡 | 一区二区三区精密机械 | 亚洲av日韩av天堂影片精品 | 成年片免费观看网站免费观看 | 国产成人精选在线不卡网站 | 97欧美精品系列一区二区 | 国产91av视频在线观看 | 亚洲无码啪啪电影 | 欧美日韩变态另类在线观看 | 国产精品亚洲第一区在线观看 | 麻豆国产精品va在线观看不卡 | 精品一区二区三区的国产在线观 | 国产成人福利视频在线观看 | 狠狠躁天| 97夜夜澡人人爽人人喊18进 | 护士长在办公室躁bd剧情堪比大片 | 欧美日韩国产自在自线 | 日本亚洲一 | 无码av免费一 | 国产av国片 | 在线一区二区 | 日韩精品久久久毛片一区二区 | 国内欧美不卡视频 | 在线无码中文字幕一区 | 欧美午夜激情影院 | 国产边靠边叫麻豆av | 国产免费久久精品99久久 | 国产精品毛片va一区二区三区 | 国产aaaaaa| 日韩人妻系列无码专 | 亚洲欧美成人中文字幕在线 | 欧美精品久久一区二区三区 | 亚洲av无码成人精品区日韩 | 午夜福利 | 午夜视频体内射 | 东京热加勒比久久综合 | 偷拍一区| 国产超碰在线观看 | 国产成人亚洲日韩欧美久久 | 中文字幕免费无码久久99 | 国产91福利在线精 | 日韩中文字幕av免费观看 | 精品伦精品一区二区三区视 | 99热最新地址永久 | 最新中文字幕av无码不卡 | 亚洲国产中文高清在线 | 少妇爆乳无码av无码专区 | 国产精品亚洲午夜一区二区三区 | 伊人亚洲 | 亚洲无码高清福利久久 | 无码潮吹无毒不卡 | av一本久道久久综合久久鬼色 | 亚洲一区二区影视 | 国产ts人妖在线 | 无码国产在线国产97在线 | 91视频直播app| 久草精品在线观看 | 果冻国产精品麻豆成人av | 亚洲伊人精品国产欧美目韩 | 亚洲国产日韩欧美一区二区三区 | 亚洲熟女乱色一区二区三区 | 天天综合色天天综合色hd | 国产av高清怡 | 国产精品美女久久久网av | 亚洲av永久无码区成人网站 | 欧美日韩国产无线码一区 | 亚洲福利一区福 | 欧美一区二区三区激情啪啪 | 国产精品蜜臀久久久av | 亚洲精品成人网 | 精品丰满人妻一区二区三区 | 中文字幕视频一区二区 | 欧美人与禽zoz0性伦交 | 99er国产这里只有精品视频免费 | 亚洲无码二区东京热 | 国产对白在线观 | 成人午夜性a一级毛片免费看 | 国产午夜激无码av毛片 | 国产精品激情综合久久 | 一区二区三区高清视频国产女人 | 久久9国产影视大全99久 | 亚洲av综合永久无码精品天堂 | 国产亚洲精品欧洲在线观看 | 岛国大片免费观看 | 亚洲av无码一区二区ai换脸 | 婷婷亚洲久悠悠色悠在线播 | 国产无夜精华 | 日本精品一区 | 成人女人爽到高潮的a片羞羞动漫 | 国产日韩欧美在线观看 | 91av在线电影 | 国产v天堂无码一区二区三区 | 日本老司机午夜福利在线免费观看 | 成人黄色在线观看 | 精品一区二区三区在线 | 精品国产成人一区二区 | 黄桃av无码免费一区二区三区 | 97久久精品人人做人人爽 | 日韩一区二区六区中文字幕 | 中文字幕无码网 | 国产黄在线观看免费观看 | 久久99精品久久久久久hb无码 | av无码免费岛国动作片片段 | 国产精品色婷婷亚洲综合看片 | 国产精品色午夜在线看 | 国产综合精品91久久久 | 91亚洲精品自 | 岛国一区二区 | 国产精品视频永久免费播放 | 精品第一国产综合精品aⅴ完整版 | 一级做a爰片久久毛片免费看 | 在线a亚洲视频播放在线观看 | 国产成人无码18禁午夜福利p | 91成版人在线观看入口 | 丰满熟妇被猛烈进入高清片 | 丰满老熟女一级aa片色欲 | 成人性生交大片免费看中文 | 午夜久久久精品 | 无码人妻一区二区三区在线 | av片在线观看永久免费 | 欧美重口另类在线播放二区 | 成年女人黄网站18禁 | 内射人妻无码色av麻豆 | 91视频手机app官方下载 | 动漫精品专区一区二区三区不卡 | 国产午夜福利短视频 | 国产精品无码二区二区 | 高清无码在线二区亚洲无码精品免费 | 国产的视频91 | a级国产电影在线观看 | 亚洲欧美色一 | 国产成人精品无码播放 | 国产高清无密码一区二区三区 | 精品国产91 | 国产精品一级毛片9 | 午夜福利一区二区三区高清视频 | 日韩福利在线观看 | 国产精品嫩草影院久久久 | 亚洲a无码综合 | 91久久精品日日躁夜夜躁欧美 | 国产欧美一区二区三区在线看 | 丰满人妻被公侵犯中文电影版 | 99欧美日本一区二区留学生 | 欧美日韩中文国产v?另类 | 国产成人无码免费视频9 | 区二区三区乱码 | 日韩精品一区二区 | 人人狠狠久久综合亚洲婷婷 | 麻豆精品国产自产在 | 97爱爱 | 色婷婷六月亚洲综合香蕉 | 无码国产精品一区二区免费 | 国产黄色片在 | 果冻文化传媒公司官网网站 | 天美果冻星空大象视频 | 韩国无码无遮挡在线观看 | 国产一区二区 | 中文字幕亚洲乱码高清 | 国产成人亚洲综 | 亚洲国产成人精品女久久久 | 午夜理论片精品国产 | 91精品高跟丝袜在线 | 亚洲精品天堂自在久久77 | 91无码人妻精品一区二区蜜桃 | 91久久99久91天天拍拍 | 日韩欧美视频免费一区二区三区 | 精品熟女碰碰人人a久久 | 国产男女猛烈无遮挡a片 | 国产精品岛 | 天天干天天曰 | 国产第二区 | av一区二区三区不卡在线 | 色欲av伊人 | 亚洲av毛片一区二区三区 | 99国产精品懂色 | 国产精品三级在线观看无码 | 亚洲av无码久久精品蜜桃播放 | 91高清免费国产自产 | 国产亚洲精品精品国产亚洲综合 | 亚洲av成人无码网天堂 | 亚洲综合偷自成人网第页色 | 三级精品手机在线 | 91美女视频 | 亚洲一二三四五区 | 午夜理伦三级理论三级 | 国产成人精品久久一区二区精品 | 精品三级| 99久久久免费精品播放 | 色欲影视天天综合 | 精品久久久久久久久 | 福利视频99 | 91精产国品一二三产区区别在 | 97青草香蕉依人在线视频 | 国产久爱青草视频在线观看 | 91高清影院| 国产亚洲欧美一区 | 午夜成人精品无码色欲 | 国产在线精品一区二区中文 | 无码人妻精品一区二区三区9厂 | a级毛片毛片免费观看久 | 国产三级片一级在线观看 | 午夜成人网站在线观看 | 人人婷婷人人澡人人爽 | 在线观看黄aⅴ免费观看 | 成人深夜福利在 | 欧美人妻羞羞一区二区三区 | 无码精品亚 | 97人妻人人做人碰人人爽免费下载 | 欧美日韩在线视频一区 | 午夜精品免费视频观看在线 | 欧美一区二区久久精品 | 无在线观看 | 国产在线秘麻豆精品观看 | 国产成人久久av免费看 | 福利姬液液酱喷水视频在线观看 | 久996视频精品免费观看 | 99久久婷| 无码专区亚洲综合另类 | 国产成人av一区二区三区中文精品 | 免费一级黄色片 | 黄色网站在线免费观看 | 精品无码视频 | 国产成人精品电影在线观看 | 91制片厂果冻传媒有限公司 | 午夜天堂一区人妻 | 久久国产91精品 | 波多野结衣电影在线完整版在线播放 | 亚洲精品综合在线影院 | 欧洲vps | 国产av巨作无遮挡 | 国产区精品高清在线观看 | 亚洲av乱码久久精品蜜桃 | 高清亚洲乱伦三级 | 欧美精品三级一区二区三区 | 亚洲美女人黄网成人女 | 91亚洲自偷手机 | 国产不卡高清视频在线观看 | 亚洲日韩在线 | 91久久精品国产91性 | 色视频在线观看免费视频 | 成人国产精品视频 | 日韩精品青青精品视频 | 欧美精品视频一区二区三区 | 99re热有精品视频国产 | 国产精品免费视频一区二区三 | 国产精选视频 | 日日碰狠狠添天天爽不卡 | 国产永久高清免费动作片www | 一区二区三区精品黄色影院 | 亚洲成a人片在线观看中文无码 | 精品久久无码中文字幕 | 日韩精品在线一区二区在线观看 | 国自产精品手机 | 国产av综合第一页 | 精品国产乱码久久久久久免 | 欧美在线视频一区二区 | 精品动漫一区二区三区 | 亚洲一区二区三区久久 | 国产精品视 | 国产高清视频 | 一区二区三区免费观看 | 99精品国产综合久久五月天 | 一级一片在线播放在线观看 | 国产一区在线电 | 激情五月色综合国产精品 | 国产午夜精品理伦片 | av免费网址国产精品 | 国产精品一区二区久久精品 | 亚洲一区爱区精品无码 | 国产精品岛国久久久久 | 91在线无码精品秘入口9色 | 精品福利一区二区在线观看 | 国产一区二区在线视频 | 韩国三级bd高清在线观看 | 亚洲日韩乱码中文字幕 | 国产免费一区二区三区在线观看 | 精品人妻少妇一区二区大牛影视 | 日韩爽爽爽 | 91成人18禁 | 日本限制 | 果冻传媒2025精品视频 | 亚洲日本欧美中文幕 | 亚洲欧美成人中文字幕在线 | 国产精品精品一区二区三区 | 一区二区三区久久 | 亚洲成aⅴ人片在线影院八 亚洲成av | 免费无遮挡无码视频在线观看 | 99精品热在线观看视频88 | 午夜不卡无码中文字幕影院 | 亚洲无码在线观看视频免费 | 欧美成人性色xxxx视频 | 国产伦精品一区二区 | 国产日韩精品一区二区三区在线观 | 综合另类| 国产免费一区二区三区免费视频 | 神马午夜福利视频 | 蕾丝av无码专区在线观看 | 日韩欧美国产一区二区三区免费 | 91精品伊人久久久大香线蕉91 | 三颗国产精品视频一区二区免费 | 久久99青青精品免费观看 | 日韩av在线中 | 国产精品免费大片 | 九一影院 | 色欲av蜜臀av在线观看麻豆 | 日韩在线观看视频网站 | 人人双人av | 无码欧精品亚洲日韩一区 | 少妇爆乳无码av无码波霸 | 国产国语三级黄色战线免费观看av | 国产a级精精彩大片免费看 国产a级毛片 | 成人午夜福利短视频在线观 | 日韩av在线免费看 | 亚洲精选aⅴ在线观看 | 国产精品美女久久久久∧v爽 | 91久久亚洲精品影院 | 国产成人92精品午夜福利 | 国产精品日韩av在自线在免费 | 丝袜美腿| 国产va免费精品高清在线观看 | 91人人摸人人爽人人爱 | 中文字幕色婷婷在线精品中 | 国产免费无码午夜福利电影 | 亚洲аv天堂手机版在线观看 | 亚洲国产一区二区a毛片 | 日日躁夜夜躁狠狠久久av | 99国产这里有精 | 国产美女短视频一区 | 成人女人爽到高潮的a片羞羞动漫 | 成人免费无码毛片 | 国产天堂亚洲 | 黄视亚洲欧洲日韩频在线观看 | 亚洲va久久久噜噜噜久久一 | 亚洲一区二区三区 | 欧美日韩中文在线字幕视频 | 欧洲国产伦久久久久久久 | 91久久精品国产91性 | 亚洲国产av无码精品色午夜 | 色婷婷综合久久久久中文图片 | 丰满少妇熟乱xxxxx视频 | 亚洲一区二区三区高清av | 午夜福利在线观看大片 | 精品一区二区三区四区在线 | 国产不卡视频在线观看 | 精人妻无码一区二区三区 | 精品久久久久久亚洲中文字幕 | 国产aⅴ无码精品一区二区三区 | 激情五月亚洲综合中文专区 | 国产精品视频一区二区538 | 狠狠干免费视频 | 人人玩人人添人人澡免费 | 国产高清亚洲精品 | 午夜在线亚洲男人午 | 在线观看免费av无码不卡 | 在线无码免费的毛片视频 | 午夜人成视频在线男人每天 | 日韩欧群交p片内射中文 | 在线首页av免费观看 | 精品一区二区三区蜜桃hd | 99无套内射中出生娃视频 | 国产精品国产名人在线 | 国产高潮流白浆喷水在线观看 | 性无码一区 | 日韩人妻无码一区二区三区久久 | 欧美精品在线一区二区三区 | 亚洲综合色成在线观看 | 国产一区二区三区在线免费观看 | 性色av无码久久一区二区三区 | 国产精品福利一区二区久久 | 久久成人精品国产亚洲v蝌蚪 | av无码网址| 换脸国产av一区二区三区 | 日韩精品一区二区三区蜜桃 | 欧美精品一区二区精品久久 | a级国产乱理伦片在线观 | 亚洲国产av一区二区三区 | 国产免费av片在线看观看 | 久久9精品区 | 69国产超薄丝袜足j在线直播 | 日韩av高清无码 | 国产swag综艺在线观看 | 欧美亚洲日韩国产一区二区三区 | 日韩欧美p片内射久久 | 日本中文一二区高 | 91制片厂果冻传媒首页 | 久久99精品久久久久久不卡 | 97人伦影院a级毛片 97人妻精品一区二区三区 | 国产爆乳无码视频在 | 欧美日韩无线码在线观 | 99国产成人高清在线观看 | 黄色大片网站 | 国产旗袍丝袜在线观看视频 | 91国内精品久久 | 91精品视频播放 | 91老司机精品福利在线 | 国产亚洲成av人片在 | 精品无码av系列网站 | 91九色国产社区在线观看 | 91传媒在线观看视频 | 在线首页av免费观看 | 国产精品黄在线观 | 欧美人妻制服另类人妻在线 | 毛片大全在线 | 精品欧美成人高清在线观看 | 精品久久久久久久久久 | 98精品国产高清在线看入口安 | 天天爽爽夜夜爽国产精品欧 | 国产午夜亚洲精品午夜鲁丝片 | av无码免费 | 中文字幕一级mv在线观看 | 毛片无码一区二区三区a片视频 | 国产成人一区二区三区精品 | 精品日本一区二区三区在线观看 | 精品国产自产久久久 | 国产美女白嫩嫩在线观看 | 国产精品自拍第一页 | 欧美高潮喷水 | 在线视频一卡二卡 | 色约约精品免费 | 91视频专区 | 亚洲欧美另类在线观看 | 亚洲国产乱码卡一卡二卡新区 | 欧美亚洲综 | 超碰人人超碰人人 | 9久久99久久久 | 成人午夜看片 | 中文字幕国内精品久久人妻 | 91人妻无码精品一区二区三区 | 国产成人麻豆精品午夜福利在 | 色综合天天综合网在线观看 | 成人片黄网站色大片免费 | 高清喜剧片大全 | 午夜福利精品无码福利 | 亚洲精品字幕在线观看 | 天天干狠狠干夜夜 | av黄色成人在线 | 日韩成人国产精品视频 | 中文字幕人妻 | 国产成人一区二区三区 | a在线v欧美 | 亚洲另类图区影 | 欧美日韩人妻精品系列一 | 91麻豆人妻春色影视 | 日本一区二区三区免费播放视频站 | 国产真实伦在线观看视频 | 亚洲国产高 | 国产一卡2卡3卡四卡精品网站 | 97se狠狠狠狠狼亚洲综合网 | 国产99一区视频免费 | 深夜福利影院 | 91大神精品视频动漫在线观看 | 亚洲成a人v欧美综合天堂 | 国产黄色大片 | 香蕉久久夜色精品国产app | 亚洲一本之道高清在线观看 | 国产v综合v亚洲欧美久久 | 国产精品18久久久久久妖精 | 国产精品嫩草影院永久第一 | 精品国产a毛片久久久av蜜桃 | 高潮又爽又大又黄无遮挡免费 | 丰满人妻熟妇乱又伦精品 | 91秒拍国产福利片 | 国产区美女91精品视频 | 91在线精品麻豆欧美在线 | 精品国产亚洲av麻豆狂野 | 国产精品白浆无码浪潮av | 国产男女猛视频在线观看 | 国产专区在线观看 | 欧美精品在线一区二区三区 | 韩国三级hd中文字幕我的女友 | 91久久精品无码一区二区 | 人妻丰满精品一区二区a片 人妻丰满熟av无码区hd | 无码不卡一区二区三区在线 | 午夜男女视频一区二区 | 亚洲精品久久久久久一区二区 | 日本中文 | 精品无码午夜一 | 日韩成人国产精品视频 | 人人妻人人澡欧美一区二区 | 精品亚洲成a人在线观看青青 | 亚洲a∨无码天堂在线观看 亚洲a∨无码专区亚洲a∨网站 | 成人欧美一区二区三区在线电影 | 国产内射老熟女aaaa∵ | 国产剧情av麻豆香蕉精品 | 91人人 | 丰满人妻一区二区三区视频53 | 午夜a级理论片在线播放不 午夜a级理论片在线播放不卡 | 国产午夜精品一区二区三区嫩草 | 99re在线视频精品新地址 | 久久av老司机精品网站导航 | 91偷伦一区二区三区蜜臀 | 亚洲中文字幕dvd在线 | 国产一级毛片特级毛片国产 | 97碰碰人妻无码视频免费 | 91麻豆精品国产91 | 欧美日韩亚洲国产精品 | 超碰人人婷婷五月天 | 在线一本到无码av | 成年福利片在线观看 | 国产国产久热这里只有精品 | 亚洲国产精品一区二区第四页 | 99久久国产综合精品1 | 国内91视频亚洲毛片在线看 |