Windows Phone版本号自升入8.1以来,开发者就多了一个选项,开发基于WinRT架构的WP或者Universal Windows App。然而开发框架转为WinRT后,很多原有的WP8基于Sliverlight框架的控件和方法变得不再有效,这无疑带来较大的困扰。今天我要讲述的就是此类问题中较易出现的列表拼音分组方案,本文基于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 = ;
string label = slg.Lookup(keySelector(item));
index = list.FindIndex(alphagroupkey => (alphagroupkey.Key.Equals(label, StringComparison.CurrentCulture)));
if (index > - && 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的你有所帮助。

Windows Phone开发手记-WinRT下分组拼音的实现的更多相关文章

  1. Windows Phone开发手记-WinRT下自定义圆形ItemsControl

    这里的ItemsControl指的是Xaml里的集合控件,包括ListView,GridView等,此篇博客主要参考MSDN Blog的一篇文章,具体出处为:http://blogs.msdn.com ...

  2. Windows Phone开发手记-WinRT下启动器替代方案

    在WP7/8时代,Silverlight框架提供了很多启动器API,我们可以很方便的使用的,来完成一些系统级的操作.但是随着Win RT架构的WP8.1(SL 8.1除外)的到来,原有的SL下的启动器 ...

  3. Android开发手记(10) 下拉菜单Spinner

    1.自定义Spinner 首先,定义Spinner要显示的项目列表/res/values/arrays.xml <?xml version="1.0" encoding=&q ...

  4. Windows Phone开发(11):常用控件(下)

    原文:Windows Phone开发(11):常用控件(下) WP控件大部分都可以从Silverlight中继承过来,这里我也只能拿一部分作演示,对于其它控件如何使用,可以参考SDK相关说明以及Sil ...

  5. windows RT开发笔记:WinRT DLL及其调用研究

    一. 几个概念: WinRT : Windows Runtime, windows运行时.创建Windows运行时(WinRT)是为了在Windows上给用户提供一种流畅且安全的应用体验.WinRT会 ...

  6. Kinect for Windows SDK开发入门(15):进阶指引 下

    Kinect for Windows SDK开发入门(十五):进阶指引 下 上一篇文章介绍了Kinect for Windows SDK进阶开发需要了解的一些内容,包括影像处理Coding4Fun K ...

  7. 【VS开发】【miscellaneous】windows(64位)下使用curl命令

    windows(64位)下使用curl命令 Curl命令可以通过命令行的方式,执行Http请求.在Elasticsearch中有使用的场景,因此这里研究下如何在windows下执行curl命令. 工具 ...

  8. Windows 10 开发人员预览版中的新增功能(转自 IT之家)

    Windows 10 开发人员预览版中的新增功能 在Win10预览版中安装工具与SDK后,即可着手创建Windows通用应用或先浏览目前的环境与此前相比都发生了什么变化. 应用建模 文件资源管理器: ...

  9. HoloLens开发手记 - Unity development overview 使用Unity开发概述

    Unity Technical Preview for HoloLens最新发行版为:Beta 24,发布于 09/07/2016 开始使用Unity开发HoloLens应用之前,确保你已经安装好了必 ...

随机推荐

  1. JSON.parse和JSON.stringify的区别

    JSON.stringify()的作用是将 JavaScript 值转换为 JSON 字符串, 而JSON.parse()可以将JSON字符串转为一个对象. 简单点说,它们的作用是相对的,我用JSON ...

  2. Java泛型总结——吃透泛型开发

    什么是泛型 泛型是jdk5引入的类型机制,就是将类型参数化,它是早在1999年就制定的jsr14的实现. 泛型机制将类型转换时的类型检查从运行时提前到了编译时,使用泛型编写的代码比杂乱的使用objec ...

  3. 负载均衡下 tomcat session 共享

    概述 在分布式部署的情况下,每台tomcat 都会有自己的session ,这样如果 用户A 在tomcat1 下登录,在tomcat2 下并没有session信息.如果 tomcat1宕机,tomc ...

  4. mysql mybatis useGeneratedKeys Field 'ID' doesn't have a default value的问题

    原因是:创建表时没有让id自动增长: CREATE TABLE `STORAGE_VIRTUAL` ( `ID` ) NOT NULL AUTO_INCREMENT, `STORAGE_ID` ) N ...

  5. MFC调试时无法解析外部类

    1.是否添加头文件 2.是否对类进行声明

  6. BZOJ 4765 普通计算姬 (分块 + BIT)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1547  Solved: 329[Submit][Status][Discus ...

  7. 微信小程序之弹框modal

    官方文档 <modal hidden="{{hidden}}" title="这里是title" confirm-text="自定义确定按钮&q ...

  8. Linux学习(1)- TCP/IP网络协议基础

    Linux学习(1)- TCP/IP网络协议基础 一.TCP/IP 简介 学习内容 TCP/IP(Transmission Control Protocol/Internet Protocol)是传输 ...

  9. (转)MVC语法-基础

    好久没有关注微软的开发了,今天看到了MVC3,顺便学习学习,我觉得Razor是个不错的做法,比使用<%%>简单多了,而且好看.首先“_”开头的cshtml文档将不能在服务器上访问,和asp ...

  10. Logging from multiple processes using log4net

    When logging with log4net to a file (using the FileAppender), the FileAppender is holding an exclusi ...