WindowsPhone 开发笔记(1)—— ViewModel
2012-04-18 23:10 F-sea 阅读(1615) 评论(4) 编辑 收藏 举报本文同步发表于WP 开发论坛Windows Phone Developer Network: http://www.wpdevn.com/showtopic-104.aspx
废话: 前很长一段时间一直忙于写 GuoKr Reader 和 喂饭 。 现在终于可以 整理一下开发中的有点价值的东西。
额。。。ViewModel 这东西 直面意思就是界面对象。。他里面描述的东西应该只有 数据和业务逻辑 ,他里面不应该与任何与 界面交互相关的东西 (比如控制一个什么控件 ,动画、消息框什么的。。。。。 )发生关系(别想歪了 我故意的。。。)
但是我们在实际使用中VM 中的发生了一些事情 总得让VIEW 知道啊 所以MS 为我们提供了
System.ComponentModel.INotifyDataErrorInfo
System.ComponentModel.INotifyPropertyChanged
System.ComponentModel.InotifyPropertyChanging
等 通知 接口
我们以INotifyPropertyChanged 为例来看下结构:
里面有个 事件:PropertyChanged
VM 通过这些通知接口里面的事件 我们可以告知 View 发生了什么事情 至于 View 管不关心 或者关心什么那就不是 ViewModel的事情了
(注意: 一般来说 要绑定要界面的属性必须实现INotifyPropertyChanged 属性 也就是说在属性被修改后必须触发 PropertyChanged事件,同时Notify 接口中的事件是在UI 现场中运行的 在跨线程运行的时候一定要注意)
我们在回过头来说VM
一般来说或我都会实现一个 BaseViewModel 吧所需要的实现的接口和基础的方法都在里面实现好
using System; using System.Net; using System.Collections.Generic; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.Windows.Threading; using System.Windows.Navigation; using Microsoft.Phone.Controls; using System.Runtime.CompilerServices; using WeiFan.Utility; namespace WeiFan.UI.ViewModel { public abstract class BaseViewModel : INotifyPropertyChanged, INotifyPropertyChanging,INotifyDataErrorInfo { Dispatcher _dispatcher; public BaseViewModel() { _dispatcher = Deployment.Current.Dispatcher; } protected Dispatcher Dispatcher { get { return _dispatcher; } } protected PhoneApplicationFrame PhoneApplicationFrame { get { return (Application.Current.RootVisual as Microsoft.Phone.Controls.PhoneApplicationFrame); } } private Dictionary<String, List<String>> m_errors = new Dictionary<string, List<string>>(); public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangingEventHandler PropertyChanging; public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public System.Collections.IEnumerable GetErrors(string propertyName) { if (String.IsNullOrEmpty(propertyName) || !m_errors.ContainsKey(propertyName)) return null; return m_errors[propertyName]; } public bool HasErrors { get { return m_errors.Count > 0; } } protected bool SetProperty<T>(ref T storage, T value,string propertyName) { if (object.Equals(storage, value)) return false; this.FirePropertyChanging(new PropertyChangingEventArgs(propertyName)); storage = value; this.FirePropertyChanged(new PropertyChangedEventArgs(propertyName)); return true; } protected virtual void FirePropertyChanging(PropertyChangingEventArgs args) { if (PropertyChanging != null) { PropertyChanging(this, args); } } protected virtual void FirePropertyChanged(PropertyChangedEventArgs args) { if (PropertyChanged != null) { PropertyChanged(this, args); } } protected virtual void FireErrorsChanged(DataErrorsChangedEventArgs args) { if (ErrorsChanged != null) ErrorsChanged(this, args); } protected virtual void AddError(string propertyName, string error, bool isWarning) { if (!m_errors.ContainsKey(propertyName)) m_errors[propertyName] = new List<string>(); if (!m_errors[propertyName].Contains(error)) { if (isWarning) m_errors[propertyName].Add(error); else m_errors[propertyName].Insert(0, error); FireErrorsChanged(new DataErrorsChangedEventArgs(propertyName)); } } protected virtual void RemoveError(string propertyName, string error) { if (m_errors.ContainsKey(propertyName) && m_errors[propertyName].Contains(error)) { m_errors[propertyName].Remove(error); if (m_errors[propertyName].Count == 0) m_errors.Remove(propertyName); FireErrorsChanged(new DataErrorsChangedEventArgs(propertyName)); } } } }
VM 就说到这里吧。。。。下面来说怎么用他。。。。。
最简单的用法的就是在页面代码中 (xaml.cs) 构造出来比如 BaseViewModel baseVM = new BaseViewModel();
然后使用 (里面公开的属性 方法 什么的 爱怎么搞怎么搞。。。。。)
如果要在xaml 中binding 的话就要把设置控件(或控件所属的容器)的DataContext设置为该VM (别的方式我还不知道。。。。。。 )
比如:
在xmal.cs 中
LayoutRoot.DataContent = new XXXXViewMode();
或者:
<Grid.DataContext>
<WeiFan_UI_ViewModel:StatusVM/>
</Grid.DataContext>
如果是后者的话 VM 会在空间Load的时候构造 但是 VM 必须有一个无参数的购找函数。。。
那么
如果VM 由于业务原因 我们总需要在构造的时候需要一些参数进行初始化那么肿么办呢。。。。。。。。。。。
我表示我还没找到好的解决方案。。。。。
我想到的方法有个两个
1、就在xaml.cs 中写吧
但是 我们在xaml 中banding的时候会变得很纠结。。。。
具体怎么纠结 各位自己去体会吧。。。。
2、还是xaml 做vm吧。。。 不过我们得写个初始方法
额。。。 比如。。。
public class StatusVM:BaseViewModel { bool m_isInitialed = false; public bool IsInitialed { get { return m_isInitialed; } set { SetProperty(ref m_isInitialed, value, "IsInitialed"); } } public void Initialization(string statusID) { ….... } }
xaml 中的写法不变
在xaml.cs 的只是需要使用vm 前 构造前 调用Initialization 进行初始化。。。。。