Windows Phone开发手记-WinRT下分组拼音的实现

栏目: 前端 · 发布时间: 6年前

内容简介:Windows Phone开发手记-WinRT下分组拼音的实现

Windows Phone版本号自升入8.1以来,开发者就多了一个选项,开发基于WinRT架构的WP或者Universal Windows App。然而开发框架转为WinRT后,很多原有的WP8基于Sliverlight框架的控件和方法变得不再有效,这无疑带来较大的困扰。今天我要讲述的就是此类问题中较易出现的列表拼音分组方案,本文基于WinRT架构予以实现,下面附上实现效果图:

Windows Phone开发手记-WinRT下分组拼音的实现

Windows Phone开发手记-WinRT下分组拼音的实现

解决方案:

在WP8下,Silverlight提供了LongListSelector控件,可以方便的实现以上的拼音分组效果,具体实现方法可以参考以下博文:

http://diaosbook.com/Post/2014/2/22/longlistselector-group-by-py-wp8

但是WP8.1则不然,WinRT框架默认不提供分组控件,唯一的解决办法是我们使用相关控件自己来实现。我讲此方案归纳为 SemanticZoom+ListView+GridView+ValueConverter=LongListSelector ,不得不说,这样实现的复杂度远大于Silverlight框架,但其自定义程度高的优势也很明显。

1.数据分组

我们要在正常列表视图下展示分组的列表,这需要我们提前做好数据的分组,对于这一点,官方提供了多种方案,最简单的就是给List中每一项都提供Key属性,这样处理起来最简单,但却十分麻烦,需要我们在数据源里提前设计好Key属性,所以这里我并不会讲述这种分组方法。

我要讲述的是通用程度较高的分组方案,不需要在数据源中设计好Key属性,而是按照正常的方式使用数据源,但是我们会对数据源进行分组处理,最后讲分组后的数据绑定到ListView控件,当然,我们的分组处理行为都是在后台自动处理的。

首先为了ListView控件能够展示分组数据,需要将它的Itemssource绑定到CollectionViewSource数据源,CollectionViewSource数据源IsGrouped属性必须设置为True,Source属性绑定到我们提供的分组数据。

<vm:MainPage_Model x:Name="MainVM" x:Key="DesignVM"/>
<CollectionViewSource x:Name="GroupData" x:Key="GroupData" IsSourceGrouped="True"  Source="{Binding StartCityGroup, Source={StaticResource DesignVM}}"/>

后台处理:

I. 这里我们创建一个辅助类,参考MSDN的文章方案,我进行了修改适应,实现如下:

