简体   繁体   English

使用 ReactiveUi 命令显示 Mahapps.Metro 对话框时出现问题

[英]Trouble with showing a Mahapps.Metro Dialog with a ReactiveUi Command

I am trying to use the Mahapps dialog boxes in my project but have been unable to get them to work when trigger from a ReactivUI command in my ViewModel.In the view's XAML, I have registered the dialog.我正在尝试在我的项目中使用 Mahapps 对话框,但是当从我的 ViewModel 中的 ReactivUI 命令触发时无法让它们工作。在视图的 XAML 中,我已经注册了对话框。

 xmlns:dialogs="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
    dialogs:DialogParticipation.Register="{Binding}"

I also have a button which is bound to the ShowDialog command.我还有一个绑定到 ShowDialog 命令的按钮。

this.BindCommand(viewModel, vm => vm.ShowDialog, x => x.button);

Finally, in my ViewModel, I have the RxUI command and the dialogcoordinator instance set.最后,在我的 ViewModel 中,我设置了 RxUI 命令和 dialogcoordinator 实例。

 public MainWindowViewModel(IDialogCoordinator dialogCoordinator)
    {

        _dialogCoordinator = dialogCoordinator;

        ShowDialog = ReactiveCommand.CreateFromTask(async () =>
        {
            await _dialogCoordinator.ShowMessageAsync(this, "Message from VM", "MVVM based dialogs!");
        });

        ShowDialog.ThrownExceptions.Subscribe(ex => Console.WriteLine(ex.ToString()));

    }

No matter what I have tried it always throw the same error which is无论我尝试过什么,它总是抛出相同的错误

System.InvalidOperationException: Context is not registered. Consider using DialogParticipation.Register in XAML to bind in the DataContext.

I am not sure if there is anything else needed to get the dialog to work or if I am just using the commands in RxUI incorrectly我不确定是否还需要其他任何东西才能使对话框正常工作,或者我是否只是错误地使用了 RxUI 中的命令

I had the same problem with another MVVM framework (MVVM Light Toolkit).我在另一个 MVVM 框架(MVVM Light Toolkit)上遇到了同样的问题。 But the framework doesn't seem the problem.但是框架似乎不是问题。 It's a matter of timing.这是时间问题。 The DialogCoordinator isn't accessable from the constructor. DialogCoordinator 不能从构造函数访问。 I personally moved all the code from the constructor to RelayCommand that is being fired我个人将所有代码从构造函数移动到正在被触发的 RelayCommand

<controls:MetroWindow
x:Class="UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
dialog:DialogParticipation.Register="{Binding}"
DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
d:DataContext="{d:DesignInstance vm:MainViewModel}"
mc:Ignorable="d">
<i:Interaction.Triggers>
    <i:EventTrigger EventName="ContentRendered">
        <i:InvokeCommandAction Command="{Binding StartupCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

I tried different events like Loaded, which worked in some cases but "ContentRendered" always worked in the VM I have the following code:我尝试了不同的事件,例如 Loaded,它在某些情况下有效,但“ContentRendered”始终在 VM 中有效,我有以下代码:

    public ICommand StartupCommand
    {
        get
        {
            return new RelayCommand(async ()=>
            {
                this.AccountName = await
                        dialogCoordinator.ShowInputAsync(this, "Welcome", "Please insert your account name");                    
            });
        }
    }

So basically it seems to be not yet registered directly but after the content is loaded it is.所以基本上它似乎还没有直接注册,但在加载内容后它是。 (In this example i used ShowInputAsync but it should work the same with ShowMessageAsync) (在这个例子中,我使用了 ShowInputAsync 但它应该与 ShowMessageAsync 一样工作)

It does seem to be a timing issue - when I first started playing with this, I got it to work by setting the VM's DialogCoordinator instance from the View's Loaded event, rather than it's constructor.这似乎是一个时间问题 - 当我第一次开始玩这个时,我通过从 View 的 Loaded 事件而不是它的构造函数设置 VM 的 DialogCoordinator 实例来让它工作。

