嵌套 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 使用其定位器逻辑来查找视图。如果没有定义 ItemTemplate
或 DisplayPathMember
属性,RxUI 将查找视图。这些视图在 Splat 容器中注册为视图模型的视图。所以<Menu.Resources>
中的DataTemplates
不考虑。这正是图像中显示的内容。创建了一个 ViewModelViewHost
,但是因为没有找到相应的视图,所以没有显示任何内容。
这可以通过使用 XAML 绑定而不是绑定背后的代码来解决(将视图模型分配给数据上下文来执行此操作!)。有关详细信息,请参阅文档。
问:如何将 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 使用其定位器逻辑来查找视图。如果没有定义 ItemTemplate
或 DisplayPathMember
属性,RxUI 将查找视图。这些视图在 Splat 容器中注册为视图模型的视图。所以<Menu.Resources>
中的DataTemplates
不考虑。这正是图像中显示的内容。创建了一个 ViewModelViewHost
,但是因为没有找到相应的视图,所以没有显示任何内容。
这可以通过使用 XAML 绑定而不是绑定背后的代码来解决(将视图模型分配给数据上下文来执行此操作!)。有关详细信息,请参阅文档。