Prism应用开发(五)——MVVM模式关键技术

一、Data Binding

Data Binding在MVVM模式中起到了重要的作用,WPF提供了强大的数据绑定功能,因此在设计view和model时应该充分利用这些能力,这意味着你必须实现正确的接口。

1)WPF支持one-way binding和two-way binding,two-way binding会将用户对界面数据的修改自动更新到底层数据对象。

2)为了将view model或者model中的数据更新通知到view,需要实现INotifyPropertyChanged接口或者INotifyCollectionChanged接口(如果model是一个集合)。

3)此外,ICollectionView接口在view和view model/model底层集合对象之间提供了排序、过滤、分组以及选择元素的跟踪操作。WPF的ListCollectionView实现了ICollectionView接口。

二、Commands

在WPF中,用户通过UI进行的操作被定义为Commands。Commands为操作和UI上的控件进行绑定提供了一种便利的方式。

WPF的一些控件提供了Command属性,这个属性可以绑定到viewModel中实现了ICommand接口的对象,例如:

  1. public class QuestionnaireViewModel  
  2. {  
  3. public QuestionnaireViewModel()  
  4. {  
  5. this.SubmitCommand = new DelegateCommand<object>(  
  6. this.OnSubmit, this.CanSubmit );  
  7. }  
  8. public ICommand SubmitCommand { getprivate set; }  
  9. private void OnSubmit(object arg) {...}  
  10. private bool CanSubmit(object arg) { return true; }  
  11. }  
public class QuestionnaireViewModel
{
public QuestionnaireViewModel()
{
this.SubmitCommand = new DelegateCommand<object>(
this.OnSubmit, this.CanSubmit );
}
public ICommand SubmitCommand { get; private set; }
private void OnSubmit(object arg) {...}
private bool CanSubmit(object arg) { return true; }
}
  1. <Button Command="{Binding Path=SubmitCommand}" CommandParameter="SubmitOrder"/>  
<Button Command="{Binding Path=SubmitCommand}" CommandParameter="SubmitOrder"/>
  1. <Button Content="Submit" IsEnabled="{Binding CanSubmit}">  
  2. <i:Interaction.Triggers>  
  3. <i:EventTrigger EventName="Click">  
  4. <i:InvokeCommandAction Command="{Binding SubmitCommand}"/>  
  5. </i:EventTrigger>  
  6. </i:Interaction.Triggers>  
  7. </Button>  
<Button Content="Submit" IsEnabled="{Binding CanSubmit}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding SubmitCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>

三、数据验证

在MVVM模式中,数据验证可以通过在view model / model实现IDataErrorInfo接口和INotifyDataErrorInfo接口来实现,这些接口允许view model / model对一个或多个属性进行数据验证,并且向view返回errir message。

IDataErrorInfo接口提供了基本的数据验证和错误报告的功能,它包含两个属性,一个索引器属性(索引器使用属性名作为参数)和一个Error属性。索引器属性根据传递的属性名返回错误消息,如果返回值为Empty或者null,表示属性change合法,Error属性为整个对象提供error message,但是现在的WPF和Silverlight引擎都没有使用这个属性。

IDataError的索引器属性将会在第一次数据绑定或者属性的每次改变被调用,因为索引器属性在每个属性发生改变的时候都会被调用,所以要保证这个数据验证函数要尽可能的高效。

  1. <TextBox  
  2. Text="{Binding Path=CurrentEmployee.Name, Mode=TwoWayValidatesOnDataErrors=True,  
  3. NotifyOnValidationError=True }"  
  4. />  
