簡體   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