最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ListView用法中與滾動(dòng)相關(guān)的需求實(shí)現(xiàn)

 更新時(shí)間:2017年06月22日 14:32:43   作者:WPInfo  
這篇文章主要介紹了ListView用法中與滾動(dòng)相關(guān)的需求實(shí)現(xiàn),獲取并設(shè)置ListView的滾動(dòng)位置,以及獲取滾動(dòng)位置處的項(xiàng)目,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

在 App 的開發(fā)過(guò)程中,ListView 控件是比較常用的控件之一。掌握它的用法,能幫助我們?cè)谝欢ǔ潭壬咸岣唛_發(fā)效率。本文將會(huì)介紹 ListView 的一種用法——獲取并設(shè)置ListView的滾動(dòng)位置,以及獲取滾動(dòng)位置處的項(xiàng)目。這里多說(shuō)一句,由于這個(gè)描述有點(diǎn),所以本文的標(biāo)題實(shí)在不好起。

舉個(gè)例子,如果你正在開發(fā)的應(yīng)用有這樣一個(gè)需求,當(dāng)用戶從一個(gè)列表頁(yè)(包括 ListView 控件)返回到前一頁(yè)面時(shí),你需要得到用戶在瀏覽 ListView 中的內(nèi)容到哪個(gè)位置以及哪一項(xiàng)了,以便告訴用戶最近瀏覽項(xiàng),并且可以讓用戶再次打開列表時(shí),直接從上次瀏覽的位置處繼續(xù)瀏覽。如下圖:

本文介紹了實(shí)現(xiàn)上述需求的方法。具體來(lái)說(shuō),這個(gè)需求可細(xì)分為兩個(gè)小需求,即:

  • 獲取、設(shè)置 ListView 的滾動(dòng)位置;
  • 獲取 ListView 滾動(dòng)位置處的項(xiàng)目。

以下我會(huì)通過(guò)上面配圖中的 Demo 應(yīng)用逐一說(shuō)明(本文末尾有源碼下載鏈接),這個(gè) Demo 包括兩個(gè)頁(yè)面,一個(gè)主頁(yè) (MainPage),一個(gè)列表頁(yè) (ItemsPage)。主頁(yè)中包括:

按鈕:可以導(dǎo)航到 ItemsPage;
最近瀏覽信息區(qū)域:可以查看上次瀏覽的項(xiàng)目,并提供一個(gè)按鈕可以導(dǎo)航到列表頁(yè)中上次瀏覽的項(xiàng)目處;

而列表頁(yè),則包括一個(gè) ListView 控件,展示若干個(gè)項(xiàng)目。

一、獲取、設(shè)置 ListView 的滾動(dòng)位置

關(guān)于獲取、設(shè)置 ListView 的滾動(dòng)位置,微軟已經(jīng)提供了相關(guān)的例子,我在這個(gè) Demo 中是直接套用的。這個(gè)功能主要是通過(guò) ListViewPersistenceHelper 來(lái)實(shí)現(xiàn)的,它提供以下兩個(gè)方法:

//獲取 ListView 的滾動(dòng)位置
public static string GetRelativeScrollPosition(ListViewBase listViewBase, ListViewItemToKeyHandler itemToKeyHandler)

// 設(shè)置 ListView 的滾動(dòng)位置
public static IAsyncAction SetRelativeScrollPositionAsync(ListViewBase listViewBase, String relativeScrollPosition, ListViewKeyToItemHandler keyToItemHandler)

