2016-11-09 81 views
0

我正在学习C#,目前在UWP应用程序中使用ISupportIncrementalLoading,但似乎无法得到它的一个挂起。即使在编译之前,它也会给我带来错误。我从here得到了这个想法。但我无法理解我如何在我的应用程序中实现它。实现ISupportIncrementalLoading接口 - UWP - C#

我有一个IIncrementalLoading接口和一个单独的类,它动态地将内容添加到ObservableCollection<T>。如果我没有执行Incremental Loading我的ObservableCollection会动态地向GridView中的SearchPage.xaml提供内容,但是如果我加载更多项目,它们会替换先前生成的项目,而只会显示新项目。

守则SearchPage.xaml

<Page 
x:Class="WatchfreeWebsite.SearchPage" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="using:WatchfreeWebsite" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
xmlns:data="using:WatchfreeWebsite" 
mc:Ignorable="d"> 

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 

    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 

    <StackPanel> 
     <TextBlock Text="Search Results" 
        FontSize="20" 
        TextAlignment="Center"/> 
     <TextBlock Text="Search for Movies and TV Shows" 
        TextAlignment="Center" 
        TextWrapping="Wrap"/> 
     <HyperlinkButton x:Name="IndexPageLink" 
         Content="Go to Index" 
         HorizontalAlignment="Center" 
         Click="IndexPageLink_Click"/> 
    </StackPanel> 
    <StackPanel Grid.Row="1"> 
     <TextBox x:Name="SearchInputBox" 
       TextAlignment="Left" 
       Width="280" 
       PlaceholderText="search" 
       TextChanged="SearchInputBox_TextChanged"></TextBox> 
     <TextBlock x:Name="ErrorTextBox" 
        TextWrapping="Wrap" 
        TextAlignment="Center"/> 
    </StackPanel> 
    <GridView Grid.Row="2" 
       x:Name="SearchGrid" 
       HorizontalAlignment="Center" 
       ItemsSource="{x:Bind SearchList, Mode=OneWay}" 
       IsItemClickEnabled="True" 
       ItemClick="SearchGrid_ItemClick"> 
     <GridView.Header> 
      <StackPanel BorderBrush="Red" 
         BorderThickness="0,0,0,1" 
         Margin="5" 
         HorizontalAlignment="Center"> 
       <TextBlock Text="" 
          x:Name="SearchGridHeader" 
          TextAlignment="Center" 
          Margin="0"/> 
      </StackPanel> 
     </GridView.Header> 
     <GridView.ItemTemplate> 
      <DataTemplate x:DataType="data:SearchItems"> 
       <StackPanel BorderThickness="0,1,0,0" 
          BorderBrush="Red" 
          Margin="5"> 
        <TextBlock Text="{x:Bind SearchTitle, Mode=OneWay}" 
           TextAlignment="Center" 
           TextWrapping="Wrap" 
           Width="140" 
           Height="40"/> 
        <StackPanel BorderBrush="Red" BorderThickness="0,0,0,1" 
           Margin="0"> 
         <Image x:Name="CoverImage" 
           Source="{x:Bind SearchImageLink, Mode=OneWay}" 
           Width="130" 
           Height="200" 
           Margin="0"/> 
        </StackPanel> 
       </StackPanel> 
      </DataTemplate> 
     </GridView.ItemTemplate> 
     <GridView.Footer> 
      <HyperlinkButton x:Name="MoreItemsLink" 
          Content="Load more items" 
          Click="MoreItemsLink_Click" 
          Visibility="Collapsed"/> 
     </GridView.Footer> 
    </GridView> 
</Grid> 

守则SearchPage.xaml.cs

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.IO; 
using System.Linq; 
using System.Runtime.InteropServices.WindowsRuntime; 
using Windows.Foundation; 
using Windows.Foundation.Collections; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Controls.Primitives; 
using Windows.UI.Xaml.Data; 
using Windows.UI.Xaml.Input; 
using Windows.UI.Xaml.Media; 
using Windows.UI.Xaml.Navigation; 
using HtmlAgilityPack; 
using static WatchfreeWebsite.HtmlDocs; 



