繁体   English   中英

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

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

我正在尝试在我的项目中使用 Mahapps 对话框,但是当从我的 ViewModel 中的 ReactivUI 命令触发时无法让它们工作。在视图的 XAML 中,我已经注册了对话框。

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

我还有一个绑定到 ShowDialog 命令的按钮。

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

最后,在我的 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()));

    }

无论我尝试过什么,它总是抛出相同的错误

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

我不确定是否还需要其他任何东西才能使对话框正常工作,或者我是否只是错误地使用了 RxUI 中的命令

我在另一个 MVVM 框架(MVVM Light Toolkit)上遇到了同样的问题。 但是框架似乎不是问题。 这是时间问题。 DialogCoordinator 不能从构造函数访问。 我个人将所有代码从构造函数移动到正在被触发的 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>

我尝试了不同的事件,例如 Loaded,它在某些情况下有效,但“ContentRendered”始终在 VM 中有效,我有以下代码:

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

所以基本上它似乎还没有直接注册,但在加载内容后它是。 (在这个例子中,我使用了 ShowInputAsync 但它应该与 ShowMessageAsync 一样工作)

这似乎是一个时间问题 - 当我第一次开始玩这个时,我通过从 View 的 Loaded 事件而不是它的构造函数设置 VM 的 DialogCoordinator 实例来让它工作。

我已经在https://github.com/dwarry/ReactiveUiMahAppsDialog 上组合了一个最小的工作应用程序来演示这一点。 它使用 ReactiveUi 的正常交互机制来触发显示对话框。 与此保持一致,我已将其放在视图中,但我不明白为什么如果您愿意,它不能适应从 ViewModel 执行此操作。 要注意的另一件事是,您需要在离开交互处理程序之前等待对话框关闭,否则 ReactiveUI 将抛出 UnhandledInteractionException。

对我来说,使用ContentRendered事件没有做任何事情; 我仍然收到异常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

我的解决方案基于 Kent Boogaart 的书籍样本

看法:

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>

MetroWindow托管反应式用户控件。

视图模型:

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; }
    }
}

完整代码可以在这里找到。

暂无
暂无

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

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