Если не трудно посмотрите пожалуйста проект:
https://www.dropbox.com/s/7ins3osgnbyj63p/MvvmDial...
Кода очень много. Я даже не знаю какой именно сюда скопировать, поэтому проще проект глянуть сразу. В общем то проект не мой, это пример где то я его скачал уже не помню где. Суть в том чтобы увязать MVVM и диалоговые окна. Так вот в проекте все работает, но там есть то от чего мне хотелось бы избавиться. Там диалоговое окно создается каждый раз новое, а мне это не нужно. Я убрал в App.xaml строки x:Shared="False" и в MainViewModel в команде вместо создания новой ViewModel-и просто показываю уже созданную (полем объявил в классе). Теперь получается так диалоговое окно открывается, потом я его закрываю и тыкаю еще раз открыть, после чего оно бросает мне исключение "Нельзя задать Visibility или вызвать Show, ShowDialog или WindowInteropHelper.EnsureHandle после закрытия окна." Помогите его убрать пожалуйста!
П.С. Насколько я понял самая суть использованного там подхода вот в этом классе:
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);
}
}
}