namespace WatchfreeWebsite 
{ 
public sealed partial class SearchPage : Page 
{ 
    HtmlDocument SearchDoc; 
    public static string[] SearchLinks = new string[500]; 
    public static string[] SearchTitles = new string[500]; 
    public static string[] SearchImageLinks = new string[500]; 
    public static string[] SearchNextPagesLinks = new string[50]; 

    public static int numberOfLinks = 0; 
    int numberOfTitles = 0; 
    int numberOfImages = 0; 
    int nextPage = 2; 
    int numberOfPages = 0; 
    public static int lastListItems = 0; 


    //IIncrementalSource<SearchItems> SearchList = new IncrementalLoadingCollection<GetTVShows(),SearchItems>(); 

    int listItems = 0; 
    DispatcherTimer sTimer = new DispatcherTimer(); 

    public SearchPage() 
    { 
     this.InitializeComponent(); 
     NavigationCacheMode = NavigationCacheMode.Enabled; 
    } 

    private void DeleteList(int count) 
    { 
     for (int x = 0; x < count; x++) 
     { 
      SearchList.RemoveAt(0); 
     } 
    } 

    private async void LoadHtmlDocument(string url) 
    { 
     try 
     { 
      if (NetworkInformatiom()) 
      { 
       SearchDoc = await new HtmlWeb().LoadFromWebAsync(url); 
      } 
      else 
      { 
       SearchDoc = null; 
      } 
      if (SearchDoc != null) 
      { 
       Links(SearchDoc); 
      } 
     } 
     catch (Exception ex) 
     { 
      ErrorDialog("SearchDoc_Download_Failed\n" + ex.Message); 
     } 
    } 

    private void Links(HtmlDocument doc) 
    { 
     listItems = 0; 
     try 
     { 
      foreach (var link in doc.DocumentNode.Descendants("a").Where(pl => pl.Attributes.Contains("href"))) 
      { 
       string dataValue = link.GetAttributeValue("href", ""); 
       //dataValue = ReplaceLinkStrings(dataValue); 
       if (dataValue.StartsWith("/watch") && dataValue.EndsWith(".html")) 
       { 
        SearchLinks[numberOfLinks] = MoviesPage.MoviesBaseLink + dataValue.Trim(); 
        listItems++; 
        numberOfLinks++; 
       } 
      } 
      ImageLinks(doc); 
     } 
     catch (Exception ex) 
     { 
      ErrorDialog("There was a problem while acquiring search links.\n" + ex.Message); 
     } 
    } 

    private void ImageLinks(HtmlDocument doc) 
    { 
     try 
     { 
      //int LinkID = 0; 
      foreach (var link in doc.DocumentNode.Descendants("img").Where(d => d.Attributes.Contains("src"))) 
      { 
       if (link != null) 
       { 
        if (link.Attributes["src"].Value == "/images/noposter.jpg") 
        { 
         SearchImageLinks[numberOfImages] = @"ms-appx:///Assets/noposter.jpg"; 
        } 
        else 
        { 
         SearchImageLinks[numberOfImages] = string.Format("http:{0}", link.Attributes["src"].Value); 
        } 
        numberOfImages++; 
       } 
       if (numberOfImages == numberOfLinks) 
       { 
        break; 
       } 
      } 
      Titles(doc); 
     } 
     catch (Exception ex) 
     { 
      ErrorDialog("There was a problem in Image links.\n" + ex.Message); 
     } 
    } 

    public void Titles(HtmlDocument doc) 
    { 
     try 
     { 
      //int a = 0; 
      foreach (var link in doc.DocumentNode.Descendants("a").Where(t => t.Attributes.Contains("title"))) 
      { 
       if (link != null && link.InnerText != "WatchFree.to" && link.InnerText != "Movies" && link.InnerText != "TV Shows") 
       { 
        string x = link.GetAttributeValue("title", null); 
        x = x.Replace("Watch Putlocker", ""); 
        x = x.Trim(); 
        SearchTitles[numberOfTitles] = x; 
        numberOfTitles++; 
        if (numberOfTitles == numberOfLinks) 
        { 
         break; 
        } 
       } 
      } 
      SearchList = SearchManager.GetTVShows(lastListItems, numberOfLinks); 
      // += or =  we will find out 
      this.Bindings.Update(); 
      lastListItems = numberOfLinks; 
      CheckNextPageLinks(doc); 
     } 
     catch (Exception ex) 
     { 
      ErrorDialog("There was a problem while acquiring movie titles.\n" + ex.Message); 
     } 
    } 