I've put together a minimal working application demonstrating this at https://github.com/dwarry/ReactiveUiMahAppsDialog .我已经在https://github.com/dwarry/ReactiveUiMahAppsDialog 上组合了一个最小的工作应用程序来演示这一点。 It uses ReactiveUi's normal Interaction mechanism to trigger displaying the dialog.它使用 ReactiveUi 的正常交互机制来触发显示对话框。 In keeping with that, I've put this in the View, but I don't see why it couldn't be adapted to do it from the ViewModel if you'd rather.与此保持一致,我已将其放在视图中,但我不明白为什么如果您愿意,它不能适应从 ViewModel 执行此操作。 One other thing to be aware of is that you need to wait for the dialog to close before leaving the Interaction Handler, or ReactiveUI will throw an UnhandledInteractionException.要注意的另一件事是,您需要在离开交互处理程序之前等待对话框关闭,否则 ReactiveUI 将抛出 UnhandledInteractionException。

For me, using the ContentRendered event did not do anything;对我来说,使用ContentRendered事件没有做任何事情; I still got the exception InvalidOperationException: Context is not registered. Consider using DialogParticipation.Register in XAML to bind in the DataContext我仍然收到异常InvalidOperationException: Context is not registered. Consider using DialogParticipation.Register in XAML to bind in the DataContext InvalidOperationException: Context is not registered. Consider using DialogParticipation.Register in XAML to bind in the DataContext . InvalidOperationException: Context is not registered. Consider using DialogParticipation.Register in XAML to bind in the DataContext

I based my solution on Kent Boogaart's book samples .我的解决方案基于 Kent Boogaart 的书籍样本

View:看法:

using System.Reactive;
using System.Reactive.Disposables;
using System.Windows;
using MahApps.Metro.Controls;
using MahApps.Metro.Controls.Dialogs;
using ReactiveUI;
using Splat;

namespace ReactiveUIMahAppsDialog
{
    public partial class ChildView
    {
        public ChildView()
        {
            InitializeComponent();

            this.WhenActivated(disposables =>
            {
                ViewModel ??= Locator.Current.GetService<ChildViewModel>() ?? new ChildViewModel();

                this.BindCommand(ViewModel,
                        viewModel => viewModel.LogInUser,
                        view => view.Test)
                    .DisposeWith(disposables);

                this.ViewModel.Message
                    .RegisterHandler(async interaction =>
                    {
                        MetroWindow window = (MetroWindow) Window.GetWindow(this);

                        await window.ShowMessageAsync("test", "test");

                        interaction.SetOutput(Unit.Default);
                    })
                    .DisposeWith(disposables);
            });
        }
    }
}

<reactiveUi:ReactiveUserControl
    x:Class="ReactiveUIMahAppsDialog.ChildView"
    x:TypeArguments="viewModels:ChildViewModel"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:reactiveUi="http://reactiveui.net"
    xmlns:viewModels="clr-namespace:ReactiveUIMahAppsDialog"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Button x:Name="Test" Content="Show Dialog" Width="100" Height="100"/>
    </Grid>
</reactiveUi:ReactiveUserControl>

Host the reactive user control in a MetroWindow .MetroWindow托管反应式用户控件。

ViewModel:视图模型:

using System.Reactive;
using System.Reactive.Linq;
using ReactiveUI;

namespace ReactiveUIMahAppsDialog
{
    public class ChildViewModel : ReactiveObject
    {
        public ChildViewModel()
        {
            Message = new Interaction<Unit, Unit>();

            LogInUser = ReactiveCommand.CreateFromTask(async _ => await Message.Handle(Unit.Default));
        }

        public ReactiveCommand<Unit, Unit> LogInUser { get; }

        public Interaction<Unit, Unit> Message { get; }
    }
}

Full code can be found here .完整代码可以在这里找到。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM