chao 的个人资料清凉水都照片日志列表更多 工具 帮助

日志


9月17日

WPF中Page的历史恢复机制

del.icio.us标签: , ,

WPF中的Page调用States类中的Replay方法恢复Page(换句话说原Page的恢复信息保存在State中),
根据这个特点,我们可以继承CustomContentState,将Replay的实现改为调用外部委托实现个性化历史记录,委托的传入参数最好是继承的自定义State本身,例如自定义State名为CustomState,则委托声明为 public delegate void ReplayCustomState(CustomState state),Replay函数里只写ReplayCustomState(this),最后在CustomState构造的时候赋值给ReplayCustomState就可以了。


此外Replay方法中的具体恢复过程是针对具体要恢复的Page页的。
例如Page中有个Label名为lblName。对应数据State中存储的数据为string Name。
Replay(CustomContentState state)中则写 lblName.Text = state.Name;

虽然自定义了State,不过WPF可不认这一套,最后还要我们将自定State手动记录下来,通过NavigationService的AddBackEntry(CustomContentState)来存储State就可以了,在想存储的地方调用这个方法就可以实现自定义历史记录了,如果根据用户的特定操作记录的话,还可以实现历史回顾特性的撤销功能,和PS很像(不过这个实在历史记录按钮里)

由于自定了State,WPF原有的历史功能就不好用了,因为它在历史功能中存储的还是系统默认的State,这可不是我们想要的结果。于是要自己写个历史程序,还好只要Page继承IProvideCustomContentState接口就可以了。

IProvideCustomContentState提供一个抽象函数 public CustomContenState GetContentState(),GetContentState()在Page触发历史变更按钮的时候触发,返回CustomContentState,所以我们可以返回自己的State,从而存储自定义State,实现历史功能。在返回自定义State前要给JournalName赋值,用于标识不同的State。
虽然在反编译时,会看到当JournalName为空时,WPF自动给它赋值了,不过没有这个在实例CustomState是无法编译的,还是老老实实写上。
多说一句,实际中State存储的JournalName是你输入的JournalName+#+容器名,从而区分不同容器相同JournalName的情况(因为容器名肯定不同)。

此外,WPF对历史页面调用GetContentState()存储State进行了位置检测,换句话说,如果你在历史界面继续跳转,那么除了传入的State会变外(看你怎么生成传入的State了),State在历史记录中的位置是不会变的,

举个例子,例如你跳转到第二步的Page,名称为Step2,在历史展开列表中从下向上数在第二位置,对页面数据无改动后继续跳转,GetContentState()触发,将传回的Sate中的JournalName改为Step5,那么历史列表中从下向上数第2项更名为Step5 而不是列表的第5项。当然如果你对页面数据进行了修改,那么这个就是倒数第二个
选项了(第一个为当前页),原先Step2后的历史记录清除了。

总结一下,自定义历史记录的实现过程,首先通过继承抽象类CustomContenState,实现Replay(NavigationService navigationService, NavigationMode mode)方法,再在Page页中利用NavigationService的AddBackEntry(CustomContentState)存储历史信息。最后通过将Page页继承IProvideCustomContentState接口,实现GetContentState()方法,实现历史按钮的功能,至此WPF中Page自定义历史恢复完全实现。