這兩個(gè)方法中各有一個(gè)參考是委托類型,分別是ListViewItemToKeyHandler ListViewKeyToItemHandler,它們的作用是告訴這個(gè)類如何處理列表項(xiàng)與 Key 的對(duì)應(yīng)關(guān)系,好使得該類可以正確地獲取或設(shè)置滾動(dòng)位置。這里的 Key 是 ListViewItem 所代表的項(xiàng)目的一個(gè)屬性(比如 Demo 中 Item 類的 Id 屬性),這個(gè)屬性的值在整個(gè)列表中是唯一的;而 Item 是在 Item 對(duì)象本身。在 Demo 中它們的實(shí)現(xiàn)分別如下:

 private string ItemToKeyHandler(object item)
  {
   Item dataItem = item as Item;
   if (dataItem == null) return null;

   return dataItem.Id.ToString();
  }

  private IAsyncOperation<object> KeyToItemHandler(string key)
  {
   Func<System.Threading.CancellationToken, Task<object>> taskProvider = token =>
   {
    var items = listView.ItemsSource as List<Item>;
    if (items != null)
    {
     var targetItem = items.FirstOrDefault(m => m.Id == int.Parse(key));
     return Task.FromResult((object)targetItem);
    }
    else
    {
     return Task.FromResult((object)null);
    }
   };
   return AsyncInfo.Run(taskProvider);
  }

實(shí)現(xiàn)這兩個(gè)方法后,重載列表頁(yè)的  OnNavigatingFrom 方法,在其中加入以下代碼,來(lái)實(shí)現(xiàn)獲取滾動(dòng)位置并保存:

string position = ListViewPersistenceHelper.GetRelativeScrollPosition(this.listView, ItemToKeyHandler);
NavigationInfoHelper.SetInfo(targetItem, position);

繼續(xù)為頁(yè)面注冊(cè) Loaded 事件,在 Loaded 事件中加入以下代碼來(lái)實(shí)現(xiàn)設(shè)置滾動(dòng)位置:

 if (navigationParameter != null)
   {
    if (NavigationInfoHelper.IsHasInfo)
    {
     await ListViewPersistenceHelper.SetRelativeScrollPositionAsync(listView, NavigationInfoHelper.LastPosition, KeyToItemHandler);
    }
   }

這里需要注意的是,設(shè)置滾動(dòng)位置的方法是異步的,所以 Loaded 方法需要加上 async 修飾符。而上述代碼中對(duì) navigationParameter 參數(shù)的判斷則是為了區(qū)別:在導(dǎo)航時(shí)是否定位到最近瀏覽的位置,具體可參考 Demo 的代碼。

二、獲取 ListView 滾動(dòng)位置處的項(xiàng)目

關(guān)于第二個(gè)需求的實(shí)現(xiàn),我們首先需要明白以下三點(diǎn):

  • ListView 的模板 (Template) 中包括 ScrollViewer,我們可以通過(guò) VisualTreeHelper 獲取到此控件;
  • ListView 提供 ContainerFromItem 方法,它使們可以通過(guò)傳遞 Item 獲取包括此 Item 的 Container,即 ListViewItem;
  • UIElement 提供 TransformToVisual 方法,可以得到某控件相對(duì)指定控件的位置轉(zhuǎn)換信息;

所以我們的思路就是:得到 ListView 控件中的 ScrollViewer,并遍歷 ListView 中所有的 Item,在遍歷過(guò)程中,得到每一項(xiàng)目的 ListViewItem,并判斷它的位置是否位于 ScrollViewer 的位置中。以下是獲取 ListView 中當(dāng)前所有可見項(xiàng)的代碼:

public static List<T> GetAllVisibleItems<T>(this ListViewBase listView)
  {
   var scrollViewer = listView.GetScrollViewer();
   if (scrollViewer == null)
   {
    return null;
   }

   List<T> targetItems = new List<T>();
   foreach (T item in listView.Items)
   {
    var itemContainer = listView.ContainerFromItem(item) as FrameworkElement;
    bool isVisible = IsVisibileToUser(itemContainer, scrollViewer, true);
    if (isVisible)
    {
     targetItems.Add(item);
    }
   }

   return targetItems;
  }

在上述代碼的 foreach 循環(huán)中的部分,正是我們前述思路的體現(xiàn)。而其中所調(diào)用的 IsVisibleToUser 方法,則是如何判斷某一 ListViewItem 是否在 ScrollViewer 中為當(dāng)前可見。其代碼如下:

