棱镜。关闭使用IDialogService创建的对话框

时间:2019-10-08 17:46:06

标签: c# wpf mvvm prism

我正在尝试使用新的IDialogService,该问题已在github问题1666. A New IDialogService for WPF中进行了讨论。我喜欢这项新功能,但找不到与InteractionRequest相比使用IDialogService的一种解决方案。

有一个按钮,按此按钮可以打开非模式对话框。如果用户再次按下同一按钮,而对话框仍然打开,则对话框关闭。应该如何以正确的方式实现这种行为?

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的名字。

2 个答案:

答案 0 :(得分:2)

您始终可以通过事件聚合器发送事件,如果一次打开多个对话框,可能必须在对话框参数中传递一些ID才能关闭右侧对话框。

但这确实很笨拙,我更愿意从IDisposable / Show中获得ShowDialog,以关闭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");

答案 1 :(得分: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();
   }
}

在我的Dialogs文件夹中的 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;
    }
}

现在在我的代码中的任何地方,在视图自定义控件的视图模型的 ViewModel 中,我唯一需要做的就是在构造函数中传递 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});