提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
转帖|其它|编辑:郝浩|2011-01-06 16:45:37.000|阅读 1208 次
概述:要在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@pclwef.cn
文章转载自:网络转载面对“数字中国”建设和中国制造2025战略实施的机遇期,中车信息公司紧跟时代的步伐,以“集约化、专业化、标准化、精益化、一体化、平台化”为工作目标,大力推进信息服务、工业软件等核心产品及业务的发展。在慧都3D解决方案的实施下,清软英泰建成了多模型来源的综合轻量化显示平台、实现文件不失真的百倍压缩比、针对模型中的大模型文件,在展示平台上进行流畅展示,提升工作效率,优化了使用体验。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@pclwef.cn
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