【Win 10 应用开发】通过数据绑定更新进度条
实现 INotifyPropertyChanged 接口可以在属性更改后通知数据的使用者,这个相信大伙儿都知道。于是,有朋友会问:对于要实时显示进度的情况,比如更新进度条,能用这个实现吗?
当然是可以的,也很简单,定义一个类,实现 INotifyPropertyChanged 接口,然后公开表示处理进度的属性,并且在属性更改后引发通知事件。
然后把该类的实例与进度条进行绑定即可,和一般的绑定差不多。不过,有一点需要强调:通常是把属性更改通知发送给UI对象的,多数情况下,我们在处理一些耗时操作都会在另一个线程上执行,这就使得在实现这个接口时,引发PropertyChanged 事件的时候容易发生错误。为了避免错误发生,在实现接口时,应当用Dispatcher来引发事件,确保能在UI线程上执行。
一个比较不错的方法,是先弄个抽象类,让它实现 INotifyPropertyChanged 接口,后面你所定义的各种 Model 类就可以从这个抽象类派生,这样会相当省事。
比如这样:
public abstract class NotifyPropertyChangedBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected async void OnPropertyChanged([CallerMemberName] string propName = "") { await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.High, () => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); }); } }
因为在引发属性更改通知时需要指定属性名称,咱们使用一个技巧,在 OnPropertyChanged 方法的参数上加一个 CallerMemberNameAttribute,这么一来,只要在被更改的属性的set方法中调用这个方法,就会自动把属性的名字传给参数了,也不用我们手动输,既免去繁杂工作,也不容易弄错。注意参数在附加CallerMemberNameAttribute后一定要给它一个默认值,说白了就是让这个参数变成可选参数,以方便运行时库在运行阶段修改它。
调用 Window.Current.Dispatcher.RunAsync 方法确保事件引发的代码是在UI线程上执行的,就不会出现因交叉线程更改用户界面而导致的异常。
好,上面说了一车的废话,下面我们来定义一个表示进度数据的类,主要包括进度的最大值、最小值,以及当前进度,这个类从刚才定义的 NotifyPropertyChangedBase 类派生。
public sealed class ProgressData : NotifyPropertyChangedBase { private int _max, _min, _currvalue; public int Max { get { return _max; } set { if (value != _max) { _max = value; OnPropertyChanged(); } } } public int Min { get { return _min; } set { if (value != _min) { _min = value; OnPropertyChanged(); } } } public int CurrentValue { get { return _currvalue; } set { if (value != _currvalue) { _currvalue = value; OnPropertyChanged(); } } } }
在用户界面上声明 ProgressBar 控件,然后绑定到上面类型的属性。
<ProgressBar Name="pb" Height="25" Margin="3,30,5,2" Maximum="{Binding Max}" Minimum="{Binding Min}" Value="{Binding CurrentValue}" SmallChange="1.0"/>
如何让 ProgressData 实例与 ProgressBar 控件关联呢,这好办,因为有一个 DataContext 属性,它可以赋任何类型的值,然后控件中的绑定会从该属性的值中寻找数据。
下面我们来关联一下。
m_progressdata = new ProgressData(); m_progressdata.Max = 100; m_progressdata.Min = 0; m_progressdata.CurrentValue = 0; this.pb.DataContext = m_progressdata;
注意看最后一行,不解释。
然后定义一个基于 Task 的异步方法,来模拟在新线程上处理数据。
async Task TestSomethingAsync() { while (m_progressdata.CurrentValue < m_progressdata.Max) { m_progressdata.CurrentValue++; await Task.Delay(20); } }
随后可以进行测试了。
private async void OnClick(object sender, RoutedEventArgs e) { m_progressdata.CurrentValue = m_progressdata.Min; Button btn = sender as Button; btn.IsEnabled = false; await TestSomethingAsync(); btn.IsEnabled = true; }
至此,就完成进度的绑定了,当你在线程中处理进度时,你可以不用管UI上用什么来显示进度了,哪怕是用文本显示,或用进度条来显示,都无所谓,数据与界面分离。
看看效果,还是挺不错的。
这种方法除了在UWP中可用,同样适用于WPF项目,因为都是一脉相承的,所以老周一直坚持:只要WPF学好了,别的都好办。
相关文章
- 从本体论开始说起——运营商关系图谱的构建及应用
- 如何成为一名数据科学家?
- 从未见过的堂兄杀了人,你的DNA是关键证据
- 20个安全可靠的免费数据源,各领域数据任你挑
- 20个安全可靠的免费数据源,各领域数据任你挑
- 阿里云李飞飞:All in Cloud时代,云原生数据库优势明显
- 基于Hadoop生态系统的一高性能数据存储格式CarbonData(性能篇)
- 大数据告诉你:10年漫威,到底有多少角色
- TigerGraph:实时图数据库助力金融风控升级
- Splunk利用Splunk Connected Experiences和Splunk Business Flow 扩大数据访问
- 大数据开发常见的9种数据分析手段
- 以免在景区看人,我爬了5W条全国景点门票数据...
- 【实战解析】基于HBase的大数据存储在京东的应用场景
- 数据科学家告诉你哪些计算机科学书籍是你应该看的
- Kafka作为大数据的核心技术,你了解多少?
- Spring Boot 整合 Redis 实现缓存操作
- 大数据学习必须掌握的五大核心技术有哪些?
- 基于Antlr在Apache Flink中实现监控规则DSL化的探索实践
- 甲骨文再次被Gartner评为分析型数据管理解决方案魔力象限领导者
- 爬取吴亦凡微博102118条转发数据,扒一扒流量的真假