    private void SearchGrid_ItemClick(object sender, ItemClickEventArgs e) 
    { 
     var clickedItem = (SearchItems)e.ClickedItem; 
     if (SearchImageLinks[clickedItem.SearchID - 1] != null && clickedItem.SearchLink != null) 
     { 
      if (clickedItem.SearchLink.Contains("tv-show")) 
      { 
       string[] itemDetails = { clickedItem.SearchTitle, SearchImageLinks[(clickedItem.SearchID - 1)], clickedItem.SearchLink }; 
       Frame.Navigate(typeof(TVShowDetailsPage), itemDetails); 
      } 
      else if (clickedItem.SearchLink.Contains("movie")) 
      { 
       string[] itemDetails = { clickedItem.SearchTitle, SearchImageLinks[(clickedItem.SearchID - 1)], clickedItem.SearchLink }; 
       Frame.Navigate(typeof(MovieDetails), itemDetails); 
      } 
     } 
     else 
     { 
      ; 
     } 
    } 

    private void SearchInputBox_TextChanged(object sender, TextChangedEventArgs e) 
    { 
     string input = SearchInputBox.Text.Trim(); 
     string output = ""; 
     if (input.Length < 3) 
     { 
      SearchGridHeader.Text = ""; 
      if (SearchNextPagesLinks[0] != null || SearchLinks[0] != null || SearchImageLinks[0] != null || SearchTitles[0] != null) 
      { 
       DefaultVariablesValues(); 
      } 
      if (SearchList != null) 
      { 
       if (SearchList.Count > 0) 
       { 
        DeleteList((SearchList.Count)); 
       } 
      } 
     } 
     if (!(input.Length < 3)) 
     { 
      //sTimer = new DispatcherTimer(); 
      if (!sTimer.IsEnabled) 
      { 
       sTimer.Interval = TimeSpan.FromSeconds(1); 
       //sTimer.Start(); 
      } 

      ErrorTextBox.Text = ""; 
      SearchGridHeader.Text = "Search Results"; 
      if (input.Contains(" ")) 
      { 
       output = input.Replace(" ", "+"); 
       output = MoviesPage.MoviesBaseLink + @"/?keyword=" + output + @"&search_section=1"; 
       ErrorTextBox.Text = output; 
       ErrorTextBox.IsTextSelectionEnabled = true; 
      } 
      else 
      { 
       output = MoviesPage.MoviesBaseLink + @"/?keyword=" + input + @"&search_section=1"; 
       //ErrorTextBox.Text = output; 
      } 
      SearchList = new ObservableCollection<SearchItems>(); 
      LoadHtmlDocument(output); 

     } 
     else 
     { 
      ErrorTextBox.Text = "the length of the input should not be less than 3"; 
      if (input.Length == 0) 
      { 
       ErrorTextBox.Text = ""; 
      } 
      if (sTimer.IsEnabled) 
       sTimer.Stop(); 
     } 
    } 

    private void IndexPageLink_Click(object sender, RoutedEventArgs e) 
    { 
     Frame.Navigate(typeof(IndexPage)); 
    } 

    private void MoreItemsLink_Click(object sender, RoutedEventArgs e) 
    { 
     LoadHtmlDocument(MoviesPage.MoviesBaseLink + SearchNextPagesLinks[numberOfPages - 1]); 
    } 

    private void DefaultVariablesValues() 
    { 
     numberOfLinks = 0; 
     numberOfTitles = 0; 
     numberOfImages = 0; 
     nextPage = 2; 
     numberOfPages = 0; 
     lastListItems = 0; 
     int a = 0; 
     foreach (var item in SearchLinks) 
     { 
      if (item != null) 
      { 
       SearchLinks[a] = null; 
      } 
      a++; 
     } 
     a = 0; 
     foreach (var item in SearchTitles) 
     { 
      if (item != null) 
      { 
       SearchTitles[a] = null; 
      } 
      a++; 
     } 
     a = 0; 
     foreach (var item in SearchImageLinks) 
     { 
      if (item != null) 
      { 
       SearchImageLinks[a] = null; 
      } 
      a++; 
     } 
     a = 0; 
     foreach (var item in SearchNextPagesLinks) 
     { 
      if (item != null) 
      { 
       SearchNextPagesLinks[a] = null; 
      } 
      a++; 
     } 
    } 

