最近有个项目有一个这样的需求,在文章浏览页底部有几个AppBarButton,其中有一个是评论按钮,需要在评论按钮上显示一个红色数字,类似微信的新消息提醒:

这种设计在iOS和Android平台都是很常见的,但UWP上并没有提供现成的控件。所以只能自己实现一个了。

做出来效果是这样的:

分析一下实现的思路。首先这还是一个AppBarButton,只是其中增加了一个数字徽章的显示,这个属性应该是可以绑定到其他属性的,如果绑定的值不为0,则显示数字,如果为0则隐藏数字。因此我们可以通过继承AppBarButton,并修改其模板来实现这个控件。

下面动手实践一下吧。我已经安装了最新的VS2017,不过使用VS2015的话也是差不多的。首先创建一个名为AppBarBadgeButtonSample的UWP项目:

选择在Blend中打开:

在页面上添加一个AppBar:

添加后是这样的结构:

然后需要将默认AppBarButton的模板导出来,给我们自定义的控件用。在按钮上右键选择编辑模板,编辑副本:

输入一个名字,为了简单起见我们就在当前文件中创建这个样式好了,点击确定。

切换到XAML模式,可以看到页面的XAML代码中添加了这样的资源:

这个就是AppBarButton的控件模板了。我们需要在这个默认模板的基础上,实现自定义的AppBarBadgeButton。

现在返回到VS2017,在当前项目中添加一个名为Controls的文件夹,再添加一个名为AppBarBadgeButton的文件夹,然后添加一个模板控件:

确定后,可以看到项目中添加了两个文件,一个是cs文件,一个是一个xaml文件:

这个Generic.xaml即控件的模板,但是如果每个控件的模板都写在这里的话,会显得比较乱。最好是每个控件的cs文件和xaml文件都放在一块。所以在AppBarBadgeButton目录下添加一个名为AppBarBadgeButton.xaml的样式文件,这样方便管理。同时把控件的命名空间从AppBarBadgeButtonSample.Controls.AppBarBadgeButton改为AppBarBadgeButtonSample.Controls。

现在可以把之前生成的默认的AppBarButton的模板复制过来了:

注意,要把key删掉,TargetType都要改成AppBarBadgeButton:

现在需要把这个模板导入到Generic.xaml中,把Generic.xaml中自动生成的删掉,改为下面这样:

<ResourceDictionary.MergedDictionaries><ResourceDictionary Source="ms-appx:///Controls/AppBarBadgeButton/AppBarBadgeButton.xaml" />
</ResourceDictionary.MergedDictionaries>

这样所有的控件的模板都跟自己的cs文件放在一块,Generic.xaml文件中只放引用位置,项目结构就清晰多了。

现在回到AppBarBadgeButton.cs,把控件的基类从Control改成AppBarButton。这样控件的所有行为都和默认的AppBarButton一致了。

我们需要一个数字属性,和一个控制数字是否可见的属性。添加以下代码:

public string Count
{get { return (string)GetValue(CountProperty); }set { SetValue(CountProperty, value); }
}// Using a DependencyProperty as the backing store for Count.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty CountProperty =DependencyProperty.Register("Count", typeof(string), typeof(AppBarBadgeButton), new PropertyMetadata("0", null));

这是一个依赖属性。注意为什么数字的类型是string呢?为什么不设置成int?

卖个关子,先做完再说。

现在可以修改控件的模板了。仔细分析模板就能找到需要改的地方,有一个名为ContentRoot的Grid,应该就是这里了,在名为Content的ContentPresenter后面添加一个Border和一个TextBlock来显示数字:

<Border CornerRadius="8" Margin="8" HorizontalAlignment="Right" VerticalAlignment="Top" Background="Red"  Grid.Row="0" MinWidth="16" Height="16"><TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"FontSize="10" Text="{TemplateBinding Count}" Foreground="Yellow" /></Border>

