嵌套 reactiveui usercontrols wpf/将 ViewModel 传递给 usercontrol

Nest reactiveui usercontrols wpf / pass ViewModel to usercontrol

问:如何将 ViewModel 绑定到 ReactiveUserControl?或者如何嵌套 Reactiveui 视图? 可能我做错了什么,但我无法弄清楚到底是什么。

ReactiveUserControl

// MenuView.xaml
<reactiveui:ReactiveUserControl
       x:Class="Views.MenuView"
       xmlns:menuItems="clr-namespace:Model"    
    .... >
    <Menu x:Name="RootMenu"
          IsMainMenu="True">
        <Menu.Resources>
            <DataTemplate DataType="{x:Type menuItems:DialogItem}">
                <TextBlock Text="{Binding Description}" />
            </DataTemplate>
        </Menu.Resources>
    </Menu>
</reactiveui:ReactiveUserControl>
// MenuView.xaml.cs
namespace Views
{
    public partial class MenuView : ReactiveUserControl<MenuViewModel>
    {
        public MenuView()
        {
            InitializeComponent();

            this.WhenActivated(disposables =>
            {
                this.OneWayBind(ViewModel,
                    vm => vm.MenuItems,
                    view => view.RootMenu.ItemsSource
                ).DisposeWith(disposables);
            });
        }
    }
}
// MenuViewModel.cs
namespace Views
{
    public class MenuViewModel : ReactiveObject
    {
        public ObservableCollection<DialogItem> MenuItems { get; } = new ObservableCollection<DialogItem>();

        public MenuViewModel()
        {
            MenuItems.Add(new DialogItem("Edit", 224));
            MenuItems.Add(new DialogItem("View", 224));
        }
    }
}

DialogItem 表示菜单中的一个项目

// DialogItem.cs
namespace Model
{
    public class DialogItem
    {
        public DialogItem(string description, int dialogId)
        {
            this.DialogId = dialogId;
            this.Description = description;
        }

        public int DialogId { get; }

        public string Description { get; }
    }
}

然后最后在 MainWindow 中包含用户控件,如下所示:

// MainWindow.xaml
<reactiveui:ReactiveWindow
        x:Class="Views.MainWindow"
....
>
    <Grid>
        <views:MenuView x:Name="MainMenu" />
    </Grid>
</reactiveui:ReactiveWindow>

代码隐藏

// MainWindow.xaml.cs
namespace Views
{
    public partial class MainWindow : ReactiveWindow<MainWindowModel>
    {
        public MainWindow()
        {
            InitializeComponent();
            this.WhenActivated(disposables =>
            {
        // BIND THE VIEWMODEL CREATED IN THE MAINWINDOW VIEWMODEL, IS THIS CORRECT?
                this.Bind(ViewModel,
                    vm => vm.MainMenuViewModel,
                    view => view.MainMenu.ViewModel
                ).DisposeWith(disposables);
            });
        }
    }
}
// MainWindowModel.cs
namespace Views
{
    public class MainWindowModel : ReactiveObject
    {
        public MenuViewModel MainMenuViewModel { get; }

        public MainWindowModel()
        {
            this.MainMenuViewModel = new MenuViewModel();
        }
    }
}

项目是迭代的,但如果我查看视觉表示树,我会在 ContentPresenter 中找到一个 ViewModelViewHost 项目,而不是 TextBlock

此处您看到菜单项未正确呈现。 (它们已呈现但没有来自 DataTemplate 的文本。

更新: 使用 Menu.ItemTemplate 确实有效,但这不是我想要的。

<reactiveui:ReactiveUserControl
       x:Class="Views.MenuView"
...
>
    <Menu x:Name="RootMenu"
          IsMainMenu="True">
        <Menu.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Description}" />
            </DataTemplate>
        </Menu.ItemTemplate>
    </Menu>
</reactiveui:ReactiveUserControl>

在 Slack 上与 Glenn Watson 讨论这个问题给了我一分钱。因为我使用的是 RxUI 绑定背后的代码,所以 RxUI 使用其定位器逻辑来查找视图。如果没有定义 ItemTemplateDisplayPathMember 属性,RxUI 将查找视图。这些视图在 Splat 容器中注册为视图模型的视图。所以<Menu.Resources>中的DataTemplates不考虑。这正是图像中显示的内容。创建了一个 ViewModelViewHost,但是因为没有找到相应的视图,所以没有显示任何内容。

这可以通过使用 XAML 绑定而不是绑定背后的代码来解决(将视图模型分配给数据上下文来执行此操作!)。有关详细信息,请参阅文档。