UWP開發入門(十)——通過繼承來擴展ListView

来源:http://www.cnblogs.com/manupstairs/archive/2016/03/25/5321390.html
-Advertisement-
Play Games

本篇之所以起這樣一個名字,是因為重點並非如何自定義控制項,不涉及創建CustomControl和UserControl使用的Template和XAML概念。而是通過繼承的方法來擴展一個現有的類,在繼承的子類中增加屬性和擴展行為。 我們在《UWP開發入門(七)——下拉刷新》中提到過嵌套ScrollVie ...


  本篇之所以起這樣一個名字,是因為重點並非如何自定義控制項,不涉及創建CustomControlUserControl使用的TemplateXAML概念。而是通過繼承的方法來擴展一個現有的類,在繼承的子類中增加屬性和擴展行為。

  我們在《UWP開發入門(七)——下拉刷新》中提到過嵌套ScrollViewer的實現思路,本篇我們對ListView的第一個擴展行為,即是摒棄嵌套的做法,而是通過訪問ListView內部的ScrollViewer控制項,來監聽ViewChanged事件。

  訪問ListView內部的ScrollViewer,必定離不開VisualTreeHelper類中的以下兩個方法:  

public static DependencyObject GetChild(DependencyObject reference, System.Int32 childIndex);

public static System.Int32 GetChildrenCount(DependencyObject reference);

  可以將這兩個方法進一步組合得到:

        static T FindFirstChild<T>(FrameworkElement element) where T : FrameworkElement
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(element);
            var children = new FrameworkElement[childrenCount];

            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;
                children[i] = child;
                if (child is T)
                    return (T)child;
            }

            for (int i = 0; i < childrenCount; i++)
                if (children[i] != null)
                {
                    var subChild = FindFirstChild<T>(children[i]);
                    if (subChild != null)
                        return subChild;
                }

            return null;
        }

  該方法通過遞歸來遍歷FrameworkElement內部的元素,並返回第一個符合類型的元素。ListViewEx第一個擴展如下:

    public class ListViewEx : ListView, INotifyPropertyChanged
    {
        private ScrollViewer _scrollViewer;

        public event EventHandler LoadHistoryEvent;
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnProperyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        public ListViewEx()
        {
            this.Loaded += ListViewEx_Loaded;
            this.Unloaded += ListViewEx_Unloaded;
        }

        private void ListViewEx_Unloaded(object sender, RoutedEventArgs e)
        {
            this.Unloaded -= ListViewEx_Unloaded;
            if (_scrollViewer != null)
            {
                _scrollViewer.ViewChanged -= Sv_ViewChanged;
            }
        }

        private void ListViewEx_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            this.Loaded -= ListViewEx_Loaded;
            _scrollViewer = FindFirstChild<ScrollViewer>(this);
            if (_scrollViewer != null)
            {
                _scrollViewer.ViewChanged += Sv_ViewChanged;
            }
        }

        private async void Sv_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
        {
            if (e.IsIntermediate == false && _scrollViewer.VerticalOffset < 1)
            {
                _scrollViewer.ChangeView(null, 50, null);
                await Task.Delay(10);
                LoadHistoryEvent?.Invoke(this, EventArgs.Empty);
            }
        }

  嗯嗯,可以看到優雅的 -= event和恰到好處的null check,啊啊!忍不住想點個贊!在ViewChanged事件監測到滾動條到達頂部後,果斷觸發ListViewEx內定義的LoadHistoryEvent來通知更新數據。

  本篇如果僅增加一個LoadHistoryEvent,又會被人非議是在補完前篇,一篇拆成兩篇寫……那好吧,我們再給ListViewEx增加第二個擴展GoBottomVisiblity屬性,顧名思義即是ListViewEx向上滾動幾屏以後,顯示一個GoBottom的按鈕。

  在ListViewEx的類中,首先定義屬性GoBottomVisibility,然後同樣是在ViewChanged事件中,計算是否顯示GoBottom按鈕。

        public Visibility GoBottomVisiblity
        {
            get { return _goBottomVisiblity; }
            set
            {
                _goBottomVisiblity = value;
                this.OnProperyChanged();
            }
        }
        private void Sv_ViewChanged2(object sender, ScrollViewerViewChangedEventArgs e)
        {
            if (e.IsIntermediate == false)
            {
                CheckGoBottomVisibility();
            }
        }

        private void CheckGoBottomVisibility()
        {
            if (_scrollViewer.VerticalOffset + _scrollViewer.ViewportHeight < _scrollViewer.ScrollableHeight)
            {
                GoBottomVisiblity = Visibility.Visible;
            }
            else
            {
                GoBottomVisiblity = Visibility.Collapsed;
            }
        }

  代碼沒法全部貼上來,一個是太長了顯得啰嗦,二是會被管理員說沒內涵從首頁刪掉……

  大體上本篇就是給ListView擴展了LoadHistoryEvent事件和GoBottomVisibility屬性。最後說說怎麼用,XAML里使用ListViewEx代替預設的ListView,會發現多出一個LoadHistoryEvent,掛上載入數據的事件就OK了。然後在列表的下部畫一個三角箭頭,Visibility綁定到ListViewExGoBottomVisibility屬性上就收工了。

  

    <Grid>
        <local:ListViewEx x:Name="listViewEx" ItemsSource="{x:Bind Items}" LoadHistoryEvent="ListViewEx_LoadHistoryEvent"></local:ListViewEx>
        <Grid Margin="10" VerticalAlignment="Bottom" HorizontalAlignment="Center" 
              Tapped="Grid_Tapped" Visibility="{x:Bind listViewEx.GoBottomVisiblity,Mode=OneWay}">
            <Ellipse Fill="LightGray" Width="30" Height="30"></Ellipse>
            <Polyline Stroke="White" Points="10,10 15,20 20,10"></Polyline>
        </Grid>
    </Grid>

  完整代碼放在GayHub上,地址:https://github.com/manupstairs/UWPSamples

  非常感謝各位捧場,能夠點開頁面看到這裡,拜謝了!Orz


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大家在用三層架構做開發的時候,是否有使用介面,使用介面的時候是否有類似這樣的代碼: 然後每個每個表都有一個這樣的介面代碼,對比之後發現,這樣的代碼是不是很多重覆呢?那麼有什麼好的辦法可以減少這樣的重覆代碼??? 我想到的是泛型,介面同樣可以泛型,看下麵這張圖,IT_admin,IT_advs,IT_ ...
  • 1.//彈出對話框.點擊轉向指定頁面 2.//彈出對話框 3.//刪除文件 4.//綁定下拉列表框datalist 5.//時間去秒顯示 6.//標題帶鏈接 7.//修改轉向 8.//彈出確定按鈕 9.//輸出數據格式化 "{0:F2}" 是格式 F2表示小數點後剩兩位 10.//提取動態網頁內容 ...
  • 請求如何進入ASP.NET MVC框架 thx@4littleProgrammer url:http://www.cnblogs.com/4littleProgrammer/p/5317058.html ...
  • 環境:VS2013+MVC5+IIS EXPRESS 問題:如果從Asp.net Web遷移到MVC,可能會遇到需要使原來的鏈接(如http://localhost:12345/old/library.html)可以繼續訪問的情況,而預設情況下,MVC對於html尾碼是不經過路由的,直接給你一個40 ...
  • 我在前面一篇隨筆《Socket開發框架之框架設計及分析》中,介紹了整個Socket開發框架的總體思路,對各個層次的基類進行了一些總結和抽象,已達到重用、簡化代碼的目的。本篇繼續分析其中重要的協議設計部分,對其中消息協議的設計,以及數據的拆包和封包進行了相關的介紹,使得我們在更高級別上更好利用Sock ...
  • 之前我喜歡只是單純的記記筆記,沒有什麼寫文章的習慣,今天也是我一邊研究一邊學習,索性就連過程什麼的都記錄下吧,或許能幫到一兩個朋友呢。 首先,我們來想想什麼叫做單例,顧名思義,單一的一個對象,那麼,單一模式有什麼好處呢?比如說,你的對象只可以實例化一次等等。 先寫一個簡單的測試里的例子吧,比如我建一 ...
  • 本系列目錄: 《1、搜索有聲小說》 《2、分析詳細頁地址》 《3、批量下載mp3》 本篇是大結局,看過前兩篇的放心吧,不會有第四篇了,軟體的下載地址,軟體完成的效果大家自己看吧。 一、查找mp3文件的下載地址 我們首先要獲取其下載地址,在評書的詳細頁中沒有找到,我們進入播放頁面,看看能找到什麼,如下 ...
  • 百度:ef5 mysql http://my.oschina.net/u/170703/blog/210814?p=1 百度:dotconnect for mysql 破解 可以找到極限軟體網站上的 dcmysql的破解版 {"創建 entityFramework 的配置節處理程式時出錯: 未能載入 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...