注意,这里要使用TemplateBinding将文本绑定到Count属性。

现在来试试。我们设置Page的x:Name为rootPage,把刚才在主页面添加的AppBarButton改成自定义的AppBarBadgeButton,不要忘了引入命名空间:xmlns:localControls="using:AppBarBadgeButtonSample.Controls"

再设置Page的DataContext,并添加一个Count属性,把AppBarBadgeButton的Count绑定到cs文件的Count属性上:

xaml:

<Pagex:Class="AppBarBadgeButtonSample.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:AppBarBadgeButtonSample"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:localControls="using:AppBarBadgeButtonSample.Controls"mc:Ignorable="d"x:Name="rootPage"><Page.BottomAppBar><CommandBar><CommandBar.Content><Grid/></CommandBar.Content><localControls:AppBarBadgeButton Icon="Accept" Count="{Binding Count}" Label="AppBarButton"/><AppBarButton Icon="Cancel" Label="AppBarButton"/></CommandBar></Page.BottomAppBar><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"></Grid>
</Page>

cs:

public sealed partial class MainPage : Page
{public MainPage(){this.InitializeComponent();this.Count = 10;this.rootPage.DataContext = this;}public int Count { get; set; }
}

我这里没有用标准的MVVM,只是简单演示一下。现在运行下看看:

效果出来了。

现在思考刚才提到的问题,为什么在DataContext里的属性可以设置为int,而控件本身的依赖属性必须设置为string呢?如果有兴趣可以将依赖属性改为int试试,结果就是按钮上什么也显示不出来:

这是因为,在使用TemplateBinding的时候,必须保证source属性和target属性的值的类型是匹配的,TextBlock的Text属性是string,那么用于绑定的属性的类型也必须是string。在使用TemplateBinding时,没有机会进行自动的类型转换。如果类型不匹配,则无法绑定。可参考:https://docs.microsoft.com/en-us/windows/uwp/xaml-platform/templatebinding-markup-extension

现在可以显示数字了,但是还需要做的更完善一点。有数字的时候显示,如果为0的时候就隐藏掉。所以再做一点小小的工作:

添加一个控制是否显示数字的属性:

public Visibility BadgeVisibility
{get { return (Visibility)GetValue(BadgeVisibilityProperty); }set { SetValue(BadgeVisibilityProperty, value); }
}// Using a DependencyProperty as the backing store for BadgeVisibility.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty BadgeVisibilityProperty =DependencyProperty.Register("BadgeVisibility", typeof(Visibility), typeof(AppBarBadgeButton), new PropertyMetadata(Visibility.Collapsed, null));

当Count值变化时,将其设置为隐藏:

public string Count{get { return (string)GetValue(CountProperty); }set { SetValue(CountProperty, value); }}// Using a DependencyProperty as the backing store for Count.  This enables animation, styling, binding, etc...public static readonly DependencyProperty CountProperty =DependencyProperty.Register("Count", typeof(string), typeof(AppBarBadgeButton), new PropertyMetadata("0", OnCountChanged));private static void OnCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){int count = 0;int.TryParse(e.NewValue.ToString(), out count);if (count != 0){((AppBarBadgeButton)d).SetValue(BadgeVisibilityProperty, Visibility.Visible);}else{((AppBarBadgeButton)d).SetValue(BadgeVisibilityProperty, Visibility.Collapsed);}}

最后将数字的Visibility属性绑定到这个值上:

<Border CornerRadius="8" Margin="8" HorizontalAlignment="Right" VerticalAlignment="Top" Background="Red" Visibility="{TemplateBinding BadgeVisibility}" Grid.Row="0" MinWidth="16" Height="16">

代码已开源:https://github.com/yanxiaodi/UWP-AppBarBadgeButton

Win10 UWP开发系列:开发一个自定义控件——带数字徽章的AppBarButton相关推荐

  1. 【安卓开发系列 -- 开发环境】Unbuntu 下 Android 持续集成打包环境搭建 -- Jenkins 构建工具安装(gradle + git + android 工具)

    [安卓开发系列 -- 开发环境]Unbuntu 下 Android 持续集成打包环境搭建 -- Jenkins 构建工具安装(gradle + git + android 工具) [1]Unbuntu ...

  2. Office365开发系列——开发一个全功能的Word Add-In

    2016年10月我参加了在北京举行的DevDays Asia 2016 - Office 365应用开发"48小时黑客马拉松",我开发的一个Word Add-In Demo--Wo ...

  3. Android开发系列之创建自定义控件

    Android开发过程中我们经常需要定义自己的控件,一方面基于复用的角度考虑,一方面也是基于逻辑处理思维的角度考虑.在这篇博客里面,笔者想要介绍.总结几种Android自定义控件的方法,如果有什么不对 ...

  4. [ Office 365 开发系列 ] 开发模式分析

    前言 本文完全原创,转载请说明出处,希望对大家有用. 在正式开发Office 365应用前,我们先了解一下Office 365的开发模式,根据不同的应用场景,我们选择最适合的开发模式. 阅读目录 Of ...

  5. EA开发系列---开发第一个交易EA

    涉及的内容 现在我们来通过MT5自带的MQL5编辑器来编写一个简单的交易EA.这个EA我们把它命名为"FirstEA",它实现如下功能: 1.初始化的时候打印一些信息到MT5终端 ...

  6. BizTalk开发系列(十二) Schema设计之Group与Order

    更多内容请查看:BizTalk动手实验系列目录                       BizTalk 开发系列 开发BizTalk项目的时候会先约定各系统之间往来的消息格式. 由于BizTalk ...

  7. 高通开发系列 - 总目录

    By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! ...

  8. [ Office 365 开发系列 ] Graph Service

    前言 本文完全原创,转载请说明出处,希望对大家有用. 通过[ Office 365 开发系列 ] 开发模式分析和[ Office 365 开发系列 ] 身份认证两篇内容的了解,我们可以开始使用Offi ...

  9. Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

    安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneG ...

最新文章

  1. 【动画2】CALayer动画
  2. 配置导出MOSS2010列表数据到Excel并根据列表记录自动刷新数据
  3. OSChina 周日乱弹 —— 做一只舔狗,开心时就去舔她,不开心时就舔自己
  4. Kafka consumer group位移0ffset重设
  5. C++中的逻辑操作符重载
  6. bash-shell高级编程--退出和退出状态码
  7. 734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流
  8. chrome同步_如何在Chrome中打开或关闭同步
  9. 无法将 lambda 表达式 转换为类型“System.Delegate”,因为它不是委托类型
  10. SpringBoot+zk+dubbo架构实践(三):部署Dubbo-admin管理平台
  11. 电影《邪不压正》打动我的
  12. emi软件测试,电磁干扰EMI的测试标准及应用
  13. 2019最火的直播平台有哪些?2019直播前十名排名
  14. ps 如何制作动态打字图?
  15. 跨平台开发 uni-app
  16. Docker之MySQL主从连接提示:Communications link failure
  17. Android项目---拼图小游戏(下)
  18. java服务器如何群发消息,java TCP编程简单实现一个消息群发功能
  19. 读《大四学生收到英国诺丁汉大学博士录取通知书》想到
  20. 微信小程序——获取用户个人信息

热门文章

  1. MySQL事务及隔离级别详解
  2. hadoop-0.20.1+120 hive-0.3.99.1+0 试用hwi(hive web interface
  3. 红帽20亿美元强劲收入的背后,让开源成为主流
  4. java如何获取本机IP
  5. popoverController简单介绍
  6. [转]我对CTO的理解
  7. Fatal error: Cannot redeclare db_connect() 错误
  8. Serializing - 序列化 综述 – To be continued.
  9. Andriod编程之Environment类
  10. html,htm,jhtml