看板 WindowsPhone 關於我們 聯絡資訊
(或許我真該用個Blog整理整理才對......) 基本上Binding(中文是資料繫結,但我習慣講綁定)、Converter跟LINQ一樣, 都是Win8/WP8方便到會讓你轉換平台會感到不方便甚至會讓你抓狂的「好」功能 (我會說「好」功能不是他不好用,相反的就是因為太好用了, iOS/Android完全沒提供類似功能(至少就我所知沒有)寫起來就綁手綁腳, 先不說我真的沒辦法接觸的iOS,Android的ListView怎麼綁定資料我怎麼看都看不懂) 就我的理解來說, Binding像個小助手一樣可以幫你把資料給填進控制項裡面 雖然說Binding的層面很多,不過在APP上最常用到的應該就是把資料塞進去這件事 這篇也只單純說明綁資料這件事,更多變化還是去找找專門的書籍吧 中文的話,王安邦老師出的那兩本WP8/Win8.1的書都有用一個章節在講Binding的事 如果還是有點搞不清楚的話,想想看Word的合併列印功能吧 這個功能會幫你把你文件中的欄位自動填上資料庫中的對應資料 Binding的概念至少就我而言是就很類似這個。 基本上Binding是要搭配XAML,而這個就我所知並不是WP8/Win8才開始 大概是WPF/Silverlight的時代就有了 好,這邊不講古,總之開始來講講Binding要怎麼做 簡單說就是在XAML的一個屬性裡面填上 {Binding Path=(屬性名稱)},或者更簡單的{Binding (屬性名稱)} 如果更簡單是Binding整個物件的話甚至{Binding}就夠了 OK,完了,就這麼簡單 當然真的寫這樣就結束的話也未免簡單過頭了 基本上寫上去之後,系統不會知道你到底是要Binding甚麼給他 所以你還得搭配控制項的DataContext屬性 (ListView/GridView/ListBox/LonglistSelector可以改用ItemsSource) 比方說,我有某個網誌的RSS資訊, 也已經先轉換成以下面的物件構成的清單物件(名為RSSList)了: public class RSSItem { public string Title { get; set; } public string Link { get; set; } public string PubDate { get; set; } public string Description { get; set; } } 然後這個RSSList我定義成一個放在DataSource這個類別下的物件 DataSource這個類別底下還有個同樣宣告為DataSource類別的Instance變數 (注意,一個類別是不能當綁定物件的, 所以想要綁定DataSource這種資料庫物件又不想要每個頁面都建一個的話 (每個頁面都建一個DataSource未免也太揮霍系統資源了) 除了在App類別宣告一個DataSource變數以外, 就是在DataSource底下再建一個同樣宣告為DataSource的靜態變數, 要不然就勤奮一點,每個頁面的OnNavigateTo/LoadState事件中都用程式碼綁定吧) Binding的時候首先在Page/PhoneApplicationPage的DataContext屬性中 宣告綁定的是DataSource.Instance這個變數 這邊我是習慣用程式碼來寫,也就是在建構式裡面填上: this.DataContext = DataSource.Instance; 之後系統會知道「這個頁面的動態內容是來自於DataSource.Instance這個變數」 所以一旦看到動態的{Binding XXX}之類的,就會直接到Instance裡面去尋找 要注意的是如果你在一個子物件又設定了DataContext/ItemsSource 系統會認定這個物件還有其子物件的動態內容都是這個新設定的DataContext 也就是說,即使我在頁面設定綁定的來源是DataSource.Instance 如果我在子物件的ListView設定ItemsSource為{Binding RSSList}的話 系統在綁定這個ListView的時候會自動從DataSource.Instance.RSSList撈資料 而不會再去傻傻地在DataSource.Instance找資料了 ListView這種清單控制項裡面, 可以選擇用DataTemplate來告訴系統這些綁定物件要用甚麼呈現方式 格式基本上是這樣(用其他的清單控制項的話請自動將ListView換成別的控制項) <ListView> <ListView.ItemTemplate> <DataTemplate> <StackPanel> <Textblock Text="{Binding Title}"/> <Textblock Text="{Binding Description} TextWrapping="Wrap"/> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> DataTemplate裡面只能有一個控制項,所以需要多個控制項的時候 請用StackPanel/Grid包起來,不然系統會報錯 如果把DataTemplate設定在App.xaml裡面作為Resource使用也可以(記得要設定x:key屬性) 實際執行的時候,DataTemplate裡面的綁定就會由系統判斷要幫你填上甚麼 所以很簡簡單單就能夠自動呈現出一票你想要的清單內容了 如果是數字的話,系統會怎麼辦呢? 答案是系統會自動把數字直接轉成字串,所以顯示上也不會有問題 總之不是太難搞的轉換的話系統都會自動幫你處理 甚至於你也可以直接在Image之類的圖像元件中, 用Source="{Binding ImageUrl}"之類指定一個文字URL 實際運作的時候系統也真的會自動幫你載入圖片喔,很方便吧 不過,如果屬性之類的名稱打錯了會怎樣呢? 真的碰到那種情況的話,系統只會在輸出視窗跑一票資訊給你 然後那個欄位一片空白,就這樣,例外狀況會先被綁定專用的方法給吃掉 所以不會發生閃退現象,不過真的發生這種事的時候還是回來檢查一下有沒有打錯比較好 ------------------------------------------------------------- 不過有的時候,為了效果或者是明瞭總會想要自訂轉換的方式 在這點上就輪到Converter登場了 (如果不這樣子的話就要用一大堆程式碼或者甚至要在Model建立Brush物件, 果然還是會有種「這樣絕對很奇怪啊」的感覺呢) 比方說以我的空氣品質APP而言,會想要呈現狀態的顏色 但是環保署給的資料自然不會給空氣品質的顏色是什麼 一般而言,綠色代表良好、黃色代表普通、紅色代表不良 (後面還有非常不良與有害這兩個,我是看維基的條目決定用紫色和咖啡色) 這個時候就可以使用Converter來透過讀取狀態的字串去轉成背景顏色 首先新增一個類別檔(建在哪都行,這邊是建在Common資料夾下) 接下來在命名空間那邊加上兩段 using System.Windows.Data; using System.Windows.Media; 其中System.Windows.Data是Converter使用的命名空間 System.Windows.Media則是SolidColorBrush這類筆刷類型所在的命名空間 所以如果是轉成其他的目標類型,可以換成別的。 (如果是Win8/Win8.1/WP8.1則是改成下面這個樣子: using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Media; 當然Windows.UI.Xaml.Media可以替換成你轉換目標的物件所在命名空間) 接下來在類別的第一行(class XXX)後面加上「 : IValueConverter」 然後在這個IValueConverter(沒有出錯的話這個字會變成淺綠色)上面按右鍵 選擇「實作介面>實作介面」 系統就會自動在類別裡面建立Convert和ConvertBack這兩個方法 Convert是把來源轉換為目標的方法,ConvertBack則是反過來 一般而言做這種綁定轉換的時候通常不會再反過來轉回去 所以我們只要去改Convert方法就好,ConvertBack就擺著不要改 可以看到Convert回傳的是object類型的物件, 也就是說我們只要轉換好之後就可以直接回傳不用去管轉換型別的問題 那麼首先要做的就是把「throw new NotImplementedException();」這一行刪掉 (這一行是向系統說明雖然繼承了這個方法但我們沒有實作, 綁定系統碰到這類錯誤的時候就會像我剛才說的把錯誤吃掉,留下一片空白給你) 接下來要關注的就只有value這個同樣是object類型的參數 它代表的是傳進方法內的轉換值 以我現在要做的這個轉換空氣品質狀態的Converter而言 Value就只有良好、普通、不良、非常不良、有害五種可能性 (但是不排除會有變化所以回傳時要記得回傳一個以上皆非的狀態不然系統會報錯) 程式碼如下填進去 string Status = (string)value; if (Status == "良好") { return new SolidColorBrush(Colors.Green); } if (Status == "普通") { return new SolidColorBrush(Colors.Yellow); } if (Status == "不良") { return new SolidColorBrush(Colors.Red); } if (Status == "非常不良") { return new SolidColorBrush(Colors.Purple); } if (Status == "有害") { return new SolidColorBrush(Colors.Brown); } return new SolidColorBrush(Colors.Gray); 紅色的字是轉換來源物件(你要判斷字串的話總要先把傳進來的object物件轉成字串) 淺藍色的字則是回傳結果 可以看到轉換程式碼非常簡單 如果要在Binding裡面使用Converter的話, 要先做的是將Converter變成一個可用的Resource WP8和Win8/Win8.1/WP8.1的Namespace寫法有點不同 如果是在WP8的話,要寫成: <common:StatusBrushConverter xmlns:common="clr-namespace:(專案命名空間).Common" x:Key="ConverterStatusBrush"/> 在Win8/Win8.1/WP8.1的話,則是寫成: <common:StatusBrushConverter xmlns:common="using:(專案命名空間).Common" x:Key="ConverterStatusBrush"/> 且都是放在App.xaml的<Application.Resources>標籤內 定義好後,我們就有一個稱為ConverterStatusBrush的標籤可以用 接著可以在像是Border之類可以指定Background屬性, 或Textblock可指定Foreground屬性的控制項中 設定屬性為「{Binding Status,Converter={StaticResources ConverterStatusBrush}}」 系統就會自動去找該物件中Status這個屬性, 然後用ConverterStatusBrush這個Converter去將屬性中的內容轉換為筆刷物件 再將這個筆刷物件指定給這個屬性 這樣就大功告成了! ---------------------------------------------------------------- 以上只是班門弄斧一番,Binding能搞的事情就微軟的文件看來真的不少 雖然說用程式碼硬幹也沒問題, 不過我想Win8/WP8會有這類的綁定API,應該是屬於所謂的MVVM框架下的產物吧 這點我就不太清楚了就是。 總之善用Binding和Converter的話,程式碼真的會變得很好讀 然後正如我之前說LINQ的時候一樣,這東西有個超大的缺點 就是你會因為太方便而變懶,然後轉換到其他平台的時候整個綁手綁腳 (比方說JavaScript就沒有這種東西......) -- 如果將字母A到Z分別編上1到26的分數(A=1,B=2...,Z=26) 你的知識(KNOWLEDGE)得到96分(11+14+15+23+12+5+4+7+5=96) 你的努力(HARDWORK)也只得到98分(8+1+18+4+23+15+18+11=98) 你的態度(ATTITUDE)才是左右你生命的全部(1+20+20+9+20+21+4+5=100) 但是得了火山矽肺病(PNEUMONOULTRAMICROSCOPICSILICOVOLCANOCONIOSIS)就有560分喔 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.250.109.234 ※ 文章網址: http://www.ptt.cc/bbs/WindowsPhone/M.1397094299.A.4F7.html
felaray:我也在想架個blog整理文章 現在用pixnet實在不好寫.. 04/10 10:09
felaray:這幾篇怎麼都在教人變懶啦 XDDD 04/10 10:09
eterbless:科技來自於惰性(無誤 04/10 10:25
TsaoCCFGOGO:請問felaray前輩,有推薦 WP8 app 開發的書嗎? 04/10 12:23
hungys:Converter超級好用 04/10 12:57
felaray:我不是前輩..問這篇的大大還有樓上的大大吧XD 04/10 13:24
felaray:WP8的中文書比7還少 不如看MSDN或是線上資源 ~~ 04/10 13:25
felaray:曾經遇到一個問題 翻手上所有的書還沒解法.. 04/10 13:27
TsaoCCFGOGO:沒有MSDN ~_~ 04/10 21:31
F版主說的MSDN指的是微軟的線上查詢網頁 https://dev.windowsphone.com/en-us/develop ↑Windows Phone http://msdn.microsoft.com/zh-tw/windows/apps/br229519 ↑Windows 8/Windows 8.1 (或許以後還會包含Windows Phone 8.1) 不過還是得說使用查詢功能要注意,因為可能會找到舊版的資料 注意看一下裡面提到的方法或屬性前面有沒有一個綠色手提袋圖示 沒有的話那代表Win8/Win8.1/WP8.1不能用 ※ 編輯: hoyunxian (111.250.100.166), 04/11/2014 09:59:03
TsaoCCFGOGO:好的,若有好書我會跟大家分享,謝謝 04/11 15:16
shaaxu:當初專題就有用到這兩個,真的超好用XD 04/12 17:34
※ 編輯: hoyunxian (59.115.103.228), 06/17/2014 10:20:30