Toolkit里的AutoCompletedBox默认的功能已经很强大了,做一个英文城市或者英文单词的提示,可以直接指定FilterMode为AutoCompleteFilterMode.SartsWith(或者其它更合适的过滤器)。
对于自带的FilterMode,请参见MSDN:http://msdn.microsoft.com/zh-cn/library/system.windows.controls.autocompletefiltermode(VS.95).aspx
但是对于中文城市名称过滤来说,恐怕还需要进一步修改。原因如下,由于我们的用户使用的输入可能是中文键盘,举一个很简单的例子来说:用户想找“北京”的时候,他输入[beijing,bei,b,北]都是需要提示的,注意,最后那个是中文,这个时候,就需要亲手来写一些代码啦。
先上个效果图:
首先是Model类
public class CityModel:BaseModel { private string _cityName = ""; private string _pinyin = ""; public string CityName { get { return _cityName; } set { _cityName = value; OnNotifyPropertyChanged("CityName"); } } public string Pinyin { get { return _pinyin; } set { _pinyin = value; } } }
Model类很简单,就2个属性,CityName为中文名称,Pinyin(嗯,确实是拼音……)为城市的拼音名。
为了实现上图中Items的显示效果,我们需要对其模版进行修改,具体XAML如下:
<phone:PhoneApplicationPage.Resources> <DataTemplate x:Key="AutoItemTemplate"> <Grid Width="400" Height="50"> <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding CityName}" d:LayoutOverrides="Height"/> <TextBlock HorizontalAlignment="Left" Margin="200,0,57,8" TextWrapping="Wrap" Text="{Binding Pinyin}" d:LayoutOverrides="Height"/> </Grid> </DataTemplate> </phone:PhoneApplicationPage.Resources> <toolkit:AutoCompleteBox x:Name="TxtUserInput" Margin="0,8,0,0" ItemTemplate="{StaticResource AutoItemTemplate}" ValueMemberPath="CityName" Height="73" VerticalAlignment="Top" />
上面的XAML代码中唯一需要说明的就是AutoCompleteBox的ValueMemberPath属性,由于Item的数据源是CityModel类型的,如上图,这时如果用户点击“北京 beijing”这个项目时,在文本框中是显示"北京"或者"beijing"就取决于ValueMemberPath的设置了。
在XAML的CS页面里,需要进一步指定AutoCompleteBox的数据源(抱歉没有严格使用MVVM绑定,这不是重点。。)
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) { viewModel = new InputCityNameViewModel(); this.DataContext = viewModel; TxtUserInput.ItemsSource = viewModel.ListCities; TxtUserInput.FilterMode = AutoCompleteFilterMode.Custom; TxtUserInput.ItemFilter = viewModel.Filter; TxtUserInput.Focus(); }ViewModel里的一些内容:
public class InputCityNameViewModel : BaseViewModel { public IList<CityModel> ListCities = new List<CityModel>(); public InputCityNameViewModel() { LoadCities(); } private void LoadCities() { //读取城市信息 } public bool Filter(string strInput, object toFilter) { CityModel model = (CityModel)toFilter; if (model.Pinyin.StartsWith(strInput) || model.CityName.StartsWith(strInput)) return true; else { return false; } } }
这里的关键就是Filter了,代码很简单,很容易看懂。
顺便再谈一个Bug的问题,AutoCompleteBox在Pivot里面的提示显示是不正常的,而且显示和触控是错位的,网上有大牛给出了变相的解决办法,但我一直认为那太复杂,个人比较懒。。前两天Bing了一下,突然眼前一亮,截图纪念一下:
粗略看了摘要之后(确实是粗略,因为中间有”…”我也没太注意),我当时以为随着Toolkit的新版的发布,这个问题已经解决了,但是点击进去一看,发现“Toolkit新版发布”和“AutoCompleteBox在Pivot的Bug的解决”这完全是两篇不同的文章…… 彻底崩溃。。
但是必须要在Pivot里面让用户输入城市名字的,这个怎么办。后来直接用了个笨点的办法,我把Pivot里面的AutoCompleteBox换成了TextBox,然后当Text获得焦点之后,跳转到一个新页面,空白页面上只有AutoCompleteBox,当用户输入完成之后再把值传递回去,算是个障眼法么。。不过我记得有很多时候在手机上都是这么做的——当用户点击输入框之后屏幕上只显示输入框和键盘及候选字,输入完之后再返回去。这样用户体验也不会太差,总比在Pivot上面硬生生的让用户直面Bug来得好,这也算是一个临时的解决办法吧,期待Toolkit的升级~