轉帖|其它|編輯:郝浩|2011-01-06 16:45:37.000|閱讀 1234 次
概述:要在MVVM架構下實現模式窗口(Modal Dialogs),首先,我們需要實現怎么顯示模式窗口。幸運的是,不管是SilverLight3還是SilverLight4都提供了 ChildWindow。當然,我們也可以使用第三方控件來實現。但是最重要的問題是怎么在MVVM架構中去實現模式窗口,即怎么在ViewMode中實現,同時要實現View層和ViewModel的松耦性,另外依照MVVM架構思想,ViewModel層不必知道View的樣式。本文主要介紹如何在在MVVM架構下實現模式窗口。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
要在MVVM架構下實現模式窗口(Modal Dialogs),首先,我們需要實現怎么顯示模式窗口。幸運的是,不管是SilverLight3還是SilverLight4都提供了 ChildWindow。當然,我們也可以使用第三方控件來實現。但是最重要的問題是怎么在MVVM架構中去實現模式窗口,即怎么在ViewMode中實 現,同時要實現View層和ViewModel的松耦性,另外依照MVVM架構思想,ViewModel層不必知道View的樣式,所以我們必須需要一個 接口,例如下圖
從上圖可以知道必須定義一個屬性DialogResult,其作用就是確定View層上確定或者取消按鈕是否被點擊。還必須定義兩個方 法:Close和ShowDialog,兩個方法的作用是關閉和顯示模式窗口。當模式窗口被關閉時,還需要一個事件Closed來處理后續的操作。最后, 還需要一個屬性Content,這個屬性非常的特殊,為什么這樣說呢?可以有兩種方法來實現。
第一種方法,我可以把屬性Content與屬性DataContext交換數據。或者換句話說,我們必須為每個實體創建一個模式窗口(Child Window),然后我們僅需要把目標實體賦值給模式窗口的屬性DataContext即可,如果下圖
第二個方法。我們需要做的事情比較多,首先把每個實體替換成單獨的Child Window,你可以使用UserControls顯示實體信息,然后把只要把UserControl賦值給模式窗口的Content即可。具體過程看下圖
在這個例子中,我將使用第二種方法實現在MVVM架構中顯示模式窗口。在接口IModalView中定義一個UserControl的屬性DataContext,如下圖:
最后,定義一個接口 IModalDialogWorker,此接口只提供了一個方法---顯示模式窗口的方法。如下圖
從上圖你可能發現,當顯示一個模式窗口時,必須得傳遞的參數有接口IModalDialog、接口IModalView、 DataContext(可以是任意實體,比如:Person、Customer等),最后,還需要傳遞一個Action,當模式窗口被關閉時它被執行。
ModalDialogWorker 的實現非常的簡單,僅僅是幾行代碼,如下:
public class ExtendedChildWindow : ChildWindow, IModalDialog
{
public void ShowDialog()
{
this.Show();
}
}
上面這個類ExtendedChildWindow 是通用的,你只需要向屬性Content賦值即可。例如,如果你需要創建一個修改實體Person的窗口,你就必須創建一個新的UserControl和實現接口IModalView。
public partial class EditPersonControl :
UserControl, IModalView{
public EditPersonControl()
{
InitializeComponent();
}
public event EventHandler<ModalViewEventArgs> Closed;
protected virtual void OnClosed( ModalViewEventArgs e )
{
if ( this.Closed != null )
this.Closed( this, e );
}
private void btnOkClick( object sender, RoutedEventArgs e )
{
this.OnClosed( new ModalViewEventArgs( true ) );
}
private void btnCancelClick( object sender, RoutedEventArgs e )
{
this.OnClosed( new ModalViewEventArgs( false ) );
}
}
你僅僅需要做的事情就是在后臺代碼中實現接口IModalView即可:若確定按鈕被按下時設置屬性DialogResult為true,若取消按鈕被按下時,設置為false。說明:因為這段代碼不是業務邏輯,是UI設計,所以可以寫在后臺。
最后在 ModalDialogWorker再寫入以下三句代碼即可
modalDialog.Content = modalView;
modalView.DataContext = dataContext;
modalDialog.ShowDialog();
最后一個問題是怎么把接口IModalDialog, IModalVIew 和IModalDialogWorker的實現潛入到ViewModel中,看下圖
在ViewModel層,需要引入Imports,然后使用類ModalDialogWorker,此類有四個參數,主要用來顯示模式窗口,其中具體的實現方法已經在上面說明過。下面的代碼就是怎么調用此接口。
private void OnEditPersonCommandExecute()
{
this.ModalDialogWorker.ShowDialog<Person>
( this.ModalDialog, this.EditPersonControl, this.SelectedPerson, p =>
{
if ( this.ModalDialog.DialogResult.HasValue && this.ModalDialog.DialogResult.Value
)
{
// OK
}
else
{
//Cancel
}
}
);
}
如果隨筆到此為知,基本上已經可以實現彈出模式窗口的效果了,但是還有一個重要的問題,怎么修改對象的值。比如:修改一個條數據時,你如果把數 據傳到模式窗口,賦值到指定的位置(TextBox,DateTime等等)。而且當在模式窗口輸入數據并點擊確定或者取消按鈕時,怎么提交這些數據,怎 么恢復對象原始狀態。
我們必須通過使用BeginEdit、EndEdit和CancelEdit方法來實現提交或者回滾這些改變。實現這些功能非常的容易,我們可 以使用接口IEditableObject.其中最重要的一個問題是怎么保存對象的狀態。我們可以使用Memento模式,看下圖
通過上圖,我們可以創建一個基類,命名為Memento,代碼如下
public class Memento<T>
{
private Dictionary<PropertyInfo, object> storedProperties = new Dictionary<PropertyInfo, object>();
public Memento( T originator )
{
this.InitializeMemento( originator );
}
public T Originator
{
get;
protected set;
}
public void Restore( T originator )
{
foreach ( var pair in this.storedProperties )
{
pair.Key.SetValue( originator, pair.Value, null );
}
}
private void InitializeMemento( T originator )
{
if ( originator == null )
throw new ArgumentNullException( "Originator", "Originator cannot be null" );
this.Originator = originator;
IEnumerable<PropertyInfo> propertyInfos = typeof( T ).GetProperties( BindingFlags.Public | BindingFlags.Instance )
.Where( p => p.CanRead && p.CanWrite );
foreach ( PropertyInfo property in propertyInfos )
this.storedProperties[ property ] = property.GetValue( originator, null );
}
}
這段代碼比較簡單,首先你要傳一個參數originator,在方法InitiallizeMemento中,你需要把對象的狀態,所有的屬性以及他們的值存入一個簡單的Dictionary
this.Originator = originator;
IEnumerable propertyInfos = typeof( T ).GetProperties(
BindingFlags.Public | BindingFlags.Instance )
.Where( p => p.CanRead && p.CanWrite );
foreach ( PropertyInfo property in propertyInfos )
this.storedProperties[ property ] = property.GetValue( originator, null );
最后,在方法RestoreState中,我們把原始數據還原取對象的初始狀態
public void Restore( T originator )
{
foreach ( var pair in this.storedProperties )
{
pair.Key.SetValue( originator, pair.Value, null );
}
}
最后是一個類Caretaker,此類是一個簡單的封裝,實現了接口IEditalbleOject以及引用了基類Memento,代碼如下
public class Caretaker<T> : IEditableObject
{
private Memento<T> memento;
private T target;
public T Target
{
get
{
return this.target;
}
protected set
{
if ( value == null )
{
throw new ArgumentNullException( "Target", "Target cannot be null" );
}
if ( Object.ReferenceEquals( this.Target, value ) )
return;
this.target = value;
}
}
public Caretaker( T target )
{
this.Target = target;
}
public void BeginEdit()
{
if ( this.memento == null )
this.memento = new Memento<T>( this.Target );
}
public void CancelEdit()
{
if ( this.memento == null )
throw new ArgumentNullException( "Memento", "BeginEdit() is not invoked" );
this.memento.Restore( Target );
this.memento = null;
}
public void EndEdit()
{
if ( this.memento == null )
throw new ArgumentNullException( "Memento", "BeginEdit() is not invoked" );
this.memento = null;
}
}
到此為止,就可以按下面的方式調用Caretaker了
Caretaker<Person> editableObject = new Caretaker<Person>( this.SelectedPerson );
editableObject.BeginEdit();
//.....
this.SelectedPerson.Name = "Pesho";
// Commit Changes
editableObject.EndEdit();
// -or CancelChanges
// editableObject.CancelEdit();
通過上面的方法,我們返回到ViewModel層,當更新對象的方法OnEditPersonCommandExecute中有如下代碼
private void OnEditPersonCommandExecute()
{
Caretaker<Person> editableObject = new Caretaker<Person>( this.SelectedPerson );
editableObject.BeginEdit();
this.ModalDialogWorker.ShowDialog<Person>(
this.ModalDialog, this.EditPersonControl, this.SelectedPerson, p =>
{
if ( this.ModalDialog.DialogResult.HasValue &&
this.ModalDialog.DialogResult.Value )
{
editableObject.EndEdit();
}
else
{
editableObject.CancelEdit();
}
} );
}
到此為止,已經可以實現在MVVM模式中彈出模式窗口以及實現修改對象的值。希望對大家有幫忙,因為如果實現真正的MVVM模式時,實現彈出窗口并且可以把數據賦值給窗口的控件,并且可以修改數據庫的值時真的不太容易
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:網絡轉載