    private void CheckNextPageLinks(HtmlDocument doc) 
    { 
     string lastLink = ""; 
     foreach (var link in doc.DocumentNode.Descendants("a").Where(t => t.Attributes.Contains("href"))) 
     { 
      string value = link.GetAttributeValue("href", ""); 
      if (value.StartsWith("/?keyword") && value.Contains("page=" + nextPage)) 
      { 
       SearchNextPagesLinks[numberOfPages] = value; 
       lastLink = value; 
       numberOfPages++; 
       break; 
      } 
     } 
     //-------------------------------------- 
     // checking for the availability of next page 
     if (lastLink.StartsWith(@"/?keyword") && lastLink.Contains("page=" + nextPage)) 
     { 
      MoreItemsLink.Visibility = Visibility.Visible; 
     } 
     else 
     { 
      MoreItemsLink.Visibility = Visibility.Collapsed; 
     } 
     //-------------------------------------- 
     foreach (var item in SearchNextPagesLinks) 
     { 
      if (item == lastLink) 
      { 
       nextPage++; 
      } 
     } 

    } 
} 
} 

守则IncrementalLoadingInterface

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using Windows.Foundation; 
using Windows.UI.Core; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Data; 

namespace WatchfreeWebsite 
{ 
public interface IIncrementalSource<T> 
{ 
    Task<IEnumerable<T>> GetPagedItems(int pageIndex, int pageSize); 
} 

public class IncrementalLoadingCollection<T, I> : ObservableCollection<I>, 
ISupportIncrementalLoading 
where T : IIncrementalSource<I>, new() 
{ 
    private T source; 
    private int itemsPerPage; 
    private bool hasMoreItems; 
    private int currentPage; 

    public IncrementalLoadingCollection(int itemsPerPage = 1) 
    { 
     this.source = new T(); 
     this.itemsPerPage = itemsPerPage; 
     this.hasMoreItems = true; 
    } 

    public bool HasMoreItems 
    { 
     get { return hasMoreItems; } 
    } 

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count) 
    { 
     var dispatcher = Window.Current.Dispatcher; 

     return Task.Run(
      async() => 
      { 
       uint resultCount = 0; 
       var result = await source.GetPagedItems(currentPage++, itemsPerPage); 

       if (result == null || result.Count() == 0) 
       { 
        hasMoreItems = false; 
       } 
       else 
       { 
        resultCount = (uint)result.Count(); 

        await dispatcher.RunAsync(
         CoreDispatcherPriority.Normal, 
         () => 
         { 
          foreach (I item in result) 
           this.Add(item); 
         }); 
       } 

       return new LoadMoreItemsResult() { Count = resultCount }; 

      }).AsAsyncOperation(); 
    } 
} 
} 
SearchItems(单独的类)

代码:

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using System.Threading.Tasks; 

namespace WatchfreeWebsite 
{ 
public class SearchItems 
{ 
    public int SearchID 
    { 
     get; set; 
    } 

    public string SearchTitle 
    { 
     get; set; 
    } 

    public string SearchImageLink 
    { 
     get; set; 
    } 

    public string SearchLink { get; set; } 
} 

public class SearchManager : IIncrementalSource<SearchItems> 
{ 
    private ObservableCollection<SearchItems> items; 

    public async Task<IEnumerable<SearchItems>> GetPagedItems(int pageIndex, int pageSize) 
    { 
     return await Task.Run<IEnumerable<SearchItems>>(() => 
     { 
      if (SearchPage.lastListItems == 0 && SearchPage.numberOfLinks == 0) 
      { 
       var shows = new ObservableCollection<SearchItems>(); 
       shows.Add(new SearchItems { SearchID = 1, SearchTitle = "No Search Results", SearchImageLink = @"ms-appx:///Assets/noposter.jpg" }); 
       return shows; 
      } 
      else 
      { 
       var result = GetTVShows(SearchPage.lastListItems, SearchPage.numberOfLinks); //(from p in persons select p).Skip(pageIndex * pageSize).Take(pageSize); 
       return result; 
      } 

     }); 
    } 

