如何使用参数在 ReactiveUI 中打开新窗口

问题描述 投票:0回答:2

我正在寻找使用尊重 MVVM ReactiveUi 原则的参数打开新窗口的最佳方法。现在我正在使用 Splat 的服务位置来打开新窗口。 假设我想在单击主窗口视图上的按钮时打开新窗口。 目前:

  1. 我在管理 MainWindow View 的 ViewModel 方法中调用 Locator.Current.GetService("WindowToOpen") 来获取要打开的窗口实例
  2. 我调用实例“WindowToOpen”的 Show 或 ShowDialog 方法

但是如果我想向“WindowToOpen”传递参数该怎么办?

谢谢

c# wpf reactiveui
2个回答
0
投票

我也找不到任何有关如何在 WPF 中使用 ReactiveUI 打开新窗口的示例。

我最终所做的是将依赖属性添加到我的视图中(因为您无法将参数传递给视图构造函数)。例如,如果您需要将字符串值

userName
传递到新窗口,则必须将以下依赖项属性添加到该视图类:

public static readonly DependencyProperty UserNameProperty =
    DependencyProperty.Register("UserName", typeof(string), typeof(YourView),
        new PropertyMetadata(default(string)));

public string UserName
{
    get => (string) GetValue(UserNameProperty);
    set => SetValue(UserNameProperty, value);
}

然后,在创建视图时,您可以为该属性分配一个值。对于你的情况:

Window window = Locator.Current.GetService("WindowToOpen") as Window;
window.PropertyToChange = valueOfProperty;
window.Show();

如果您需要视图模型中的属性值(如果您使用 MVVM,则可能会这样做),请将依赖项属性绑定到视图模型中的属性。这必须在视图的

WhenActivated
方法中完成:

this.WhenActivated(disposables =>
{
    // Instantiate the view model just in case it is null
    ViewModel ??= Locator.Current.GetService<YourView>() ??
                  throw new InvalidOperationException("YourViewis not registered.");

    this.WhenAnyValue(view => view.UserName)
        .BindTo(ViewModel, viewModel => viewModel.UserName)
        .DisposeWith(disposables);

    // other bindings
});

我知道这一切感觉非常笨重和混乱。但我还没有找到任何关于如何仅使用 ReactiveUI 正确完成此操作的示例。


0
投票

在 ReactiveUI 中,您可以使用 IViewFor 或本例中的 ReactiveWindow 将视图与视图模型关联起来。因此,如果您想传递参数,您将使用您需要的任何参数创建一个视图模型实例,然后使用某种窗口服务将该视图模型分配给正确的视图并显示它。

窗口服务逻辑:

  1. 为您的窗口获取视图模型
  2. 查找关联窗口
  3. 将视图模型分配给找到的窗口。
  4. 显示窗口。

这项服务可能是这样的:

public interface IWindowService
{
    void OpenWindow<TViewModel>(TViewModel viewModel) where TViewModel : ReactiveObject;
}

public class WindowService : IWindowService
{
    public void OpenWindow<TViewModel>(TViewModel viewModel) where TViewModel : ReactiveObject
    {
        var viewLocator = Locator.Current.GetService<IViewLocator>();
        var view = viewLocator.ResolveView(viewModel);

        if (view is not ReactiveWindow<TViewModel> window)
            throw new Exception("ViewModel does not have associated Window");

        window.ViewModel = viewModel;
        window.Show();
    }
}

你可以这样使用它

public class MainViewModel : ReactiveObject
{
    public ReactiveCommand<Unit, Unit> OpenWindow { get; }

    public MainViewModel(IWindowService? windowService = null)
    {
        this.windowService = windowService ?? Locator.Current.GetService<IWindowService>();

        OpenWindow = ReactiveCommand.Create(() =>
        {
            var vm = new ExternalWindowViewModel(/*Add some parametrs*/);
            this.windowService.OpenWindow(vm);
        });
    }
}

假设您的视图中有按钮或其他内容绑定到 OpenWindow 命令:

public partial class MainWindow : ReactiveWindow<MainViewModel>
{
    public MainWindow()
    {
        InitializeComponent();
        ViewModel = new MainViewModel();

        this.WhenActivated(disposables =>
        {
            this.BindCommand(ViewModel, vm => vm.OpenWindow, v => v.NewWindowBtn)
                .DisposeWith(disposables);
        });
    }
}

另外不要忘记将视图与视图模型相关联:

Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly());
© www.soinside.com 2019 - 2024. All rights reserved.