WPF中的轉換器是一個非常好的數據類型轉換解決方案,實用和強大, 它的作用是將源數據轉換為WPF自身需要的類型,對數據實體沒有侵略性,會在項目工程中頻繁使用。所以掌握轉換器是WPF開發的必備技能。 我剛接觸轉換器的時候,沒有考慮通用性,每次遇到一個轉換需求都會去創建一個新的轉換器,久而久之,項目中的 ...
WPF中的轉換器是一個非常好的數據類型轉換解決方案,實用和強大, 它的作用是將源數據轉換為WPF自身需要的類型,對數據實體沒有侵略性,會在項目工程中頻繁使用。所以掌握轉換器是WPF開發的必備技能。
我剛接觸轉換器的時候,沒有考慮通用性,每次遇到一個轉換需求都會去創建一個新的轉換器,久而久之,項目中的轉換器已多如牛毛
這當然是我無法容忍的,我決定用一種通用轉換器來代替絕大部分性質相同的轉換操作,通過約定一套參數規則來適應不同的轉換場景,達到轉換器復用的目的。
轉換器分為兩種,IValueConverter(單值轉換器)和IMultiValueConverter(多值轉換器)
單值通用轉換器 ObjectConverter
參數規則【比較值1|比較值2:true返回值:false返回值】
仔細一看,這個參數規則其實和三元表達式的含義相同,當源數據等於比較值1或者比較值2的時候,返回true返回值,否則返回false返回值
有了這個規則,就可以實現通用轉換需求了,ObjectConverter源碼如下
public class ObjectConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string[] parray = parameter.ToString().ToLower().Split(':'); //將參數字元分段 parray[0]為比較值,parray[1]為true返回值,parray[2]為false返回值 if (value == null) return parray[2]; //如果數據源為空,預設返回false返回值 if (parray[0].Contains("|")) //判斷有多個比較值的情況 return parray[0].Split('|').Contains(value.ToString().ToLower()) ? parray[1] : parray[2]; //多值比較 return parray[0].Equals(value.ToString().ToLower()) ? parray[1] : parray[2]; //單值比較 } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var returnValue = "otherValue"; string[] parray = parameter.ToString().ToLower().Split(':'); if (value == null) return returnValue; var valueStr = value.ToString().ToLower(); if (valueStr != parray[1]) return returnValue; else return parray[0].Contains('|') ? parray[0].Split('|')[0] : parray[0]; } }
ObjectConverter的使用
1 <converter:ObjectConverter x:Key="objConverter"/> 2 3 <Border Visibility="{Binding PanelStatus, Converter={StaticResource objConverter},ConverterParameter=true:Visible:Collapsed}"> 4 5 <Border Background="{Binding BgColor, Converter={StaticResource objConverter},ConverterParameter=1:Red:Blue}"> 6 7 <TextBlock Text="{Binding Type, Converter={StaticResource objConverter},ConverterParameter=1|2:VIP會員:普通會員}"/>
多值通用轉換器 MultiObjectConverter
參數規則【各組比較值:比較條件(&或|):true返回值:false返回值:返回值類型枚舉】
多值轉換器的參數規則略顯麻煩,但是也和三元表達式類似,只不過多了比較條件和返回值枚舉類型,這裡有人要問了為什麼單值轉換器不需要聲明返回值枚舉而多值轉換器需要,這是因為多值轉換器的返回值不返回實際類型的話,返回類型會失效,WPF的預設轉換器似乎沒有起到作用。這個問題我也正在研究,所以先定義一個返回值枚舉用來轉換返回值的類型。姑且算一個臨時解決方案吧
1 public class MultiObjectConverter : IMultiValueConverter 2 { 3 /// <summary> 4 /// 多值轉換器 5 /// </summary> 6 /// <param name="values">參數值數組</param> 7 /// <param name="parameter"> 8 /// <para>參數</para> 9 /// <para>各組比較值:比較條件(&或|):true返回值:false返回值:返回值類型枚舉</para> 10 /// <para>v1;v2-1|v2-2;v3:&:Visible:Collapsed:1</para> 11 /// </param> 12 /// <returns></returns> 13 public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 14 { 15 string[] param = parameter.ToString().ToLower().Split(':'); //將參數字元串分段 16 string[] compareValues = param[0].Split(';'); //將比較值段分割為數組 17 if (values.Length != compareValues.Length) //比較源數據和比較參數個數是否一致 18 return ConvertValue(param[3], param[4]); 19 var trueCount = 0; //滿足條件的結果數量 20 var currentValue = string.Empty; 21 IList<string> currentParamArray = null; 22 for (var i = 0; i < values.Length; i++) 23 { 24 currentValue = values[i] != null ? values[i].ToString().ToLower() : string.Empty; 25 if (compareValues[i].Contains("|")) 26 { 27 //當前比較值段包含多個比較值 28 currentParamArray = compareValues[i].Split('|'); 29 trueCount += currentParamArray.Contains(currentValue) ? 1 : 0; //滿足條件,結果+1 30 } 31 else 32 { 33 trueCount += compareValues[i].Equals(currentValue) ? 1 : 0; //滿足條件,結果+1 34 } 35 } 36 currentParamArray = null; 37 currentValue = string.Empty; 38 var compareResult = param[1].Equals("&") ? 39 trueCount == values.Length : 40 trueCount > 0; //判斷比較結果 41 return ConvertValue(compareResult ? param[2] : param[3], param[4]); 42 } 43 44 public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 45 { 46 throw new NotImplementedException(); 47 } 48 49 private object ConvertValue(string result, string enumStr) 50 { 51 var convertResult = (ConvertResult)int.Parse(enumStr); 52 if (convertResult == ConvertResult.顯示類型) 53 return result.Equals("collapsed") ? Visibility.Collapsed : Visibility.Visible; 54 if (convertResult == ConvertResult.布爾類型) 55 return System.Convert.ToBoolean(result); 56 return null; //後續自行擴展 57 } 58 59 private enum ConvertResult 60 { 61 顯示類型 = 1, 62 布爾類型 = 2, 63 字元串類型 = 3, 64 整型 = 4, 65 小數型 = 5, 66 畫刷類型 = 6, 67 樣式類型 = 7, 68 模板類型 = 8 69 } 70 }
MulitObjectConverter的使用
1 <TextBlock Text="test"> 2 <TextBlock.Visibility> 3 <MultiBinding Converter="{StaticResource mobjConverter}" 4 ConverterParameter="1|2;true:|:Visible:Collapsed:1"> 5 <Binding Path="Filed1"/> 6 <Binding Path="Filed2"/> 7 </MultiBinding> 8 </TextBlock.Visibility> 9 </TextBlock>
單值通用轉換器和多值通用轉換器已經講完了,讀者可以根據自己的需求定製ConverterParameter的規則,實現靈活擴展。歡迎入群交流372754241