wpf 柱形图,关闭使用IDialogService创建的对话框

oalqel3c  于 2022-12-19  发布在  其他
关注(0)|答案(3)|浏览(374)

我正在尝试使用一个新的IDialogService,这在github的1666. A New IDialogService for WPF期中讨论过。我喜欢这个新特性,但是我找不到一个解决方案来解决使用IDialogService与InteractionRequest相比的问题。
有一个按钮,按下它会打开非模态对话框。如果用户再次按下同一个按钮,而对话框仍然打开,对话框关闭。应该如何以正确的方式实现此行为?

主窗口视图模型

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 => { });
    }
}

自定义弹出视图模型

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的名称除外。

jq6vz3qz

jq6vz3qz1#

你总是可以通过事件聚合器发送一个事件,如果一次打开多个对话框,你可能需要在对话框参数中传递一些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");
hec6srdp

hec6srdp2#

我发现使用订户模式的Prism实现是最简单的,我使用了一个将在模式中使用并进行通信的类:

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

在我的示例中,我将向您展示如何使用Prism 8.0.0.1909在WPF中使用登录对话框来执行此操作

在应用程序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;
    }
}

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

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

   _eventAggregator= eventAggregator;
   // the other code
}

现在,我可以关闭对话框,并在此示例中,通过调用以下命令,从任何位置将falls返回到App.cs中的OnInitalize

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

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

798qvoo83#

如果我没理解错的话,你想用编程的方式来关闭日志窗口,而不是点击窗口的关闭按钮,对吗?如果是这样的话,也许我可以为你提供一个解决方案。虽然这个方法不是很优雅,但它非常简单。
我的项目使用mahapps风格,我想使用metrowindow作为dailoghost窗口。根据prism文档,我注册了dailoghost窗口和用户控件,如下所示:

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

UserEidt是一个用户控件,我在UserEidt中放置了一个确认按钮和一个取消按钮,并且这两个按钮都绑定了UserEditViewModel中的DelegateCommand。问题是,如何通过单击取消按钮来关闭日志窗口?
下面是我的解决方案,首先定义一个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的内容,所以在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();
    }
}

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

相关问题