頁面與ViewModel(下)

来源:http://www.cnblogs.com/ms-uap/archive/2016/06/17/5592590.html
-Advertisement-
Play Games

在上一篇博客中,筆者分享了一些從頁面整體的角度對頁面與ViewModel的思考。在本文中筆者希望從相對細節的角度分享一些對頁面與ViewModel的思考。 比如,當我們在更新View Model中的綁定數據時,應該怎樣更新呢?簡單的自然可以用新的數據實例直接替代舊的,但是這樣容易造成UI界面閃爍。尤 ...


在上一篇博客中,筆者分享了一些從頁面整體的角度對頁面與ViewModel的思考。在本文中筆者希望從相對細節的角度分享一些對頁面與ViewModel的思考。

比如,當我們在更新View Model中的綁定數據時,應該怎樣更新呢?簡單的自然可以用新的數據實例直接替代舊的,但是這樣容易造成UI界面閃爍。尤其是綁定數據是一個列表的情況下,如果整個列表被替換,可以非常明顯的看到列表"一閃"。這樣的用戶體驗無疑是不理想的。那麼我們在更新View Model中綁定的數據實例時,可以採用差異更新的方法。以一個數據列表為例,在更新時對比新舊列表,先遍歷新表,對每一個元素查看在舊表中有無對應元素。如果沒有,說明是新增的數據,可以將該新表中的元素同時加入到一個臨時表和舊表中,如果舊表有排序則還需要註意插入的位置。如果有,說明是舊元素更新,則用新元素的值更新舊元素後,將舊元素加入到臨時表中。然後遍歷舊表,對舊表中每一個元素在臨時表中查看有無對應元素。如果有,則不用做任何處理。如果沒有,則說明該元素已經被刪除,應該在舊表中將這個元素移除。這樣對UI界面的更新看起來會比較平滑。

這裡寫一下筆者在旺信UWP中所寫的差異化更新演算法,權當拋磚引玉。

            var bList = new List<bool>();//輔助列表
            for (int j = 0; j < MainList.Count; j++)//輔助列表初始與舊表同長
            {
                bList.Add(false);
            }
            for (int i = 0; i < groups.Count; i++)//遍歷新表
            {
                bool inserted = false;
                bool contains = false;
                for (int j = 0; j < MainList.Count; j++)//新表中的元素與舊表對比
                {
                    if (groups[i].key != MainList[j].key)//如果不是同一元素
                    {
                        if ((groups[i].key == "群主")//嘗試插入
                            || (
                                MainList[j].key != "群主" && MainList[j].key != "管理員"
                                && (groups[i].key == "管理員" || groups[i].key.CompareTo(MainList[j].key) < 0)
                                )
                            )
                        {
                            MainList.Insert(j, groups[i]);
                            bList.Insert(j, true);
                            inserted = true;
                            Debug.WriteLine("inserted:" + j + "," + groups[i].key);
                            break;
                        }
                    }
                    else//如果是同一元素,用新表元素內容更新舊表
                    {
                        contains = true;
                        MainList[j].update(groups[i]);
                        bList[j] = true;
                        break;
                    }
                }
                if ((!contains) && (!inserted))//不包括在舊表內,也沒有插入,則追加在舊表尾部
                {
                    MainList.Add(groups[i]);
                    bList.Add(true);
                }
            }
            for (int i = bList.Count; i > 0; i--)//對比輔助列表,移除舊表中不應再存在的元素
            {
                if (!bList[i-1])
                {
                    try
                    {
                        MainList.RemoveAt(i - 1);
                    }
                    catch (Exception)
                    {
                        Debug.WriteLine("RemoveAt error:" + i);
                    }
                }
            }

在這段代碼中,用新的數據groups更新舊的數據MainList

再比如,在我們的頁面上,我們一般都會放置一個表示正在載入數據的控制項。這個載入中控制項的狀態一般也是綁定一個後臺數據的。對於一般的頁面,我們可以採取在載入數據前後設置該綁定值的方法來修改頁面所顯示的載入狀態。而對於UWP旺信這種依賴網路,一個頁面可能同時調用多個網路介面更新數據的情況,就不是非常合適了。比如a,b兩個介面同時請求數據,將載入狀態置為載入中。如果a介面先返回,則會將載入狀態置為完成。而實際上b介面仍然在請求數據,正確的載入狀態應該還是載入中,直到b介面也返回。為此筆者想到了可以增加一個初始值為0的計數變數,當有載入請求時就自增1,當請求非同步結束或回調返回時就自減1,綁定的載入狀態的get方法根據當計數是否為0返回是否在載入狀態。這樣一來就可以使多個載入請求都能正確的改變載入狀態。

