D
D
DarkByte20152016-05-17 11:20:09
WPF
DarkByte2015, 2016-05-17 11:20:09

How to get rid of InvalidOperationException?

If it's not difficult, please see the project: https://www.dropbox.com/s/7ins3osgnbyj63p/MvvmDial...
There is a lot of code. I don’t even know which one to copy here, so it’s easier to look at the project right away. In general, the project is not mine, this is an example where I downloaded it, I don’t remember where. The bottom line is to link MVVM and dialog boxes. So everything works in the project, but there is something that I would like to get rid of. There, a dialog box is created each time a new one, but I don't need it. I removed the x:Shared="False" lines in App.xaml and in the MainViewModel in the command, instead of creating a new ViewModel, I just show the already created one (I declared the field in the class). Now it turns out that the dialog box opens, then I close it and poke it open again, after which it throws me an exception "You cannot set Visibility or call Show, ShowDialog or WindowInteropHelper.EnsureHandle after closing the window." Please help me remove it!
P.S. As far as I understand, the essence of the approach used there is in this class:

using MvvmDialogs.Presenters;
using MvvmDialogs.ViewModels;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace MvvmDialogs.Behaviors
{
  public static class DialogBehavior
  {
    private static Dictionary<IDialogViewModel, Window> DialogBoxes = new Dictionary<IDialogViewModel, Window>();
    private static Dictionary<Window, NotifyCollectionChangedEventHandler> ChangeNotificationHandlers = new Dictionary<Window, NotifyCollectionChangedEventHandler>();
    private static Dictionary<ObservableCollection<IDialogViewModel>, List<IDialogViewModel>> DialogBoxViewModels = new Dictionary<ObservableCollection<IDialogViewModel>, List<IDialogViewModel>>();

    public static readonly DependencyProperty ClosingProperty = DependencyProperty.RegisterAttached(
      "Closing",
      typeof(bool),
      typeof(DialogBehavior),
      new PropertyMetadata(false));

    public static readonly DependencyProperty ClosedProperty = DependencyProperty.RegisterAttached(
      "Closed",
      typeof(bool),
      typeof(DialogBehavior),
      new PropertyMetadata(false));

    public static readonly DependencyProperty DialogViewModelsProperty = DependencyProperty.RegisterAttached(
      "DialogViewModels",
      typeof(object),
      typeof(DialogBehavior),
      new PropertyMetadata(null, OnDialogViewModelsChange));

    public static void SetDialogViewModels(DependencyObject source, object value)
    {
      source.SetValue(DialogViewModelsProperty, value);
    }

    public static object GetDialogViewModels(DependencyObject source)
    {
      return source.GetValue(DialogViewModelsProperty);
    }

    private static void OnDialogViewModelsChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      var parent = d as Window;
      if (parent == null)
        return;

      // when the parent closes we don't need to track it anymore
      parent.Closed += (s, a) => ChangeNotificationHandlers.Remove(parent);

      // otherwise create a handler for it that responds to changes to the supplied collection
      if (!ChangeNotificationHandlers.ContainsKey(parent))
        ChangeNotificationHandlers[parent] = (sender, args) =>
        {
          var collection = sender as ObservableCollection<IDialogViewModel>;
          if (collection != null)
          {
            if (args.Action == NotifyCollectionChangedAction.Add ||
              args.Action == NotifyCollectionChangedAction.Remove || 
              args.Action == NotifyCollectionChangedAction.Replace)
            {
              if (args.NewItems != null)
                foreach (IDialogViewModel viewModel in args.NewItems)
                {
                  if (!DialogBoxViewModels.ContainsKey(collection))
                    DialogBoxViewModels[collection] = new List<IDialogViewModel>();
                  DialogBoxViewModels[collection].Add(viewModel);
                  AddDialog(viewModel, collection, d as Window);
                }
              if (args.OldItems != null)
                foreach (IDialogViewModel viewModel in args.OldItems)
                {
                  RemoveDialog(viewModel);
                  DialogBoxViewModels[collection].Remove(viewModel);
                  if (DialogBoxViewModels[collection].Count == 0)
                    DialogBoxViewModels.Remove(collection);
                }
            }
            else if (args.Action == NotifyCollectionChangedAction.Reset)
            {
              // a reset event is typically generated in response to clearing the collection.
              // unfortunately the framework doesn't provide us with the list of items being
              // removed which is why we have to keep a mirror in DialogBoxViewModels
              if (DialogBoxViewModels.ContainsKey(collection))
              {
                var viewModels = DialogBoxViewModels[collection];
                foreach (var viewModel in DialogBoxViewModels[collection])
                  RemoveDialog(viewModel);
                DialogBoxViewModels.Remove(collection);
              }
            }
          }
        };

      // when the collection is first bound to this property we should create any initial
      // dialogs the user may have added in the main view model's constructor
      var newCollection = e.NewValue as ObservableCollection<IDialogViewModel>;
      if (newCollection != null)
      {
        newCollection.CollectionChanged += ChangeNotificationHandlers[parent];
        foreach (IDialogViewModel viewModel in newCollection.ToList())
          AddDialog(viewModel, newCollection, d as Window);
      }

      // when we remove the binding we need to shut down any dialogs that have been left open
      var oldCollection = e.OldValue as ObservableCollection<IDialogViewModel>;
      if (oldCollection != null)
      {
        oldCollection.CollectionChanged -= ChangeNotificationHandlers[parent];
        foreach (IDialogViewModel viewModel in oldCollection.ToList())
          RemoveDialog(viewModel);
      }
    }

    private static void AddDialog(IDialogViewModel viewModel, ObservableCollection<IDialogViewModel> collection, Window owner)
    {
      // find the global resource that has been keyed to this view model type
      var resource = Application.Current.TryFindResource(viewModel.GetType());
      if (resource == null)
        return;

      // is this resource a presenter?
      if (IsAssignableToGenericType(resource.GetType(), typeof(IDialogBoxPresenter<>)))
      {
        resource.GetType().GetMethod("Show").Invoke(resource, new object[] { viewModel });
        collection.Remove(viewModel);
      }

      // is this resource a dialog box window?
      else if (resource is Window)
      {
        var userViewModel = viewModel as IUserDialogViewModel;
        if (userViewModel == null)
          return;
        var dialog = resource as Window;
        dialog.DataContext = userViewModel;
        DialogBoxes[userViewModel] = dialog;
        userViewModel.DialogClosing += (sender, args) =>
          collection.Remove(sender as IUserDialogViewModel);
        dialog.Closing += (sender, args) =>
        {
          if (!(bool)dialog.GetValue(ClosingProperty))
          {
            dialog.SetValue(ClosingProperty, true);
            userViewModel.RequestClose();
            if (!(bool)dialog.GetValue(ClosedProperty))
            {
              args.Cancel = true;
              dialog.SetValue(ClosingProperty, false);
            }
          }
        };
        dialog.Closed += (sender, args) =>
        {
          Debug.Assert(DialogBoxes.ContainsKey(userViewModel));
          DialogBoxes.Remove(userViewModel);
          return;
        };
        dialog.Owner = owner;
        if (userViewModel.IsModal)
          dialog.ShowDialog();
        else
          dialog.Show();
      }
    }

    private static void RemoveDialog(IDialogViewModel viewModel)
    {
      if (DialogBoxes.ContainsKey(viewModel))
      {
        var dialog = DialogBoxes[viewModel];
        if (!(bool)dialog.GetValue(ClosingProperty))
        {
          dialog.SetValue(ClosingProperty, true);
          DialogBoxes[viewModel].Close();
        }
        dialog.SetValue(ClosedProperty, true);
      }
    }
    

    // courtesy James Fraumeni/StackOverflow: http://stackoverflow.com/questions/74616/how-to-detect-if-type-is-another-generic-type/1075059#1075059
    private static bool IsAssignableToGenericType(Type givenType, Type genericType)
    {
      var interfaceTypes = givenType.GetInterfaces();

      foreach (var it in interfaceTypes)
      {
        if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
          return true;
      }

      if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
        return true;

      Type baseType = givenType.BaseType;
      if (baseType == null) return false;

      return IsAssignableToGenericType(baseType, genericType);
    }
  }

}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
akass, 2016-05-17
@akass

So everything is right, how will he show it to you if you closed it?
As an option, you can handle the closing of the window and hide it instead of closing it.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question