Silverlight入门系列使用MVVM模式9 想在ViewModel中控制Storyboard动画.docx
- 文档编号:29803300
- 上传时间:2023-07-27
- 格式:DOCX
- 页数:16
- 大小:22.05KB
Silverlight入门系列使用MVVM模式9 想在ViewModel中控制Storyboard动画.docx
《Silverlight入门系列使用MVVM模式9 想在ViewModel中控制Storyboard动画.docx》由会员分享,可在线阅读,更多相关《Silverlight入门系列使用MVVM模式9 想在ViewModel中控制Storyboard动画.docx(16页珍藏版)》请在冰豆网上搜索。
Silverlight入门系列使用MVVM模式9想在ViewModel中控制Storyboard动画
实现Treeview的展开状态持久化和自动恢复,配合MVVM实现不容易。
所以,MVVM的核心概念理解不难,在具体使用上则问题多多。
今天要讲的话题就是一个MVVM使用上的具体问题:
Silverlight中的Storyboard动画是否可以在ViewModel中来控制?
为什么想在ViewModel中控制Storyboard?
假设我的业务逻辑在ViewModel中,业务操作好了保存Save成功了就需要启动一个动画:
Stobyboard.begin()。
而这个动画在视图中,怎么去控制它?
这个需求很普遍吧。
确实很普遍,但实现就不那么简单了,不像下面这样的Storyboard启动那么简单:
1:
Name="myImage" 2: Source=" 3: 4: 5: 6: Name="myStoryboard"> 7: 0: 2" 8: Storyboard.TargetName="myImage" 9: Storyboard.TargetProperty="Opacity" 10: From="0"To="1"/> 11: 12: 13: 14: 15: 解决方法一: ViewModel中用事件Event通知View启动Storyboard动画 ViewModel是对界面逻辑、业务逻辑、和模型数据的封装和抽象,ViewModel不依赖于具体的View视图,所以ViewModel根本不知道具体的某个Storyboard,怎么去启动这个动画呢? 解决问题思路有好多: 第一种方法就是很自然的想到在ViewModel中用事件Event通知View启动动画。 具体做法是: 在ViewModel中添加一个事件Event,当业务操作好了保存Save成功了用这个事件通知View,这样View在Event的处理函数里面打开动画即可。 ViewModel代码: 1: publicclassYourViewModel 2: { 3: publicdelegatevoidYourEventHandler(objectsender,EventArgse); 4: publiceventYourEventHandlerYourEvent; 5: protectedvoidOnYourEvent(EventArgse){ 6: if(YourEvent! =null)YourEvent(this,e); 7: } 8: 9: //当业务操作好了保存Save成功了触发这个事件 10: //OnYourEvent(newEventArgs(a)); 11: } 在Xaml.cs写codebehind代码: 1: varvm=newYourViewModel(); 2: vm.YourEvent+=(s,e)=> 3: { 4: varstory=Resources["YourTransition"]asStoryboard; 5: story.Begin(); 6: }; 7: this.DataContext=vm; 解决方法二: ViewModel属性和View绑定并用Trigger 大家知道,ViewModel的属性可以和View绑定,当属性变化的时候用NotifyPropertyChanged自动通知View。 按照这个思路,我们只要在ViewModel加一个属性,当业务操作好了保存Save成功了就改变这个属性的值,然后就会自动通知View,在View中加个Trigger,当绑定的值变化的时候就触发启动动画。 假设ViewModel属性为boolPopupSideShow.在视图中: 1: xmlns: i=" 1: xmlns: ei= Storyboard定义在Resource中: (此处Storyboard没实际意义仅为演示) 1: 2: Name="popupSideShowStory"> 3: 0: 1"/> 4: 0: 1"/> 5: 6: Name="popupSideHideStory"> 7: 0: .8"/> 8: 0: .8"/> 9: 10: 在View视图中绑定ViewModel属性为boolPopupSideShow,并用Trigger实现当绑定的值PopupSideShow变化的时候就触发启动动画: 1: Name="PopUpDisplaySide"Background="White"> 2: Interaction.Triggers> 3: DataTriggerBinding="{BindingPopupSideShow}"Value="true"> 4: ControlStoryboardActionStoryboard="{StaticResourcepopupSideShowStory}"/> 5: DataTrigger> 6: DataTriggerBinding="{BindingPopupSideShow}"Value="false"> 7: ControlStoryboardActionStoryboard="{StaticResourcepopupSideHideStory}"/> 8: DataTrigger> 9: Interaction.Triggers> 10: 11: 12: 13: 解决方法三: 加一个中间人管理Storyboard从而既实现ViewModel和View解耦,又能在ViewModel控制StoryboardViewModel属性和View 既然我们想在ViewModel里面控制Storyboard,而ViewModel又不能依赖具体的View,所以我们可以加个中间人把Storyboard抽象出来,这样既能实现ViewModel和View解耦,又能在ViewModel通过中间人控制Storyboard。 这个思路我想也是很自然的。 但怎么实现呢? 首先这个中间人要和View发生联系必须要能在Xaml里面绑定,所以我们要实现DependencyProperty。 我们首先加一个StoryboardManager: 1: usingSystem; 2: usingSystem.Windows; 3: usingSystem.Windows.Media.Animation; 4: usingSystem.Collections.Generic; 5: 6: namespaceTestVMAnimation 7: { 8: publicclassStoryboardManager 9: { 10: publicstaticDependencyPropertyIDProperty= 11: DependencyProperty.RegisterAttached("ID",typeof(string),typeof(StoryboardManager), 12: newPropertyMetadata(null,IdChanged)); 13: 14: staticreadonlyDictionary 15: 16: publicdelegatevoidCallback(objectstate); 17: 18: /// 19: ///IDsthechanged. 20: /// 21: /// 22: /// 23: privatestaticvoidIdChanged(DependencyObjectobj,DependencyPropertyChangedEventArgse) 24: { 25: varsb=objasStoryboard; 26: if(sb==null) 27: return; 28: 29: varkey=e.NewValueasstring; 30: if(Storyboards.ContainsKey(key)) 31: Storyboards[key]=sb; 32: else 33: Storyboards.Add(key,sb); 34: } 35: 36: /// 37: ///Playsthestoryboard. 38: /// 39: /// 40: /// 41: /// 42: publicstaticvoidPlayStoryboard(stringid,Callbackcallback,objectstate) 43: { 44: if(! Storyboards.ContainsKey(id)) 45: { 46: callback(state); 47: return; 48: } 49: Storyboardsb=Storyboards[id]; 50: EventHandlerhandler=null; 51: EventHandlerhandlertemp=handler; 52: handler=delegate{sb.Completed-=handlertemp;callback(state);}; 53: sb.Completed+=handler; 54: sb.Begin(); 55: } 56: 57: /// 58: ///SetstheID. 59: /// 60: /// 61: /// 62: publicstaticvoidSetID(DependencyObjectobj,stringid) 63: { 64: obj.SetValue(IDProperty,id); 65: } 66: 67: /// 68: ///GetstheID. 69: /// 70: /// 71: /// 72: publicstaticstringGetID(DependencyObjectobj) 73: { 74: returnobj.GetValue(IDProperty)asstring; 75: } 76: } 77: 78: } 有了DependencyProperty就可以在Xaml里面绑定了,注意下面的StoryboardManager.ID: 1: 2: Key="YourStoryboardResourceKey" 3: StoryboardManager: StoryboardManager.ID="YourAnimation"> 4: 0: 1"Storyboard.TargetName="btn1" 5: Storyboard.TargetProperty="Angle"/> 6: 7: 在ViewModel里面控制Storyboard很简单,下面这个例子是通过Command调用的,你当然也可以不通过Command直接调用Storyboard,像本文的例子,可以在ViewModel的业务逻辑里面当业务操作好了保存Save成功了启动Storyboard动画。 1: publicclassYourViewModel 2: { 3: publicICommandPlayStoryboardCommand{get;privateset;} 4: 5: publicYourViewModel() 6: { 7: PlayStoryboardCommand=newDelegateCommand( 8: ()=>{ 9: StoryboardManager.PlayStoryboard("YourAnimation",(o)=>{},null); 10: }); 11: } 12: 13: 14: } 解决方法四: 不要在ViewModel里面控制Storyboard,把Transition封装在控件中 用MVVM模式的出发点之一就是分离关注点(Separationofconcerns).View负责什么? UILayout,structure,appearance,animation,那View的CodeBehind(Xaml.cs)可以有什么? View的CodeBehind可以有InitializeComponent,可以有Xaml里面表示不了的视觉行为,比如复杂动画控制(带callback,completed事件那种)。 还可以是视觉元素的控制。 总之,只要这些代码是View该负责的,是高内聚的,是不想被重用的,是不能被测试的,那你就搁在codebehind好了。 绝对应该避免业务逻辑在里面哦。 某位大神说过,“解决问题的最好办法是thinkdifferent,说不定问题本身就不是个问题”。 是的,你想在ViewModel里面控制Storyboard,这本身是不是有问题? 想想我们的动画一般在什么时候发生? 真的是业务逻辑完成了发生吗? 真的和业务逻辑相关吗? 不! 动画其实是和VisualElement的VisualState相关。 也就是说,我们往往是在某个panel显示/隐藏/打开/关闭的时候有个淡入淡出、推箱子、跳跃、或者x/y/z/3D旋转的效果(不要告诉我是显示/隐藏panel本身,这个可以和ViewModel的属性绑定的,不是动画)。 说白了就是一个transition,从一个VisualState到另一个VisualState而已。 好了,想清楚了,问题就没有了。 也就是说,你无须在ViewModel里面控制Storyboard,只要在View里面定义好VisualState就可以了,封装在控件行为中,把VisualState动画写在控件的模板中,有关怎么封装Silverlight控件这儿就不多说了,下回有空再说。 具体做法可以参考MSDN这个页面,里面就有button的VisualState切换动画,比如MouseOver等: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: VisualStateManager.VisualStateGroups> 21: VisualStateGroupx: Name="CommonStates"> 22: VisualStatex: Name="Normal"/> 23: VisualStatex: Name="MouseOver"> 24: 25: 26: 27: 28: 29: 30: VisualState> 31: VisualStatex: Name="Pressed"> 32: 33:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Silverlight入门系列使用MVVM模式9 想在ViewModel中控制Storyboard动画 Silverlight 入门 系列 使用 MVVM
![提示](https://static.bdocx.com/images/bang_tan.gif)
链接地址:https://www.bdocx.com/doc/29803300.html