Prism. 如何关闭由IDialogService创建的对话框?

4

我正在尝试使用一个新的IDialogService,它在Github的问题1666. A New IDialogService for WPF中被讨论。我喜欢这个新功能,但是我无法找到一种解决使用IDialogService与InteractionRequest进行比较的情况的方法。

有一个按钮,按下该按钮会打开非模态对话框。 如果用户在对话框仍然打开时再次按下相同的按钮,则对话框将关闭。 应该如何以适当的方式实现这种行为?

MainWindowViewModel

public class MainWindowViewModel : BindableBase
{
    private readonly IDialogService _dialogService;
    public DelegateCommand CustomPopupCommand { get; }

    public MainWindowViewModel(IDialogService dialogService)
    {
        _dialogService = dialogService;
        CustomPopupCommand = new DelegateCommand(OpenClosePopup);
    }

    private void OpenClosePopup()
    {
        // It looks like some additional logic should be implemented here.
        // How to save previously opened IDialogAware instance and close it if needed?
        _dialogService.Show("CustomPopupView", new DialogParameters("Title=Good Title"), result => { });
    }
}


CustomPopupViewModel(自定义弹出窗口视图模型)
public class CustomPopupViewModel : BindableBase, IDialogAware
{
    private string _title;
    public string Title
    {
        get => _title;
        set => SetProperty(ref _title, value);
    }
    public DelegateCommand<object> CloseCommand { get; }

    public CustomPopupViewModel()
    {
        CloseCommand = new DelegateCommand<object>(CloseDialog);
    }

    public event Action<IDialogResult> RequestClose;

    public void OnDialogOpened(IDialogParameters parameters)
    {
        Title = parameters.GetValue<string>(nameof(Title));
    }

    public void OnDialogClosed()
    {
    }

    public bool CanCloseDialog()
    {
        return true;
    }

    public void RaiseRequestClose(IDialogResult dialogResult)
    {
        RequestClose?.Invoke(dialogResult);
    }

    private void CloseDialog(object button)
    {
        RaiseRequestClose(
            new DialogResult(button is ButtonResult buttonResult ? buttonResult : ButtonResult.Cancel));
    }
}

我不知道如何以适当的方式实现它,因为IDialogService.Show()方法完全解耦了对ViewModel和View的了解。当然,除了View的名称。

3个回答

4

你可以通过事件聚合器发送事件,可能需要在对话框参数中传递一些id,以便在同时打开多个对话框时关闭正确的对话框。

但是这种方法感觉很笨拙,我更喜欢从Show/ShowDialog获得一个IDisposable,在Dispose时关闭对话框。

public CustomPopupViewModel(IEventAggregator eventAggregator)
{
    eventAggregator.GetEvent<CloseDialogEvent>().Subscribe( id => { if (id == _id) CloseMe(); } );
}

public void OnDialogOpened(IDialogParameters parameters)
{
    _id = parameters.GetValue<string>("id");
}

_dialogService.Show("CustomPopupView", new DialogParameters("id=12345"), result => { });

_eventAggregator.GetEvent<CloseDialogEvent>().Publish("12345");

嗯...这可能是一个解决方案,但正如你所提到的有点笨重。我正在考虑使用类似于MVVMDialogs的方法,其中您可以将ViewModel传递给对话框服务,对话框服务将ViewModel设置为View的DataContext,而不是像Prism中那样使用自动连接。 - YarikM
@YarikM 是的,视图模型优先的对话框服务也是一个不错的解决方案。 - Haukinger
我遇到了同样的问题,这是关闭已打开的Prism DialogService的最佳解决方案吗?奇怪的是,在任何地方都找不到太多关于这个的信息。 - Reza
我在 GitHub 上创建了一个问题。你能否将你的用例添加到“预期用例”部分?https://github.com/PrismLibrary/Prism/issues/2007 - Haukinger
我尝试了这个,但是在对话框启动后,它甚至没有执行你代码的最后一行。它仍然在等待对话框结果。 - baye dbest
@baydbest 你是调用 Show 还是 ShowDialog?我期望后者会等待(你仍然可以从另一个线程引发事件),但 Show 不应该阻塞。 - Haukinger

