Ответ 1
Это еще проще, если ваша модель просмотра расширяет Caliburn.Micro.Screen
:
TryClose();
У меня есть ViewModel1
и View1, связанные с ним. Я запускаю диалоговое окно из ViewModel2
(некоторая другая модель) с помощью объекта IWindowManager
. Код из ViewModel2
class:
windowManager.ShowDialog(new ViewModel());
Итак, у меня есть диалоговое окно с пользовательским элементом управления View1.
Мой ответ следующий - я могу закрыть это диалоговое окно, используя красную кнопку закрытия, но как закрыть его с помощью моей конкретной кнопки (содержится в пользовательском элементе View1
), что-то вроде кнопки "Отмена" с закрытой командой (Command={Binding CancelCommand}
), CancelCommand
, конечно, содержится в классе ViewModel1
.
Это еще проще, если ваша модель просмотра расширяет Caliburn.Micro.Screen
:
TryClose();
Вы можете получить текущее представление (в вашем случае диалоговое окно) с реализацией интерфейса IViewAware
на вашем ViewModel. Затем вы можете вызвать Close
в представлении (Window
, созданный как диалог), когда ваша команда выполнена.
Самый простой способ - извлечь из ViewAware
:
public class DialogViewModel : ViewAware
{
public void ExecuteCancelCommand()
{
(GetView() as Window).Close();
}
}
Если вам не разрешено выводить, вы можете реализовать его самостоятельно:
public class DialogViewModel : IViewAware
{
public void ExecuteCancelCommand()
{
dialogWindow.Close();
}
private Window dialogWindow;
public void AttachView(object view, object context = null)
{
dialogWindow = view as Window;
if (ViewAttached != null)
ViewAttached(this,
new ViewAttachedEventArgs(){Context = context, View = view});
}
public object GetView(object context = null)
{
return dialogWindow;
}
public event EventHandler<ViewAttachedEventArgs> ViewAttached;
}
Примечание. Я использовал Caliburn.Micro 1.3.1 для своего образца.
Более чистый способ (тема личного вкуса), который я использую много, - использовать шаблон IResult, таким образом, вы абстрагиваете реализацию окна
ViewModel
public IEnumerable<IResult> CloseMe()
{
yield return new CloseResult();
}
Код результата
public class CloseResult : Result
{
public override void Execute(ActionExecutionContext context)
{
var window = Window.GetWindow(context.View);
window.Close();
base.Execute(context);
}
}
public abstract class Result : IResult
{
public virtual void Execute(ActionExecutionContext context)
{
OnCompleted(this, new ResultCompletionEventArgs());
}
protected virtual void OnCompleted(object sender, ResultCompletionEventArgs e)
{
if (Completed != null)
Completed(sender, e);
}
public event EventHandler<ResultCompletionEventArgs> Completed;
}
edit (требуется только для IoC). Если вы хотите сделать это еще дальше, вы делаете базовый класс для всех экранов
public abstract class ShellPresentationModel : Screen
{
public ShellPresentationModel(IResultFactory resultFactory)
{
Result = resultFactory;
}
public IResultFactory Result { get; private set; }
}
Таким образом, вы можете легче вложить зависимости с IoC, тогда ваш метод закрытия VIewmodel будет выглядеть следующим образом:
public IEnumerable<IResult> CloseMe()
{
yield return Result.Close();
}
Пример в IResult, который использует зависимость, может быть
public class ShowDialogResult<TModel> : Result
{
private readonly IWindowManager windowManager;
private readonly TModel model;
private Action<TModel> configure;
public ShowDialogResult(IWindowManager windowManager, TModel model)
{
this.windowManager = windowManager;
this.model = model;
}
public IResult Configure(Action<TModel> configure)
{
this.configure = configure;
return this;
}
public override void Execute(ActionExecutionContext context)
{
if(configure != null)
configure(model);
windowManager.ShowDialog(model);
base.Execute(context);
}
}
edit Только что заметил, что я забыл добавить пример вышеприведенного IoC exmaple, здесь идет С детским шаблоном контейнера IoC это будет выглядеть как
public IEnumerable<IResult> ShowDialog()
{
yield return Result.ShowDialog<MyViewModel>();
}
Без шаблона дочернего контейнера вам нужно будет вручную ввести parent dependeync в дочерний элемент
yield return Result.ShowDialog<MyViewModel>().Configure(m => m.SomeData = this.SomeData);