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接口的對象,例如:

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; }
}
<Button Command="{Binding Path=SubmitCommand}" CommandParameter="SubmitOrder"/>
<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的索引器屬性將會在第一次數據綁定或者屬性的每次改變被調用,因爲索引器屬性在每個屬性發生改變的時候都會被調用,所以要保證這個數據驗證函數要儘可能的高效。

<TextBox
Text="{Binding Path=CurrentEmployee.Name, Mode=TwoWay, ValidatesOnDataErrors=True,
NotifyOnValidationError=True }"
/>
 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尚不支持。

public abstract class DomainObject : INotifyPropertyChanged,
INotifyDataErrorInfo
{
private ErrorsContainer<ValidationResult> errorsContainer =
new ErrorsContainer<ValidationResult>(
pn => this.RaiseErrorsChanged( pn ) );
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public bool HasErrors
{
get { return this.ErrorsContainer.HasErrors; }
}
public IEnumerable GetErrors( string propertyName )
{
return this.errorsContainer.GetErrors( propertyName );
}
protected void RaiseErrorsChanged( string propertyName )
{
var handler = this.ErrorsChanged;
if (handler != null)
{
handler(this, new DataErrorsChangedEventArgs(propertyName) );
}
}
...
}




發佈了71 篇原創文章 · 獲贊 13 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章