0

如果我理解正确,您想在编程方式下关闭对话框窗口而不是单击Windows的关闭按钮,对吗? 如果是这样,也许我可以为您提供解决方案。 尽管这种方法不是非常简洁,但非常简单。

我的项目使用Mahapps样式,我想将MetroWindow用作DailogHost窗口。 根据Prism文档,我像这样注册DialogHost窗口和UserControl:

containerRegistry.RegisterDialogWindow<DialogHost>(nameof(DialogHost));
containerRegistry.RegisterDialog<UserEdit, UserEditViewModel>(nameof(UserEdit));

UserEidt是一个用户控件,我在UserEidt中放置了确认按钮和取消按钮,并将两个按钮绑定到UserEditViewModel中的DelegateCommand。问题是,如何通过单击取消按钮关闭dailogwindow?

这是我的解决方案,首先定义一个IDailogViewModel接口:

public interface IDialogViewModel
{
    Action CloseDialogWindow { get; set; }
}

然后,UserEditViewModel实现此接口:

public class UserEditViewModel : BindableBase, IDialogAware,IDialogViewModel
{
   public DelegateCommand CancelCmd { get; private set; }
   public Action CloseDialogWindow { get; set; }
   
   public UserEditViewModel()
   {
       CancelCmd = new DelegateCommand(CloseDialogWindow)
   }

   private void CloseDialogWindow()
   {
       CloseDialogWindow.Invoke();
   }
}

实际上,当对话框窗口弹出时,UserEdit将成为dialogWindow的内容。因此,在对话框窗口的加载事件处理程序中,我可以通过使用Window.Content获取UserEdit对象,以下是代码:
public partial class DialogHost : MetroWindow, IDialogWindow
{
    public DialogHost()
    {
        InitializeComponent();
    }

    public IDialogResult Result { get; set; }

    private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
    {
        var dialogVM = (IDialogViewModel)((UserControl)Content).DataContext;
        dialogVM.CloseDialogWindow += CloseDialogWindow;
    }

    void CloseDialogWindow()
    {
        Close();
    }
}

现在,点击取消按钮后,对话框窗口将关闭。


0

我发现使用Prism实现订阅者模式最简单。我使用一个类来实现该模式并进行通信:

public class DialogStatus
{ 
    public bool DialogResult { get; set; }
}

在我的示例中,我将展示如何使用Prism 8.0.0.1909在WPF中使用登录对话框来实现此操作。
在App.cs文件中:
protected override void OnInitialized()
{
   var login = Container.Resolve<LoginDialog>();
   var result = login.ShowDialog();
   if (result.HasValue && result.Value)
   {
       base.OnInitialized();
   }
   else
   {
      Application.Current.Shutdown();
   }
}

LoginDialog.cs 在我的对话框文件夹中

public partial class LoginDialog : Window
{
    public LoginDialog(IEventAggregator eventAggregator)
    {
        InitializeComponent();
        eventAggregator.GetEvent<CloseDialogWindowEvent>().Subscribe(OnCloseWindow);
    }

    private void OnCloseWindow(DialogStatus obj)
    {
        base.DialogResult = obj.DialogResult;
    }
}

现在在我的代码中的任何地方,在视图模型或自定义控件的视图模型中,我唯一需要做的就是在构造函数中传递IEventAggregator并将其保存在一个字段中。

private readonly IEventAggregator _eventAggregator;
public LoginControlViewModel(IAuthenticationService authenticationService
                            , IConnectFileImporterService connectFileImporterService
                            , IDialogService dialogService
                            , IEventAggregator eventAggregator)
{

   _eventAggregator= eventAggregator;
   // the other code
}

我现在可以关闭我的对话框,在这个示例中返回true,通过调用它可以从任何地方落到我的App.cs的OnInitalize中。

_eventAggregator.GetEvent<CloseDialogWindowEvent>().Publish(new CloseDialogWindowEvent() { DialogResult = true });

或者

_eventAggregator.GetEvent<CloseDialogWindowEvent>().Publish(new CloseDialogWindowEvent() { DialogResult = false});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接