从MVVM中的ViewModel关闭视图

时间:2014-04-28 10:33:29

标签: wpf mvvm

我有一个浮动窗口模板,我在其中通过初始化MessageBoxViewModel对象来加载一个消息框以显示消息

我想在用户点击“关闭”按钮时关闭此弹出窗口。我该怎么做 我在MessageBoxViewModel中编写了Close按钮命令。

 public class MessageBoxViewModel : ViewModelBase
{

    public MessageBoxViewModel ( string messageText)
    {
        //  load all the fields
    }




    }
    private string message;

    public string Message
    {
        get
        {
            return message;
        }
        set
        {
            if (value == message)
                return;
            message = value;
            base.OnPropertyChanged("Message");
        }
    }

    #region Commands

    RelayCommand okay;
    public ICommand OKAY
    {
        get
        {
            if (okay == null)
            {
                okay = new RelayCommand(
                    param => this.CallOkay()
                    );
            }
            return okay;
        }
    }

    #endregion

    void CallOkay()
    {
      //  should write logic to close this window

    }

3 个答案:

答案 0 :(得分:0)

MVVM的本质规定模型对正在读取它的窗口一无所知。

解决方案是视图模型抛出一个事件供Window处理。

在您的视图模型代码中:

public event EventHandler CallOkayRequested;

void CallOkay()
{
  var dg = this.CallOkayRequested;
  if(dg != null) 
  {
     dg(this, EventArgs.Empty);
  }

}

在您的窗口代码中,处理此事件:

MyMessageBox() 
{
   InitializeComponent();
   ((MessageBoxViewModel)this.DataContext).CallOkayRequested += ModelCallOkayRequested;
}

void ModelCallOkayRequested(object sender, EventArgs args)
{
     this.Close();
}

这可能是最好的方法,例如,如果视图模型在想要关闭对话框之前执行其他一些操作。

<小时/> 但是,如果视图模型除了中继请求之外什么都不做,那么如果您完全绕过模型并使用标准RoutedUICommand,则代码更少。

在您的XAML中声明命令绑定:

<Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.Close" Executed="CloseCommandExecuted" />
</Window.CommandBindings>

将此命令附加到您的按钮:

    <Button Command="ApplicationCommands.Close">
        Close
    </Button>

并在窗口代码中处理close方法:

private void CloseCommandExecuted(object sender, EventArgs args)
{
     this.Close();
}

答案 1 :(得分:0)

Sriram Sakthivel的评论中提到了很多方法。但使用视图模型事件最简单:

public event Action ViewModelClosed;
void CallOkay()
{
    if (ViewModelClosed != null) ViewModelClosed();
}

在MessageBox的代码中:

...
MessageBoxViewModel vm = new MessageBoxViewModel();
vm.ViewModelClosed += () => this.Close();

另一种方式:

我总是在我的视图中使用一层消息框,如下所示:

<UserControl>
    <Grid>
        <Border>
            <!-- contents of my control -->
        </Border>
        <Border Visibility="{Binding IsVisible, 
                Converter={StaticResource BooleanToVisibilityConverter}}" 
                Background="#4000">
            <!-- contents of my message box -->
        </Border>
    </Grid>
</UserControl>

将一个布尔(IsVisible)属性添加到MessageBoxViewModel并将MessageBox的Visibility绑定到它。然后只需在CallOkay()

中更改其值

答案 2 :(得分:0)

另一个MVVM框架使用的方法(Caliburn Micro)实际上只是使用来自VM的事件。

然而,为了将想法扩展到可重用的“模块”,Caliburn Micro使用Conductor类来管理View的生命周期与ViewModel的生命周期之间的关系。 ViewModel上的一个接口将其标记为“可关闭”,并且您需要编写特定于您正在使用的窗口/对话框实现的指挥(假设它不是标准Window的子类)。

在代码中的某处,您必须创建一个窗口并将其绑定到viewmodel。这是创建导体以管理关系的地方(Caliburn在其IWindowManager实现中具有此功能,当Window / {{ShowPopup实现时,ShowDialog实例提供并绑定public class WindowConductor { private ISupportClose _closeable; private Window _window; private bool _closingFromViewModel; private bool _closingFromView; public WindowConductor(Window view, ISupportClose closeable) { _closeable = closeable; _window = view; _window.Closed += WindowClosed; _closeable.Closed += ViewModelClosed; } public void WindowClosed(object sender, EventArgs e) { if(_closingFromViewModel) return; _closingFromView = true; closeable.Close(); } public void ViewModelClosed(object sender, EventArgs e) { if(_closingFromView) return; _closingFromViewModel = true; window.Close(); } } 实例1}}方法被称为

指挥可能看起来像(一个人为的例子):

ISupportClose

您的public interface ISupportClose { event EventHandler<CloseEventArgs> Closed; void Close(); } 界面可以是:

public void CreateWindow(viewModel) 
{
    Window window = new Window();
    window.DataContext .. // etc etc bind up the view/model

    // Wrap the window/vm with the conductor if the view supports the interface
    var closeable = viewModel as ISupportClose;

    if(closeable != null)
        new WindowConductor(window, closeable);
}

然后,当您创建窗口以显示VM的视图时:

Screen

我总觉得这非常有用,因为它将问题分成了更小的块。无论如何,您通常不会在应用程序中使用超过1个窗口的实现。

可能值得注意的是,所有这些背后都有一些管道代码(实际上基类{{1}}提供了生命周期管理的标准实现等)。

如果你没有使用MVVM框架,我强烈建议你这样做 - 编写样板'胶水'已经由多个框架完成了