我现在写MVVM中的ViewModel都会把窗体传递进来如    public class MainWindowViewModel : Z.Core.WPF.NotificationObject
    {
        private readonly Window window;
        public MainWindowViewModel(Window win)
        {
            this.window = win;
            Init();
        }
    }然后在调用的地方用        public MainWindow()
        {
            this.DataContext = new ViewModel.MainWindowViewModel(this);
            InitializeComponent();
        }为什么是要这样呢?
因为我在窗体中有一个按钮是关闭当前Window的
然后我给他绑定到我的ViewModel中的命令如:        public ICommand OnClose { get; set; }
        public void Close(EventArgs e)
        {
            if (Service.ServiceClient.Instance != null)
            {
                Service.ServiceClient.Instance.Leave();
                Service.ServiceClient.Instance.Close();
                Service.ServiceClient.Instance = null;
            }
            //this.window.Close();
        }但是这样的话在窗体里面点击关闭(不是窗口右上角的X)的时候,
只会执行我的命令内容,而不会关闭窗体(因为给程序只当他是一般命令)
然后现在我只能把窗体的对像传进来,然后在Close命令中加上
this.windows.Close()来实现关闭那正确的MVVM做法是应该怎么做谢谢

解决方案 »

  1.   

    楼主 mvvm的设计主要是为了解耦
    你把窗体传进去 和普通的写法无太大差异哦
    通常只是view引用vm 但是vm不关心view是什么 这样才能松耦合哦
    具体来时楼主可以看看事件 消息机制 mvvmlight prism 这些框架
    也许会有收获 还有 切忌不要为了mvvm而mvvm
      

  2.   


    public class SomeWindow: ChildWindow
    {
        private SomeViewModel _someViewModel;    public SomeWindow()
        {
            InitializeComponent();        this.Loaded += SomeWindow_Loaded;
            this.Closed += SomeWindow_Closed;
        }    void SomeWindow_Loaded(object sender, RoutedEventArgs e)
        {
            _someViewModel = this.DataContext as SomeViewModel;
            _someViewModel.PropertyChanged += _someViewModel_PropertyChanged;
        }    void SomeWindow_Closed(object sender, System.EventArgs e)
        {
            _someViewModel.PropertyChanged -= _someViewModel_PropertyChanged;
            this.Loaded -= SomeWindow_Loaded;
            this.Closed -= SomeWindow_Closed;
        }    void _someViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == SomeViewModel.DialogResultPropertyName)
            {
                this.DialogResult = _someViewModel.DialogResult;
            }
        }
    }
      

  3.   

    http://stackoverflow.com/questions/501886/wpf-mvvm-newbie-how-should-the-viewmodel-close-the-form
      

  4.   

    http://stackoverflow.com/questions/501886/wpf-mvvm-newbie-how-should-the-viewmodel-close-the-form
      

  5.   

    楼上的链接里各种做法都有了。整理一下:
    用CallMehothod方法:    <Button  Content="关闭" Name="btnLeave"  Height="23" FontSize="10">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <!-- 调用Window.Close会触发Closed事件,自动执行后台的OnClose命令 -->
                    <ei:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType=Window}}"  MethodName="Close" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>如果不忌讳写在code behind类中的话,可以这样: public MainWindow()
    {
    this.DataContext = new ViewModel.MainWindowViewModel();
    InitializeComponent(); this.btnLeave.Click += (o, args) => this.Close(); // 同样会自动触发执行OnClose命令
    }另外,我觉得特殊情况下,只要不违反MVVM总的原则,传个参数就传了,没什么了不起。
    只不过作为构造参数传进去,ViewModel所有的地方都能访问到UI,影响太大。
    可以把window作为Command的参数传过去,缩小它的作用范围:    <Button  Content="关闭" Name="btnLeave"  Height="23" FontSize="10"
                    Command="{Binding OnClose}"  
                    CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}" />
    后台的OnClose命令现在被两处调用(Button.Command和Window.Closed),所以要修改下: public void Close(object e)
    {
    // 这是从Window.Closed事件调用过来的
    if (e is EventArgs)
    {
    if (Service.ServiceClient.Instance != null)
    {
    Service.ServiceClient.Instance.Leave();
    Service.ServiceClient.Instance.Close();
    Service.ServiceClient.Instance = null;
    }
    }
    else if (e is Window) // 这是从Button.Command事件调用过来的
    (e as Window).Close(); // 这里会再自动触发Window.Closed事件
    }
    上面这种做法不能让正统的MVVM人士看到,因为不够纯正。