//将输入的数据源进行拼音分组,返回CollectionViewSource可以接受的数据结构
public class AlphaKeyGroup<T>:List<T> { const string GlobeGroupKey = "?"; public string Key { get; private set; } //public List<T> this { get; private set; } public AlphaKeyGroup(string key) { Key = key; } private static List<AlphaKeyGroup<T>> CreateDefaultGroups(CharacterGroupings slg) { List<AlphaKeyGroup<T>> list = new List<AlphaKeyGroup<T>>(); foreach (CharacterGrouping cg in slg) { if (cg.Label == "") continue; else if (cg.Label == "...") { list.Add(new AlphaKeyGroup<T>(GlobeGroupKey)); } else list.Add(new AlphaKeyGroup<T>(cg.Label)); } return list; } public static List<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, Func<T, string> keySelector, bool sort) { CharacterGroupings slg = new CharacterGroupings(); List<AlphaKeyGroup<T>> list = CreateDefaultGroups(slg); foreach (T item in items) { int index = 0; string label = slg.Lookup(keySelector(item)); index = list.FindIndex(alphagroupkey => (alphagroupkey.Key.Equals(label, StringComparison.CurrentCulture))); if (index > -1 && index < list.Count) list[index].Add(item); } if (sort) { foreach (AlphaKeyGroup<T> group in list) { group.Sort((c0, c1) => { return keySelector(c0).CompareTo(keySelector(c1)); }); } } return list; } }

II. 添加可用于绑定到CollectionViewSource的List<AlphaKeyGroup<City>>属性,这里的City是自定义数据模型,如下:

//这里的代码是MVVM-Sidekick框架自动生成的,主要就是第一行的定义代码
public List<AlphaKeyGroup<City>> StartCityGroup { get { return _StartCityGroupLocator(this).Value; } set { _StartCityGroupLocator(this).SetValueAndTryNotify(value); } } #region Property List<AlphaKeyGroup<City>> StartCityGroup Setup protected Property<List<AlphaKeyGroup<City>>> _StartCityGroup = new Property<List<AlphaKeyGroup<City>>> { LocatorFunc = _StartCityGroupLocator }; static Func<BindableBase, ValueContainer<List<AlphaKeyGroup<City>>>> _StartCityGroupLocator = RegisterContainerLocator<List<AlphaKeyGroup<City>>>("StartCityGroup", model => model.Initialize("StartCityGroup", ref model._StartCityGroup, ref _StartCityGroupLocator, _StartCityGroupDefaultValueFactory)); static Func<BindableBase, List<AlphaKeyGroup<City>>> _StartCityGroupDefaultValueFactory = model => { var vm = CastToCurrentType(model); //TODO: Add the logic that produce default value from vm current status. return default(List<AlphaKeyGroup<City>>); }; #endregion

III. 给StartCityGrup赋予数据,这里就用到我们的辅助类了,实现如下:

//StartCity是List<City>类型的源数据集合
StartCityGroup = AlphaKeyGroup<City>.CreateGroups(StartCity, (City s) => { return s.Name; }, true);

这里因为我们要根据城市名称拼音分组,所以使用了对应的Name属性。

2.绑定视图

还需要设置ListView分组标头,设置GrupStyle,如下:

<ListView Margin="15,10" x:Name="StartCityList" ItemsSource="{Binding Source={StaticResource GroupData}}"  Foreground="Black" Background="White" SelectionChanged="StartCityList_SelectionChanged" >
						<ListView.GroupStyle>
							<GroupStyle HidesIfEmpty="True">
								<GroupStyle.HeaderTemplate>
									<DataTemplate>
										<Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62" Height="62" Margin="0,0,18,0" HorizontalAlignment="Stretch">
											<TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6" FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
										</Border>
									</DataTemplate>
								</GroupStyle.HeaderTemplate>
							</GroupStyle>
						</ListView.GroupStyle>
						<ListView.ItemTemplate>
							<DataTemplate>
								<StackPanel Orientation="Horizontal">
									<TextBlock Text="{Binding Name}" FontSize="20"/>
									<TextBlock Margin="10,0,0,0" FontSize="20" Text="{Binding CityCode}"/>
								</StackPanel>
							</DataTemplate>
						</ListView.ItemTemplate>
					</ListView>

到了这里,ListView就可以实现拼音分组显示了。

IV.实现分组拼音跳转

这里就需要使用GridView和SemanticZoom控件,GridView控件用于显示拼音字母集合,SemanticZoom实现视图切换,实现代码如下:

<SemanticZoom  Background="White" x:Name="semanticZoom" ViewChangeStarted="SemanticZoom_ViewChangeStarted">
				<SemanticZoom.ZoomedInView>
					<ListView Margin="15,10" x:Name="StartCityList" ItemsSource="{Binding Source={StaticResource GroupData}}"  Foreground="Black" Background="White" SelectionChanged="StartCityList_SelectionChanged" >
						<ListView.GroupStyle>
							<GroupStyle HidesIfEmpty="True">
								<GroupStyle.HeaderTemplate>
									<DataTemplate>
										<Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62" Height="62" Margin="0,0,18,0" HorizontalAlignment="Stretch">
											<TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6" FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
										</Border>
									</DataTemplate>
								</GroupStyle.HeaderTemplate>
							</GroupStyle>
						</ListView.GroupStyle>
						<ListView.ItemTemplate>
							<DataTemplate>
								<StackPanel Orientation="Horizontal">
									<TextBlock Text="{Binding Name}" FontSize="20"/>
									<TextBlock Margin="10,0,0,0" FontSize="20" Text="{Binding CityCode}"/>
								</StackPanel>
							</DataTemplate>
						</ListView.ItemTemplate>
					</ListView>
				</SemanticZoom.ZoomedInView>
				<SemanticZoom.ZoomedOutView>
					<!-- 缩放后的跳转界面 -->
					<GridView x:Name="ZoomGridView"  ItemsSource="{Binding View.CollectionGroups ,Source={StaticResource GroupData}}" HorizontalAlignment="Center" Background="Gray" VerticalAlignment="Center">
						<GridView.ItemTemplate>
							<DataTemplate>
								<Border Background="White" >
									<Border Margin="2" Width="90" Height="90" HorizontalAlignment="Left" Background="{Binding Group.Count,Converter={StaticResource BackgroundConverter}}">
										<TextBlock Text="{Binding Group.Key}" Foreground="White" FontSize="48" Padding="6" HorizontalAlignment="Left" VerticalAlignment="Center"/>
									</Border>
								</Border>
							</DataTemplate>
						</GridView.ItemTemplate>
					</GridView>
				</SemanticZoom.ZoomedOutView>
			</SemanticZoom>

这里需要注意一下,ListView和GridView使用同一个CollectionViewSource作为数据源时,可以实现自动分组跳转,不需要多余的代码。如果不是,则需要使用SemanticZoom控件的ViewChangeCompleted和ViewChangeStarted进行代码控制实现。

V. 实现分组标头颜色区分

这里我自定义了一个IValueConverter来进行GridView项显示颜色的转化,这里根据绑定分组数据的数量来区分,如果此分组有对应的数据则显示蓝色,如果分组数据为空,则显示为灰色,实际效果如第二张图片。

转换器实现代码:

class BackgroundConverter:IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, string language)
		{
			
			if(value!=null)
			{
				var count = int.Parse(value.ToString());
				if (count > 0)
					return new SolidColorBrush(Windows.UI.Colors.Blue);
			}
			return new SolidColorBrush(Windows.UI.Colors.Gray);
		}

		public object ConvertBack(object value, Type targetType, object parameter, string language)
		{
			throw new NotImplementedException();
		}
	}

总结:

WinRT框架的实现拼音分组控件虽然复杂程度大增,但是其功能区的高度可自定义化,无疑是较大的进步,我想微软会在后续的更新中推出更好的控件或解决方案,希望这篇文章对于开发WinRT框架app的你有所帮助。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Charlotte's Web

Charlotte's Web

E. B. White / Scholastic / 2004 / USD 0.01

This is the tale of how a little girl named Ferm, with the help of a friendly spider, saved her pig, Wilbur, from the usual fate of nice fat little pigs.一起来看看 《Charlotte's Web》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

html转js在线工具
html转js在线工具

html转js在线工具