    public static ObservableCollection<SearchItems> GetTVShows(int start, int finish) 
    { 
     var movies = new ObservableCollection<SearchItems>(); 
     for (int x = start; x < finish; x++) 
     { 
      movies.Add(new SearchItems { SearchID = (x + 1), SearchTitle = SearchPage.SearchTitles[x], SearchImageLink = SearchPage.SearchImageLinks[x], SearchLink = SearchPage.SearchLinks[x] }); 
     } 

     //if (start == 0 && finish == 0) 
     { 
      //movies.Add(new SearchItems { SearchID = 1, SearchTitle = "No Search Results", SearchImageLink = @"ms-appx:///Assets/noposter.jpg" }); 
     } 
     return movies; 
    } 
} 

} 

说明: 实现增量装载我打电话GetTVShows()startfinish参数,以获得所需物品的数量之前首先。如果搜索没有得到任何东西,它们都是zero,所以GetTVShows()只生成一个项目No Results

但是在增量加载时,我必须在编译时指定我想要的项目数量,因为它必须搜索项目,我不能指定有多少项目将在那里,但是我获得的项目的最大数量是24个请求。

我甚至试图使用+=来我的SearchResults,但VS产生的错误,这是不适用于ObservableCollection所以我搜索互联网,并发现增量加载。但是如果可能的话,我想通过单击链接添加更多结果而不是滚动边缘。我似乎无法理解增量加载是如何工作的以及如何调用我的GetTVShows()函数来产生所需的结果。

我也记得从Twitter的这个Windows 10,因为它使用增量加载,以获得更多的DM与hyperlink点击。但是这些DM已经存储在数据库中,因此它们不会被动态添加(至少这是我的想法,我可能是错的)。

如果有人能指出我能做些什么来使它工作,那将会非常感激。任何信息,以帮助我或任何链接指向我在正确的方向,所以我可以理解如何ISupportIncrementalLoading实际工作的影响,将不胜感激。谢谢。

回答

0

我想通了我自己...

public static ObservableCollection<SearchItems> GetTVShows(int start, int finish) 
{ 
    var movies = new ObservableCollection<SearchItems>(); 
    for (int x = start; x < finish; x++) 
    { 
     movies.Add(new SearchItems { SearchID = (x + 1), SearchTitle = SearchPage.SearchTitles[x], SearchImageLink = SearchPage.SearchImageLinks[x], SearchLink = SearchPage.SearchLinks[x] }); 
    } 

    if (start == 0 && finish == 0) 
    { 
     movies.Add(new SearchItems { SearchID = 1, SearchTitle = "No Search Results", SearchImageLink = @"ms-appx:///Assets/noposter.jpg" }); 
    } 
    return movies; 
} 

我用上面的代码将项目添加到我的GridView和事实证明var movies是局部范围内,从而每一个函数被调用一次,它是空的。这就是为什么它只加载它被要求的项目。现在我在文件范围内声明它为private static,因为GetTVShows()也是一个静态函数,并且当我单击我的hyperlink按钮时,它向视图添加了更多项目。

所以在我的情况下,花在增量加载上的所有时间都被浪费了。因为我不需要边缘增量加载。

现在我的代码如下所示:

private static ObservableCollection<SearchItems> movies = new ObservableCollection<SearchItems>(); 
public static ObservableCollection<SearchItems> GetTVShows(int start, int finish) 
{ 
//var movies = new ObservableCollection<SearchItems>(); 
for (int x = start; x < finish; x++) 
{ 
    movies.Add(new SearchItems { SearchID = (x + 1), SearchTitle = SearchPage.SearchTitles[x], SearchImageLink = SearchPage.SearchImageLinks[x], SearchLink = SearchPage.SearchLinks[x] }); 
} 

if (start == 0 && finish == 0) 
{ 
    movies.Add(new SearchItems { SearchID = 1, SearchTitle = "No Search Results", SearchImageLink = @"ms-appx:///Assets/noposter.jpg" }); 
} 
return movies; 
} 

希望这可以帮助其他人前进的道路上...