/// <summary>
  /// Code from here:
  /// https://social.msdn.microsoft.com/Forums/en-US/86ccf7a1-5481-4a59-9db2-34ebc760058a/uwphow-to-get-the-first-visible-group-key-in-the-grouped-listview?forum=wpdevelop
  /// </summary>
  /// <param name="element">ListViewItem or element in ListViewItem</param>
  /// <param name="container">ScrollViewer</param>
  /// <param name="isTotallyVisible">If the element is partially visible, then include it. The default value is false</param>
  /// <returns>Get the visibility of the target element</returns>
  private static bool IsVisibileToUser(FrameworkElement element, FrameworkElement container, bool isTotallyVisible = false)
  {
   if (element == null || container == null)
    return false;

   if (element.Visibility != Visibility.Visible)
    return false;

   Rect elementBounds = element.TransformToVisual(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
   Rect containerBounds = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);

   if (!isTotallyVisible)
   {
    return (elementBounds.Top < containerBounds.Bottom && elementBounds.Bottom > containerBounds.Top);
   }
   else
   {
    return (elementBounds.Bottom < containerBounds.Bottom && elementBounds.Top > containerBounds.Top);
   }
  }

可以看出,我們是能過(guò)得到兩個(gè) Rect 值。Rect 類型的值代表一個(gè)矩形區(qū)域的位置和大小,我們對(duì)這兩個(gè)值進(jìn)行比較后,返回最終的結(jié)果。

獲取 ListViewItem 的 Rect 值: element.TransformToVisual(container) 返回的結(jié)果是 GeneralTransform 類型,這個(gè)值表明了 ListViewItem 相對(duì)于 Container(即 ScrollViewer)的位置轉(zhuǎn)換信息。GeneralTransform 類型可能我們并不太熟悉,不過(guò),從它派生出來(lái)的這些類: ScaleTransform、TranslateTransform ,我們就熟悉了,GeneralTransform 正是它們的基類。GeneralTransform 包括以下兩個(gè)重要的方法:

  • TransformPoint, 可以將得到的轉(zhuǎn)換信息計(jì)算成 Point 值,表示某控件相對(duì)于另一控件的坐標(biāo)位置
  • TransformBounds,可以將得到的轉(zhuǎn)換信息計(jì)算成 Rect 值,表示某控件相對(duì)于另一控件的坐標(biāo)位置及所占的區(qū)域。

所以,我們通過(guò) TransformBounds 方法就得到了 ListViewItem 相對(duì)于 ScrollViewer 的位置和所占區(qū)域的信息。

獲取 ScrollViewer 的 Rect 值: 直接實(shí)例化一個(gè) Rect,以 0,0 作為你左上角的坐標(biāo)位置點(diǎn), ScrollViewer 的 ActualWidth 和 ActualHeight 作為其大小。

接下來(lái),就是比較的過(guò)程:這里,我們做了一個(gè)判斷,判斷是否要求元素 (ListViewItem) 完全在 ScrollViewer 中(而非僅部分在其中)。如果要求部分顯示即可,則只要元素的 Top 小于 Container 的 Bottom 值,并且元素的 Bottom 大于 Container 的 Top;如果要求全部顯示,那么算法是:元素的 Top 大于 Container 的 Top 并且元素的 Bottom 小于 Container 的 Bottom。如果您對(duì)語(yǔ)言描述或者代碼都還不明白,也可以在紙上畫一下進(jìn)行比較。

接下來(lái),我們照著 GetAllVisbleItems 方法的思路可以實(shí)現(xiàn) GetFirstVisibleItem 方法,即獲取列表中第一個(gè)可見項(xiàng),代碼可參考 Demo 的源碼,在此不再贅述。

我們?cè)谥爸剌d的方法 OnNavigatingFrom 中加上這句代碼,即可以獲取到用戶瀏覽位置處的那一項(xiàng)。

var targetItem = this.listView.GetFirstVisibleItem<Item>();

至此,所有主要功能已經(jīng)基本完成。

結(jié)語(yǔ)

本文介紹了如何獲取和設(shè)置 ListView 的滾動(dòng)位置,以及獲取滾動(dòng)位置處的那一項(xiàng),前者主要是借助于 ListViewPersistenceHelper 來(lái)實(shí)現(xiàn),后者則是通過(guò)獲取 ListViewItem 和 ScrollViewer 的 Rect 值并進(jìn)行比較而最終實(shí)現(xiàn)的。如果您有更好的方法、不同的看見,請(qǐng)留言,共同交流。

