从原则上说ViewModel中不应该获取View的信息,但是事实是在特殊场合需要,比如正确提交后需要关闭判断,如果ViewModel+View的后置代码实现比较麻烦,希望在ViewModel中一并完成。我在网上看到MVVM Light框架中有一种方法可以实现,但必须使用它的dll,为了尽量少用第三方dll的情况下。我使用了自己的方式来实现。 OK,现在就介绍一下我的经验。

MVVM中轻松实现Command绑定(三)中,我介绍了一种万能Command绑定,我们就利用这个进行扩展。现在,就实现关闭窗口时Window.Closing事件的额外参数中允许取消关闭。

实现思路:
1.在窗体加载时,将Window作为参数传递到ViewModel中;
2.在ViewModel中添加Window的Closing事件,此时就能得到EventArgs参数;
3.当窗体触发Closing事件时,ViewModel中定义的事件处理方法就能起效。

步骤:
1.Window窗体的xaml,注意<i:Interaction>需要使用Blend的System.Windows.Interactivity.dll文件。在Loaded事件中传递了window参数,该参数是<Window>的Name或者x:Name。

  1. <Window x:Class="WpfApplication1.Window3_EventArgs" 
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.         xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
  5.         xmlns:vm="clr-namespace:WpfApplication1" 
  6.         Title="Window3_EventArgs" Height="300" Width="300" 
  7.         x:Name="window"> 
  8.     <Window.DataContext> 
  9.         <vm:Window3_ViewModel /> 
  10.     </Window.DataContext> 
  11.     <Grid> 
  12.         <TextBlock Text="请点击关Closing" /> 
  13.     </Grid> 
  14.     <i:Interaction.Triggers> 
  15.         <i:EventTrigger EventName="Loaded"> 
  16.             <i:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=window}" /> 
  17.         </i:EventTrigger> 
  18.     </i:Interaction.Triggers> 
  19. </Window> 
<Window x:Class="WpfApplication1.Window3_EventArgs"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
		xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
		xmlns:vm="clr-namespace:WpfApplication1"
        Title="Window3_EventArgs" Height="300" Width="300"
		x:Name="window">
	<Window.DataContext>
		<vm:Window3_ViewModel />
	</Window.DataContext>
	<Grid>
		<TextBlock Text="请点击关Closing" />
	</Grid>
	<i:Interaction.Triggers>
		<i:EventTrigger EventName="Loaded">
			<i:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=window}" />
		</i:EventTrigger>
	</i:Interaction.Triggers>
</Window>


2.ViewModel,注意DelegateCommand需要Prism中的Microsoft.Practices.Prism.dll。在LoadedCommand中给win添加Closing事件。
注:Closing事件我采用的Lambda委托的语法,sender和e分别是该事件的两个参数,该事件完整签名是void win_Closing(object sender, System.ComponentModel.CancelEventArgs e) 。当然如果你需要的话,可以写成方法。

  1. public class Window3_ViewModel { 
  2.     public ICommand LoadedCommand { 
  3.         get
  4.             return new DelegateCommand<Window>(win => { 
  5.                 win.Closing += (sender, e) => { 
  6.                     if (MessageBox.Show("确认要关闭窗口吗?", "提示", MessageBoxButton.YesNo) == MessageBoxResult.No) { 
  7.                         e.Cancel = true
  8.                     } 
  9.                 }; 
  10.             }); 
  11.         } 
  12.     } 
public class Window3_ViewModel {
	public ICommand LoadedCommand {
		get {
			return new DelegateCommand<Window>(win => {
				win.Closing += (sender, e) => {
					if (MessageBox.Show("确认要关闭窗口吗?", "提示", MessageBoxButton.YesNo) == MessageBoxResult.No) {
						e.Cancel = true;
					}
				};
			});
		}
	}
}


运行效果如图:

posted on 2012-10-08 13:04  swarb  阅读(217)  评论(0编辑  收藏  举报