2

I am currently using MVVM (Light) to build an application with WPF. However, in a few cases I must open a new dialog (also WPF) when the user clicks a button. However, this is being a tough fight.

Here is how I am doing it:

    private void _ShowItemDialog(Item item)
    {
        var itemVM = new ItemViewModel();
        itemVM.CurrentItem = item ?? new Item();
        itemVM.Load();

        var itemView = new View.ItemView() { DataContext = itemVM };
        if (itemView.ShowDialog() == true)
        {
            if (item == null)
            {
                itemList.Add(itemVM.CurrentItem);
            }
        }

        itemVM.Cleanup();
    }

And the itemView XAML there is no binding to the DataContext, otherwise two different instances of the ViewModel would be created.

Inside the Window tag. To have the result at ShowDialog, I use the DialogCloser code:

    public static class DialogCloser
    {
        public static readonly DependencyProperty DialogResultProperty =
            DependencyProperty.RegisterAttached(
                "DialogResult",
                typeof(bool?),
                typeof(DialogCloser),
                new PropertyMetadata(DialogResultChanged));

        private static void DialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window != null)
                window.DialogResult = e.NewValue as bool?;
        }

        public static void SetDialogResult(Window target, bool? value)
        {
            target.SetValue(DialogResultProperty, value);
        }
    }

In the ItemView, this is declared inside Window tag as follows:

my:DialogCloser.DialogResult="{Binding DialogResult}"

And when the dialog is closed, the closing event sets DialogResult to true or false.

This works perfectly for the first time the screen is opened, but it is not possible to open the dialog again after it is closed.

I would like to know if you have any better ideas for opening the dialog, and why this code does not work.

Thanks!

EDIT: I have already fixed the code. What I need to do is create a new ViewModel and attach it to the DataContext every time the dialog is opened. Moreover, I had to remove the DataContext binding from XAML. Please check the code changes above.

With these changes I have found out that it is not possible to use the ViewModel from ViewModelLocator because it is a "singleton" and not a new instance at each new window. Therefore, the DialogResult held the last value and if I tried to change its value back to null (as it is when the ViewModel is initialized) an exception is thrown. Do you have any clues of why this happens? It would be very good for me to use the ViewModel from ViewModelLocator, since it would keep the same strategy throughout the system.

Thank you!

jpnavarini
  • 763
  • 4
  • 13
  • 25
  • I am not sure if I get you right. To create a new ViewModel instance for your View, every time your View is generated, you can create an instance of your ViewModel in the Views code behind and set the Views DataContext to that new generated ViewModel. – Andre Aug 07 '12 at 13:03
  • @Andre I would not like to create a new ViewModel for each View. It is exactly the oposite. I would like to use the ViewModel singleton, however I don't understand why using the same instance for new windows opened does not work. Moreover, why can't I "erase" the DialogResult? – jpnavarini Aug 07 '12 at 14:03

2 Answers2

0

I do that by implementing static XxxxInteraction classes that have methods called for example NewUser(); That methods opens the Dialogs and do some work. In my ViewModel I call the XxxxInteraction classes via commands.

The efforts of that way of implementing is, that you can easely modify the methods in the static Interaction classes for using UnitTests.

    public static class UserInteractions
    {
        public static User NewUser()
        {
            var userDialog = new NewUserDialog();
            If(userDialog.ShowDialog() != true) return null;

            var user = new User();
            user.Name = userDialog.Name;
            user.Age = userDialog.Age;
            return user;
        }
    }

    public class MyViewModel
    {
        ...

        public void NewUserCommandExecute()
        {
            var newUser = UserInteractions.NewUser();
            if(newUser == null) return;

            //Do some with new created user
        }
    }

NewUserDialog is a normal Window that is bound to a ViewModel too.

I think this is a good way of implementing dialogs for the mvvm pattern.

Andre
  • 1,044
  • 1
  • 11
  • 23
  • No, I have unit tests for that static methods (I actually dont create an instance of the wpf windows in that methods, i have an other class that does that for me - AskUser.XXX). – Andre Aug 07 '12 at 06:38
  • Please, take a look at the Edit part added in my post. Thank you. – jpnavarini Aug 07 '12 at 12:28
0

i've done this a while ago, i use a dialog service and call this service in my viewmodel. take a look.

EDIT: btw, thats all you have to do in your viewmodel

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
Community
  • 1
  • 1
blindmeis
  • 22,175
  • 7
  • 55
  • 74