Windows 8 Metro開發疑難雜症(一)——導航

來源:互聯網
上載者:User

Win8的導航的實在是讓我有點鬱悶,尤其是像我這樣原來做過WP7開發的真的一時難以適應。

Win8導航的問題,目前一共有兩個:

  1. 如果在不啟用頁面緩衝的時候,每次返回的時候都會重新整理頁面(在WP7中頁面的所有狀態自動儲存,離開的時候什麼樣的,返回的時候還是那樣),這就導致使用者狀態需要開發人員自己去儲存。你可能會說既然這樣可以啟動頁面緩衝啊,是啊,你當然可以啟用頁面緩衝,但是一旦啟用了頁面的緩衝,你這個頁面同一時間只能有一個執行個體,這樣對於對應不同的參數顯示不同的資料的頁面來說就很困難了,因為你同一時間只有一個執行個體。
  2. 導航的時候使用者是可以傳遞object參數的,我剛看到可以傳遞object參數的時候我還以開心,覺得微軟終於把WP7的導航模型改進了下,可是當我調試掛起狀態的時候我發現我錯了,直接crash。於是我在微軟的官網論壇問了下,給我的回答是,如果傳遞的參數是複雜類型(即使你已經標記了DataContract和DataMember)那麼程式掛起的時候依然會crash,那也就是說你必須把你的複雜類型在傳遞之前序列化成字串,然後在目標頁把字串還原序列化成相應對象。我覺得微軟你這麼做有意思嗎?尼瑪你還不如用WP7導航模型啊!

 

下面針對第一個問題進行討論。首先如果你的頁面不需要根據不同的參數顯示不同的資料的,那麼完全可以啟用頁面緩衝(頁面的NavigationCacheMode設定成Enabled或者Required)。如果你的頁面需要根據不同的參數顯示不同資料,那麼作為開發人員要做的事情比起WP7的導航模型來說要多了,首先是頁面資料的儲存,其次是頁面狀態的儲存(如果有捲軸你得儲存捲軸的狀態,如果有文字框,你得儲存文字框中的文本…..)。現在拿VS2012中的內建的模版做個列子。

 

首先從項目模版中選擇Grid APP模版,建立項目以後直接運行。進入首頁,滑動捲軸,滑倒最後,然後隨便選擇一項進入該項詳細資料頁,然後返回,這時你會發現頁面回到的初始狀態,捲軸也回到了原點。現在解釋下為什麼會這樣。

首先頁面沒有啟用緩衝,那麼每次返回的時候頁面總是會重新整理,如何重新整理的?其實就是返回的時候系統重新調用InitializeComponent方法,原來所有的資料和狀態都不複存在,就像一個全新的頁面一樣(其實你應該把它當成一個全新的頁面)。

如果只能這樣的話我們肯定會抓狂,還好微軟留了兩個方法,LoadState和SaveState,其實這兩個方法是項目模版中自訂的方法。

  •  LoadState方法,當該頁面第一次載入(注意不是返回)的時候,參數pageState為null。當頁面是從前一頁返回的時候載入的,那麼參數pageState參數包含了你在SaveState方法裡儲存的資料。這時你就可以恢複頁面的資料和狀態了。
  •  SaveState方法,當從當前頁導航進入其他頁的時候,會在當前頁調用SaveSate方法,這時候你需要把頁面的資料和狀態儲存到pageState中,供LoadState的時候使用儲存的 資料

我們以GroupedItemsPage為例,首先我們需要在SaveState裡面添加一些代碼:

 protected override void SaveState(Dictionary<string, object> pageState)        {            base.SaveState(pageState);            //把DefaultViewModel中的所有資料轉移到pageState中            foreach (var item in this.DefaultViewModel)            {                pageState[item.Key] = item.Value;            }            //儲存捲軸滾動狀態,這裡只儲存HorizontalOffset            var scroll = itemGridView.GetVisualDescendants<ScrollViewer>().FirstOrDefault();            pageState["HorizontalOffset"] = scroll == null ? 0 : scroll.HorizontalOffset;        }

然後在LoadState裡面添加如下代碼:

  protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)        {            //pageState不為null,那麼表明是返回狀態,這時候需要恢複資料和狀態            if (pageState != null)            {                itemGridView.LayoutUpdated += itemGridView_LayoutUpdated;                if (pageState != null)                {                    foreach (var item in pageState)                    {                        this.DefaultViewModel[item.Key] = item.Value;                    }                }            }            else            {                // pageState為null,表明是第一次載入頁面,需要初始化資料                var sampleDataGroups = SampleDataSource.GetGroups((String)navigationParameter);                this.DefaultViewModel["Groups"] = sampleDataGroups;            }        }

後面添加itemGridView_LayoutUpdated事件的方法:

  //頁面的捲軸        ScrollViewer scroll;        void itemGridView_LayoutUpdated(object sender, object e)        {            if (scroll == null)                scroll = itemGridView.GetVisualDescendants<ScrollViewer>().FirstOrDefault();            if (scroll != null)            {                if (this.DefaultViewModel.ContainsKey("HorizontalOffset"))                {                    double d = (double)this.DefaultViewModel["HorizontalOffset"];                    scroll.ScrollToHorizontalOffset(d);                    //捲軸的狀態恢複不是一下子就恢複的,可能需要多次調用ScrollToHorizontalOffset才能準確恢複                    if (d == scroll.HorizontalOffset)                        itemGridView.LayoutUpdated -= itemGridView_LayoutUpdated;                }                else//如果DefaultViewModel中沒有HorizontalOffset資料,那麼就不需要恢複捲軸狀態了                    itemGridView.LayoutUpdated -= itemGridView_LayoutUpdated;            }        }

添加完這些代碼就可以直接運行了,這時你會發現,不管是頁面資料還是頁面狀態都能準確的恢複到上一次的狀態。

上面代碼中涉及到的GetVisualDescendants方法是一個擴充方法,具體代碼如下:

 public static class VisualTreeExtensions    {        public static IEnumerable<T> GetVisualDescendants<T>(this DependencyObject element) where T : DependencyObject        {            return element.GetVisualDescendants().OfType<T>();        }        /// <summary>        /// 擷取某個元素的所有子孫節點        /// </summary>        public static IEnumerable<DependencyObject> GetVisualDescendants(this DependencyObject element)        {            if (element == null)            {                throw new ArgumentNullException("element");            }            return GetVisualDescendantsAndSelfIterator(element).Skip(1);        }        private static IEnumerable<DependencyObject> GetVisualDescendantsAndSelfIterator(DependencyObject element)        {            Queue<DependencyObject> remaining = new Queue<DependencyObject>();            remaining.Enqueue(element);            while (remaining.Count > 0)            {                DependencyObject obj = remaining.Dequeue();                yield return obj;                foreach (DependencyObject child in obj.GetVisualChildren())                {                    remaining.Enqueue(child);                }            }        }        public static IEnumerable<DependencyObject> GetVisualChildren(this DependencyObject element)        {            if (element == null)            {                throw new ArgumentNullException("element");            }            return GetVisualChildrenAndSelfIterator(element).Skip(1);        }        private static IEnumerable<DependencyObject> GetVisualChildrenAndSelfIterator(this DependencyObject element)        {            yield return element;            int count = VisualTreeHelper.GetChildrenCount(element);            for (int i = 0; i < count; i++)            {                yield return VisualTreeHelper.GetChild(element, i);            }        }    }

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.