我想用MVVM模式构建一个简单的应用程序。
此应用程序将包含两个主要部分:
导航很简单:
我之前使用代码完成了,其中菜单项的代码隐藏事件处理程序已加载所有页面,应该显示的那个作为StackPanel的子项加载。但是,这在MVVM中不起作用,因为您不希望手动填充StackPanel,而是显示例如带有DataTemplate等的“PageItem”对象
那些使用MVVM制作了这样一个简单的点击菜单应用程序的人,你的基本应用程序结构是什么?我正在考虑这些问题:
MainView.xaml:
<DockPanel LastChildFill="False">
<Menu
ItemsSource="{Binding PageItemsMainMenu}"
ItemTemplate="{StaticResource MainMenuStyle}"/>
<ContentControl
Content="{Binding SelectedPageItem}"/>
</DockPanel>
其中Menu填充了“PageItems”集合,DataTemplate将每个“PageItem对象”的标题显示为每个MenuItem的标题。
ContentControl将填充一个具有完整功能的View / ViewModel对,但我不确定。
答案 0 :(得分:9)
首先,我认为你应该保留代码隐藏事件处理程序,没有任何意义将一个简单的2行事件处理程序更改为复杂的命令驱动的怪物没有任何实际原因(并且不说测试性,这是主要的菜单,每次运行应用程序时都会对其进行测试。)
现在,如果您确实想要使用纯MVVM路由,那么您必须执行此操作才能使菜单触发命令,首先,在某些资源部分添加此样式:
<Style x:Key="MenuItemStyle" TargetType="MenuItem">
<Setter Property="Command"
Value="{Binding DataContext.SwitchViewCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}"/>
<Setter Property="CommandParameter"
Value="{Binding}"/>
</Style>
此样式将使菜单项在附加的视图模型上触发SwitchViewCommand,并使用MenuItem的DataContext作为命令参数。
实际视图与您的代码相同,并且作为ItemContainerStyle对该样式的附加引用(因此它适用于菜单项而不是DataTemplate的内容):
<DockPanel LastChildFill="False">
<Menu DockPanel.Dock="Top"
ItemsSource="{Binding PageItemsMainMenu}"
ItemTemplate="{StaticResource MainMenuStyle}"
ItemContainerStyle="{StaticResource MenuItemStyle}"/>
<ContentControl
Content="{Binding SelectedPageItem}"/>
</DockPanel>
现在你需要的视图模型(我使用了字符串,因为我没有你的PageItem代码):
private string _selectedViewItem;
public List<string> PageItemsMainMenu { get; set; }
public string SelectedPageItem
{
get { return _selectedViewItem; }
set { _selectedViewItem = value; OnNotifyPropertyChanged("SelectedPageItem"); }
}
public ICommand SwitchViewCommand { get; set; }
并使用您使用的任何命令类来使命令调用此代码:
private void DoSwitchViewCommand(object parameter)
{
SelectedPageItem = (string)parameter;
}
现在,当用户单击菜单项时,菜单项将以页面项为参数调用SwitchViewCommand。
该命令将调用将设置SelectedPageItem属性的DoSwitchViewCommand
该属性将引发NotifyPropertyChanged,它将通过数据绑定进行UI更新。
或者,您可以编写一个2行事件处理程序,您的选择
答案 1 :(得分:0)
我可以想象一下VM中的一个ObservableCollection,它包含了可以从菜单中调用的所有页面。 然后将ItemsControl和ContentControl绑定到它,以使ContentControl始终显示该列表中的CurrentItem。 当然,菜单只会绑定到某些Title属性 而ContentControl将采用整个项目并根据类型插入一些适当的视图。
答案 2 :(得分:0)
另一种选择是使用ListBox而不是菜单,将ListBox设置为菜单样式然后您可以绑定到选定的值,如下所示:
<DockPanel LastChildFill="False">
<ListBox
ItemsSource="{Binding PageItemsMainMenu}"
ItemTemplate="{StaticResource MainMenuStyle}"
IsSynchronizedWithCurrentItem="True"/>
<ContentControl
Content="{Binding PageItemsMainMenu/}"/>
</DockPanel>
注意IsSynchronizedWithCurrentItem =“True”设置所选项目,并使用尾部斜杠设置{Binding PageItemsMainMenu /}以使用它。