在旺信UWP中,筆者就為ViewModel添加了這樣的變數:

 

        public bool isLoading
        {
            get { return loadingCount > 0; }
        }

        private int _loadingCount = 0;

        public int loadingCount
        {
            get { return _loadingCount; }
            set { _loadingCount = (value < 0 ? 0 : value); RaisePropertyChanged("isLoading"); }
        }

在xaml頁面上則將ProgressRing控制項的IsActive屬性綁定到isLoading變數上:

<ProgressRing Grid.Row="2" Grid.RowSpan="2" IsActive="{x:Bind thisData.isLoading,Mode=OneWay}" Width="60" Height="60" Foreground="{ThemeResource WXThemeColorBrush}"></ProgressRing>

在調用非同步方法前後,並不直接設置isLoading變數,而是採取上面提到的,調用前loadingCount變數自增1,完成後loadingCount變數自減1的方法來影響ProgressRing控制項所顯示的載入狀態IsActive。

另外,在使用x:Bind方法時,筆者發現如果把綁定image圖片控制項的source綁定到一個string,當綁定的string值為空時會在log中出現exception。即使在string值為空時把image控制項隱藏也仍然會出現。然而旺信中數據的屬性值基本都是從伺服器傳輸到客戶端的,有時確實會有一些圖片的url為空。這樣一來最好給圖片屬性值都給一個預設值。那麼預設值該如何確定呢?如果是普通的占點陣圖片,那麼可能在不該出現圖片的地方顯示。經過實踐,筆者選擇了在應用中加入一個長度為0的圖片,把該圖片的uri作為圖片屬性的預設值。當然這個方法只是消除了log中的exception,具體是否提升了應用的效率,還有待驗證。

以上就是筆者對對頁面與ViewModel的細節的思考,希望能對小伙伴們開發UWP應用有所幫助。當然也歡迎大家拍磚,提出更多更好的經驗,讓我們共同進步。


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

-Advertisement-
Play Games
更多相關文章
  • QQ群里,偶爾不時的會有人問,原來的分散式網站負載工具怎麼下載不了啦?或者不能用啦?之類的問題。 我只能說,鑒於互聯網精神,我之前把它關了。其實主要是我那個VPS商,前端時間,估計也是資金問題,泥瑪尼的打不開1個月都沒人理,最後還告訴我硬碟數據全沒了。 好在我夠善良,不然真想拿刀砍他。趁著感冒,敲敲... ...
  • 在開發ASP.NET MVC時,我們會遇上這樣的情形,需要一次性傳送多個Model從控制器Controller至視圖View。 實現很簡單,只是創建一個集合類即可。Ok,下麵先在資料庫準備一些數據,如: CREATE TABLE [dbo].[TableA] ( [A] NVARCHAR(30) N ...
  • 前言 如果你還不知道ZKEACMS,不妨先瞭解一下。 ASP.NET MVC 開源建站系統 ZKEACMS 推薦,從此網站“拼”起來 官方地址:http://www.zkea.net/zkeacms 下載地址:https://github.com/SeriaWei/ASP.NET-MVC-CMS/r ...
  • 原文: "Working with SQL Server LocalDB" 作者: "Rick Anderson" 翻譯: "魏美娟(初見)" 校對: "孟帥洋(書緣)" 、 "張碩(Apple)" 、 "許登洋(Seay)" 類負責連接資料庫並將 對象和數據記錄進行映射。 Startup.cs 文 ...
  • 前言 GPS測量儀測量的產地面積,然後提交到系統中,系統需要校驗這塊產地和其他產地是否有重疊,重疊超過10%就要提出警告這塊產地已經被XXX登記入庫了。GPS測量儀測量出來的數據是連續的經緯度坐標數據。現在的問題就轉換成求一個一系列點圍成的區域和其他區域是否存在交集。拿到這個需求我想應該很簡單,網上 ...
  • 通過批處理操作註冊表實現winform應用中Webbrowser以指定的IE版本載入網頁 參考博文:http://www.cnblogs.com/liuzhendong/archive/2012/03/21/2410107.html ...... ...
  • 按[Ctrl+Shift+F]彈出查找視窗(不統計以#號開頭、以/開頭的代碼和空行) 1、輸入 :b*[^:b#/]+.*$ 2、選擇使用正則表達式 3、查找文件類型,*.cs多種類型用分號(;)隔開 點擊查找全部(查找結果如下) ...
  • 在WPF中 控制項綁定數據源時,數據源建議採用 ObservableCollection<T>集合 ObservableCollection<T> 類:表示一個動態數據集合,在添加項、移除項或刷新整個列表時,此集合將動態提供通知。數據源發生更改時,控制項內容也自動發生相應修改。無需重新綁定。 list< ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...