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

xoshrz7s  于 2023-06-07  发布在  React
关注(0)|答案(4)|浏览(679)

我试图在我的项目中使用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中的命令不正确

j2cgzkjk

j2cgzkjk1#

我在使用另一个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一样工作)

4sup72z8

4sup72z82#

这看起来确实是一个时间问题--当我第一次开始使用它时,我通过从View的Loaded事件设置VM的DialogCoordinator示例,而不是它的构造函数来让它工作。
我已经在https://github.com/dwarry/ReactiveUiMahAppsDialog上创建了一个最小的工作应用程序来演示这一点。它使用ReactiveUi的正常交互机制来触发显示对话框。为了与此保持一致,我将其放在View中,但如果您愿意,我不明白为什么它不能从ViewModel中进行调整。另一件需要注意的事情是,在离开交互处理程序之前,您需要等待对话框关闭,否则ReactiveUI将抛出UnhandledInteractionException。

bbuxkriu

bbuxkriu3#

对我来说,使用ContentRendered事件没有做任何事情;我仍然得到了例外InvalidOperationException: Context is not registered. Consider using DialogParticipation.Register in XAML to bind in the DataContext
我的解决方案基于肯特Boogaart的book samples
浏览次数:

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中托管React式用户控件。
视图模型:

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

完整代码可以在here中找到。

jutyujz0

jutyujz04#

i used _dialogCoordinator.ShowModalMessageExternal(context,title,message);而且效果很好!

相关问题