SilverLight4:在MVVM架构下实现模式窗口

SilverLight4:在MVVM架构下实现模式窗口,第1张

概述SilverLight4:在MVVM架构下实现模式窗口   要在MVVM架构下实现模式窗口(Modal Dialogs),首先,我们需要实现怎么显示模式窗口。幸运的是,不管是SilverLight3还是SilverLight4都提供了ChildWindow。当然,我们也可以使用第三方控件来实现。但是最重要的问题是怎么在MVVM架构中去实现模式窗口,即怎么在ViewMode中实现,同时要实现View SilverLight4:在MVVM架构下实现模式窗口

  要在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  ModalDialogWorker : IModalDialogWorker{    
public   voID  ShowDialog < T >

IModalDialog modalDialog, 
IModalVIEw modalVIEw, 
T dataContext, 
Action
< T >  onClosed )   
 {        
if  ( modalDialog  ==   null  )            
throw   new  ArgumentNullException(  " modalDialog " " Cannot be null "  );       
 
if  ( modalVIEw  ==   null  )            
throw   new  ArgumentNullException(  " modalVIEw " " Cannot be null "  );         
EventHandler onDialogClosedHandler 
=   null ;        EventHandler < ModalVIEwEventArgs >  onVIEwClosedHandler  =   null ;        
 
if  ( onClosed  !=   null  )        
{            onDialogClosedHandler 
=  ( s, a )  =>             
{                
modalDialog.Closed 
-=  onDialogClosedHandler;                
onClosed( dataContext );           
 };            
 onVIEwClosedHandler 
=  ( s, a )  =>             {                
modalDialog.Closed 
-=  onDialogClosedHandler;                modalVIEw.Closed  -=  onVIEwClosedHandler;                modalDialog.DialogResult  =  a.DialogResult;                 // modalDialog.Close();                
onClosed( dataContext );           
 };             
modalDialog.Closed 
+=  onDialogClosedHandler;            
modalVIEw.Closed 
+=  onVIEwClosedHandler;       
 }         
modalDialog.Content 
=  modalVIEw;        modalVIEw.DataContext  =  dataContext;        modalDialog.ShowDialog();    
}
}

 

  下面来实现接口 IModalDialog和IModalVIEw.ModalDialog的实现非常简单,只要继承Child Window和接口IModalDialog即可。请看下面代码

  

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            
}        

);
}

 

  如果随笔到此为知,基本上已经可以实现d出模式窗口的效果了,但是还有一个重要的问题,怎么修改对象的值。比如:修改一条数据时,你如果把数据传到模式窗口,赋值到指定的位置(TextBox,DateTime等等)。而且当在模式窗口输入数据并点击确定或者取消按钮时,怎么提交这些数据,怎么恢复对象原始状态。

  我们必须通过使用BeginEdit、EndEdit和CancelEdit方法来实现提交或者回滚这些改变。实现这些功能非常的容易,我们可以使用接口IEditableObject.其中最重要的一个问题是怎么保存对象的状态。我们可以使用Memento模式,看下图

 通过上图,我们可以创建一个基类,命名为Memento<T>,代码如下

 

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,monospace; direction: ltr; color: black; Font-size: 8pt; border-style: none; padding: 0px;">    }
}

  这段代码比较简单,首先你要传一个参数originator,在方法InitiallizeMemento中,你需要把对象的状态,所有的属性以及他们的值存入一个简单的Dictionary<string,object>

 

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 );

  最后,在方法RestoreState中,我们把原始数据还原取对象的初始状态  

public voID Restore( T originator )
{
    foreach ( var pair in this.storedPropertIEs )
    {
        pair.Key.SetValue( originator,null );
    }
}

  最后是一个类Caretaker,此类是一个简单的封装,实现了接口IEditalbleOject以及引用了基类Memento<T>,代码如下

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()

            throw new ArgumentNullException( "Memento","BeginEdit() is not invoked" );

        this.memento.Restore( Target );

        this.memento = null;

    public voID EndEdit()

        if ( this.memento == null )

"BeginEdit() is not invoked" );

}

  到此为止,就可以按下面的方式调用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模式中d出模式窗口以及实现修改对象的值。希望对大家有帮忙,因为如果实现真正的MVVM模式时,实现d出窗口并且可以把数据赋值给窗口的控件,并且可以修改数据库的值时真的不太容易

   原文地址:http://www.silverlightshow.net/items/ModalDialogs-IEditableObject-and-MVVM-in-Silverlight-4.aspx

  点击下载源程序

总结

以上是内存溢出为你收集整理的SilverLight4:在MVVM架构下实现模式窗口全部内容,希望文章能够帮你解决SilverLight4:在MVVM架构下实现模式窗口所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/1074722.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-26
下一篇2022-05-26

发表评论

登录后才能评论

评论列表(0条)

    保存