<TextBox
Text="{Binding Path=CurrentEmployee.Name, Mode=TwoWay, ValidatesOnDataErrors=True,
NotifyOnValidationError=True }"
/>
  1.  public class Agent : NotificationObject, IDataErrorInfo  
  2.     {   
  3.         /// <summary>  
  4.         /// Name of Agent  
  5.         /// </summary>  
  6.         [DisplayOrder(1)]  
  7.         [DisplayName("Agent Name")]  
  8.         public string DisplayName  
  9.         {  
  10.             get  
  11.             {  
  12.                 return displayName;  
  13.             }  
  14.             set  
  15.             {  
  16.                 if (displayName != value)  
  17.                 {  
  18.                     displayName = value;  
  19.                     this.isSelfChanged = true;  
  20.                     RaisePropertyChanged<string>(() => this.DisplayName);  
  21.                     RaisePropertyChanged<string>(() => this.Error);  
  22.                 }  
  23.             }  
  24.         }  
  25.   
  26.         /// <summary>  
  27.         /// the address client can connect to the agent  
  28.         /// </summary>  
  29.         [DisplayOrder(2)]  
  30.         [DisplayName("EndPoint Address")]  
  31.         public string Address  
  32.         {  
  33.             get  
  34.             {  
  35.                 return address;  
  36.             }  
  37.             set  
  38.             {  
  39.                 address = value;  
  40.                 this.isSelfChanged = true;  
  41.                 RaisePropertyChanged<string>(() => this.Address);  
  42.                 RaisePropertyChanged<string>(() => this.Error);  
  43.             }  
  44.         }      
  45.  
  46.         #region IDataErrorInfo Members  
  47.   
  48.         string IDataErrorInfo.Error  
  49.         {  
  50.             get { throw new NotImplementedException(); }  
  51.         }  
  52.   
  53.         string IDataErrorInfo.this[string columnName]  
  54.         {  
  55.             get  
  56.             {  
  57.                 if (!string.IsNullOrEmpty(columnName))  
  58.                 {  
  59.                     Error = string.IsNullOrEmpty(Error) ? Error : (Error + Environment.NewLine);  
  60.                     switch (columnName)  
  61.                     {  
  62.                         case "DisplayName":  
  63.                             if (string.IsNullOrEmpty(DisplayName))  
  64.                                 return "Display name is required.";  
  65.                         case "Address":  
  66.                             if (string.IsNullOrEmpty(Address))  
  67.                                 return "Address is required.";  
  68.                         default:  
  69.                             return string.Empty;  
  70.                     }  
  71.                 }  
  72.                 return string.Empty;  
  73.             }  
  74.         }  
  75.  
  76.         #endregion       
  77.     }   
 public class Agent : NotificationObject, IDataErrorInfo
    { 
        /// <summary>
        /// Name of Agent
        /// </summary>
        [DisplayOrder(1)]
        [DisplayName("Agent Name")]
        public string DisplayName
        {
            get
            {
                return displayName;
            }
            set
            {
                if (displayName != value)
                {
                    displayName = value;
                    this.isSelfChanged = true;
                    RaisePropertyChanged<string>(() => this.DisplayName);
                    RaisePropertyChanged<string>(() => this.Error);
                }
            }
        }

        /// <summary>
        /// the address client can connect to the agent
        /// </summary>
        [DisplayOrder(2)]
        [DisplayName("EndPoint Address")]
        public string Address
        {
            get
            {
                return address;
            }
            set
            {
                address = value;
                this.isSelfChanged = true;
                RaisePropertyChanged<string>(() => this.Address);
                RaisePropertyChanged<string>(() => this.Error);
            }
        }    

        #region IDataErrorInfo Members

        string IDataErrorInfo.Error
        {
            get { throw new NotImplementedException(); }
        }

        string IDataErrorInfo.this[string columnName]
        {
            get
            {
                if (!string.IsNullOrEmpty(columnName))
                {
                    Error = string.IsNullOrEmpty(Error) ? Error : (Error + Environment.NewLine);
                    switch (columnName)
                    {
                        case "DisplayName":
                            if (string.IsNullOrEmpty(DisplayName))
                                return "Display name is required.";
                        case "Address":
                            if (string.IsNullOrEmpty(Address))
                                return "Address is required.";
                        default:
                            return string.Empty;
                    }
                }
                return string.Empty;
            }
        }

        #endregion     
    } 
INotifyDataErrorInfo接口比IDataErrorInfo更灵活,它支持一个属性的多个错误描述,异步数据验证以及在错误状态改变时通知view的功能。然而,INotifyDataError当前只在Silverlight4中支持,WPF4尚不支持。

  1. public abstract class DomainObject : INotifyPropertyChanged,  
  2. INotifyDataErrorInfo  
  3. {  
  4. private ErrorsContainer<ValidationResult> errorsContainer =  
  5. new ErrorsContainer<ValidationResult>(  
  6. pn => this.RaiseErrorsChanged( pn ) );  
  7. public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;  
  8. public bool HasErrors  
  9. {  
  10. get { return this.ErrorsContainer.HasErrors; }  
  11. }  
  12. public IEnumerable GetErrors( string propertyName )  
  13. {  
  14. return this.errorsContainer.GetErrors( propertyName );  
  15. }  
  16. protected void RaiseErrorsChanged( string propertyName )  
  17. {  
  18. var handler = this.ErrorsChanged;  
  19. if (handler != null)  
  20. {  
  21. handler(thisnew DataErrorsChangedEventArgs(propertyName) );  
  22. }  
  23. }  
  24. ...  
  25. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值