1

In my project I have a child window, multiple instances of which can be open at a time. They take in an instance of an object, display information about it, and return information about it. Right now it's working but I have to close the window with the 'X' in the top corner. I would like to be able to close the windows with 'Accept' and 'Cancel' buttons. Should I click accept, I would like to have MVVM Light's messenger send back the appropriate data (which is already functional) and close the window. If I click 'cancel' the changes should be discarded and the window closed. Unfortunately I don't know of a good (and MVVM-friendly) way to close the windows using buttons. I have looked into using commands to no avail and I'm not sure how to go about this. Any help would be appreciated. I don't really know what code to post in this situation...

<Button x:Name="btnAccept"
          Grid.Row="2"
          Grid.Column="1"
          Content="Accept"
          Command="{Binding AcceptCommand}"/>
<Button x:Name="btnCancel"
          Grid.Row="2"
          Grid.Column="2"
          Content="Cancel" />

    private void ExecuteAcceptCommand()
    {
        Messenger.Default.Send(Adv.Name); 

        //Close the window here somehow?
    }
Jason D
  • 2,634
  • 6
  • 33
  • 67
  • Introducing the MVVM abstraction allows you to test the view state and behavior. This really isn't something you would test and as such is best handled in code behind. – Ritch Melton Jun 08 '13 at 23:14
  • I wouldn't be opposed at all to using code-behind in this situation. If you'd be willing to propose an answer that would get this to work I'd gladly accept it. – Jason D Jun 08 '13 at 23:16
  • Actually, the message the Messenger sends relies on data from the ViewModel, so I can't close the window completely from code-behind. – Jason D Jun 08 '13 at 23:28

2 Answers2

2
public class WindowClass
{
    public WindowClass()
    {
       var messenger = ServiceLocator.Current.GetInstance<IMessenger>();
       messenger.Register<CloseWindowMessage>(this, _ => Close());
    }
}

Where CloseWindowMessage is

public class CloseWindowMessage : MessageBase {}
Ritch Melton
  • 11,498
  • 4
  • 41
  • 54
  • What framework is this designed for? `ServiceLocator` does not have a .Get property for me. – Jason D Jun 09 '13 at 01:40
  • That was out of my head. Many implementations are different. Since you are probably using Simple Ioc with MVVM Light I updated my answer. – Ritch Melton Jun 09 '13 at 01:45
  • Thanks for the update. For `CloseWindowMessage`, I assume I need to make a class for that. Is there anything in particular that I need to include? – Jason D Jun 09 '13 at 01:52
  • You can pass data with the Message class that you create but I tend not to pass data with my messages out of personal choice. I prefer to get my data from whatever class is responsible for it. – Ritch Melton Jun 09 '13 at 01:53
  • VS isn't recognizing `CloseWindowMessage`, that's why I thought I had to use a custom class. – Jason D Jun 09 '13 at 01:57
  • Right, you'll have to declare/define it. – Ritch Melton Jun 09 '13 at 01:57
  • I created the class originally and inherited from `MessageBase` but now I get an error saying "No overload for method 'Register' takes 1 argument'. – Jason D Jun 09 '13 at 02:01
  • I assumed you knew the syntax. I'll check the MVVM Light implementation and update it. – Ritch Melton Jun 09 '13 at 02:06
  • When I use the code in the answer you proposed, the child window won't open and the program crashes. When I use `Messenger.Default.Register(this, _ => Close());`, the command works but it closes all open child windows. – Jason D Jun 09 '13 at 06:09
  • Also, I've been looking into tokens but haven't managed to get them to work for this scenario. – Jason D Jun 09 '13 at 06:22
  • I assumed you were putting your messenger instance in the IoC Container which it is not and that is why you are getting the exceptions. You could make a unique message for each window or use tokens or put some logic in the window to see if its visible or any number of other things. The general takeaway here is that you can send a message to make the window close and that technique makes your VM testable (which is the original goal of the MVVM abstraction). – Ritch Melton Jun 09 '13 at 20:38
  • There are a handful of other ways that don't involve sending messages. You can have your window fetch the VM from your container and add a click handler in the codebehind. The handler then inspects the vm state to see if that particular window should close. Again, this is a general technique and specifics are up to you. – Ritch Melton Jun 09 '13 at 20:40
  • Thanks for all of your help; I certainly do appreciate it. Everything seems to be in working order now. – Jason D Jun 09 '13 at 21:28
0

If multiple child windows register for same type of message,

You need to make sure that this message is only received by correct child window or all child windows will receive same message, but only the right one will close. In this case, the message needs to contain a property that has correct value to let child window to determine if it is the one to close.

MVVMLight has facility called "token" when you register or send message.

Check this out:

How to send message to one view of many

Community
  • 1
  • 1
flyfrog
  • 752
  • 1
  • 6
  • 7