源碼下載

參考資料:

ListView Sample
How to get the first visible group key in the grouped listview

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C#如何利用結(jié)構(gòu)體對(duì)固定格式數(shù)據(jù)進(jìn)行解析

    C#如何利用結(jié)構(gòu)體對(duì)固定格式數(shù)據(jù)進(jìn)行解析

    這篇文章主要為大家詳細(xì)介紹了C#利用結(jié)構(gòu)體對(duì)固定格式數(shù)據(jù)進(jìn)行解析,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C#中如何執(zhí)行存儲(chǔ)過(guò)程方法

    C#中如何執(zhí)行存儲(chǔ)過(guò)程方法

    C#中如何執(zhí)行存儲(chǔ)過(guò)程方法,需要的朋友可以參考一下
    2013-04-04
  • C#通過(guò)子窗體刷新父窗體的實(shí)現(xiàn)方法

    C#通過(guò)子窗體刷新父窗體的實(shí)現(xiàn)方法

    在一些軟件,比如,進(jìn)銷存管理系統(tǒng)中添加銷售單信息時(shí),每個(gè)銷售單都可能對(duì)應(yīng)多種商品,而且在向銷售單中添加商品時(shí),一般都是在新彈出的窗體中選擇商品,這時(shí)就涉及通過(guò)子窗體刷新父窗體的問(wèn)題,本文給大家介紹了C#通過(guò)子窗體刷新父窗體的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2024-04-04
  • c#并行任務(wù)多種優(yōu)化方案分享(異步委托)

    c#并行任務(wù)多種優(yōu)化方案分享(異步委托)

    c#并行任務(wù)多種優(yōu)化方案分享,使用異步委托+回調(diào)函數(shù)方式實(shí)現(xiàn),大家參考使用吧
    2013-12-12
  • 利用C#實(shí)現(xiàn)SSLSocket加密通訊的方法詳解

    利用C#實(shí)現(xiàn)SSLSocket加密通訊的方法詳解

    這篇文章主要給大家介紹了關(guān)于如何利用C#實(shí)現(xiàn)SSLSocket加密通訊的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • C#條件編譯、內(nèi)聯(lián)函數(shù)、CLS介紹

    C#條件編譯、內(nèi)聯(lián)函數(shù)、CLS介紹

    這篇文章介紹了C#的條件編譯、內(nèi)聯(lián)函數(shù)、CLS,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • C#中實(shí)體類與XML相互轉(zhuǎn)換方式

    C#中實(shí)體類與XML相互轉(zhuǎn)換方式

    這篇文章主要介紹了C#中實(shí)體類與XML相互轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • C#控制鍵盤按鍵的常用方法

    C#控制鍵盤按鍵的常用方法

    這篇文章主要介紹了C#控制鍵盤按鍵的常用方法,涉及C#針對(duì)鍵盤大寫、滾動(dòng)、數(shù)字的開啟與鎖定等功能,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下
    2015-05-05
  • C#擴(kuò)展方法實(shí)例分析

    C#擴(kuò)展方法實(shí)例分析

    這篇文章主要介紹了C#擴(kuò)展方法,結(jié)合實(shí)例形式分析了C#擴(kuò)展方法的功能、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-06-06
  • C#中英文混合字符串截取函數(shù)

    C#中英文混合字符串截取函數(shù)

    這篇文章介紹了C#中英文混合字符串截取函數(shù),有需要的朋友可以參考一下
    2013-09-09

最新評(píng)論

崇信县| 岗巴县| 通化县| 衡水市| 华坪县| 宜宾县| 乐至县| 鄂尔多斯市| 琼中| 扶风县| 茂名市| 平利县| 乐亭县| 银川市| 河东区| 沐川县| 龙井市| 武强县| 孝昌县| 灵山县| 民权县| 太康县| 泰来县| 石柱| 寿宁县| 金阳县| 台东市| 宜都市| 铁岭市| 高邮市| 龙岩市| 岳阳县| 汉中市| 河北区| 伊吾县| 巴东县| 瓦房店市| 油尖旺区| 石台县| 鄱阳县| 全椒县|