C# 使用MVVM在xaml中进行命令绑定
目前,我正在尝试使用C#、WPF、MVVM创建我的第一个Windows应用程序,请参见下图 我的文件结构: 该应用程序的目标是在左侧有一个导航菜单,可用于导航到不同的内容,这些内容必须显示在白色区域中(见上图) 导航菜单中的“菜单项”(左侧的6个按钮)用于更改白色区域中显示的内容。我使用以下代码创建这些按钮:C# 使用MVVM在xaml中进行命令绑定,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,目前,我正在尝试使用C#、WPF、MVVM创建我的第一个Windows应用程序,请参见下图 我的文件结构: 该应用程序的目标是在左侧有一个导航菜单,可用于导航到不同的内容,这些内容必须显示在白色区域中(见上图) 导航菜单中的“菜单项”(左侧的6个按钮)用于更改白色区域中显示的内容。我使用以下代码创建这些按钮: class MenuItemViewModel:BaseViewModel { public MenuItemViewModel(string ItemName, string
class MenuItemViewModel:BaseViewModel
{
public MenuItemViewModel(string ItemName, string ItemImage, ICommand Command)
{
_MenuItem = new MenuItemModel(ItemName, ItemImage);
_command = Command;
}
private MenuItemModel _MenuItem;
public ICommand _command;
public MenuItemModel MenuItem
{
get { return _MenuItem; }
}
public ICommand Command
{
get { return _command; }
}
} // Class
在my Main Window.xaml中,我使用“ItemsControl”将“ItemsForce”绑定到菜单项列表
MainWindows.xaml:
<Window x:Class="TSD.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TSD"
xmlns:ViewModels="clr-namespace:TSD.ViewModels"
xmlns:views="clr-namespace:TSD.Views"
mc:Ignorable="d"
Title="TS Dashboard" Height="600" Width="1025" WindowStartupLocation="CenterScreen"
WindowStyle="None"
ResizeMode="CanResize"
WindowState="Normal"
>
<Window.Resources>
</Window.Resources>
<WindowChrome.WindowChrome>
<WindowChrome
CaptionHeight="0"
ResizeBorderThickness="5"/>
</WindowChrome.WindowChrome>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Background="#2b6ea4" MouseDown="Window_MouseDown">
<TextBlock x:Name="mainwindow_title" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="20,0,0,0" Text="{Binding MainWindowText}">
</TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Width="75">
<Button Background="Transparent" BorderThickness="0" Width="25" Name="min_button" Click="MinimizeButton_Click">
<Image Source="/assets/mini.png" Height="10" Width="10"/>
</Button>
<Button Background="Transparent" BorderThickness="0" Width="25" Name="max_button" Click="MaximizeButton_Click">
<Image Source="/assets/max.png" Height="10" Width="10"/>
</Button>
<Button Background="Transparent" BorderThickness="0" Width="25" Name="close_button" Click="CloseButton_Click">
<Image Source="/assets/close.png" Height="10" Width="10"/>
</Button>
</StackPanel>
</Grid>
<Grid Grid.Column="0" Margin="0,0,0,0" Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding ImagePath}"></Image>
<ItemsControl Background="#2B6EA4" Grid.Row="1" x:Name="NavigationMenu" ItemsSource="{Binding MenuItems}" Width="auto" HorizontalContentAlignment="Stretch">
</ItemsControl>
</Grid>
<Grid Grid.Column="1" Margin="0,0,0,0" Grid.Row="2">
<ContentControl Content="{Binding CurrentViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type ViewModels:HcfContentViewModel}">
<views:UserControlHcfContent/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:SLDContentViewModel}">
<views:UserControlSLDContent/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Grid>
</Grid>
在我的MainWindowViewModel中,我创建了一个UserControl列表,每个UserControl代表导航菜单中的一个按钮,该列表称为_menuItems,并绑定到前面显示的ItemsControl
MainWindowViewModel.cs:
class MainWindowViewModel : BaseViewModel, INotifyPropertyChanged
{
public MainWindowViewModel(NavigationStore navigationStore)
{
//Set name for window.
_MainWindowText = "My first MVVM application";
_ImagePath = "/assets/placeholder_image_name.png";
//Create MenuItems
UserControlMenuItem Item1 = new UserControlMenuItem(dummyCommand, "ISSUE LIST", "/assets/issue_list_icon.png");
UserControlMenuItem Item2 = new UserControlMenuItem(dummyCommand, "SYSTEM SHORTLOG DOWNLOAD","/assets/sld_icon.jpg");
UserControlMenuItem Item3 = new UserControlMenuItem(navigateHcfCommand, "HOSE CONNECTION FINDER", "/assets/hose_icon.png");
UserControlMenuItem Item4 = new UserControlMenuItem(dummyCommand, "GET CONFIG", "/assets/config_icon.png");
UserControlMenuItem Item5 = new UserControlMenuItem(dummyCommand, "KNOWLEDGE TRANSFER", "/assets/knowledge_transfer_icon.png");
UserControlMenuItem Item6 = new UserControlMenuItem(dummyCommand, "AMBITION LISTS", "/assets/ambition_list_icon.png");
//Properties
_MenuItems = new List<UserControlMenuItem> { Item1, Item2, Item3, Item4, Item5, Item6 };
_navigationStore = navigationStore;
//Commands used in this view
dummyCommand = new DummyCommand();
navigateHcfCommand = new ShowHcfCommand(_navigationStore);
}
// Class fields
private string _MainWindowText;
private List<UserControlMenuItem> _MenuItems;
private string _ImagePath;
private readonly NavigationStore _navigationStore;
// Commands
public ICommand navigateHcfCommand;
public ICommand dummyCommand;
//Class properties
public string ImagePath
{
get => _ImagePath;
set {
_ImagePath = ImagePath;
OnPropertyChanged("ImagePath");
}
}
public string MainWindowText
{
get => _MainWindowText;
set {
_MainWindowText = value;
OnPropertyChanged("MainWindowText");
}
}
public List<UserControlMenuItem> MenuItems
{
get => _MenuItems;
set {
_MenuItems = value;
OnPropertyChanged("MenuItems");
}
}
public BaseViewModel CurrentViewModel
{
get => _navigationStore.CurrentViewModel;
set { _navigationStore.CurrentViewModel = value; }
}
public ICommand UpdateCommand
{
get;
private set;
}
//
// Events
//
//Declare the event
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}// Class
以及menuitemodel.cs:
class MenuItemModel : INotifyPropertyChanged
{
private string _ItemName;
private string _ItemImage;
public MenuItemModel(string itemname, string itemimage)
{
_ItemName = itemname;
_ItemImage = itemimage;
}
public string ItemName
{
get => _ItemName;
set {
_ItemName = value;
OnPropertyChanged("ItemName");
}
}
public string ItemImage
{
get => _ItemImage;
set {
_ItemImage = value;
OnPropertyChanged("ItemImage");
}
}
//
// Events
//
//Declare the event
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
从第一张图片可以看出,这工作正常,问题在于绑定命令以更改“内容区域”(白色区域第一张图片)
我将在这里简要介绍内容区的代码:
在MainWindow.xaml(第一个代码段)中,您将看到一个“ContentControl”,这里我绑定了CurrentViewModel,它表示要在内容区域中显示的内容。我使用navigationStore存储必须显示的ViewModel
navigationStore.cs:
public class NavigationStore
{
public BaseViewModel CurrentViewModel { get; set; }
}
以及“内容页”的示例:
视图:
型号:
class HcfContentModel : INotifyPropertyChanged
{
private string _activeProductName;
private int _availableProducts;
public HcfContentModel()
{
}
public string activeProductName
{
get => _activeProductName;
set
{
_activeProductName = value;
OnPropertyChanged("activeProductName");
}
}
public int availableProducts
{
get => _availableProducts;
set
{
_availableProducts = value;
OnPropertyChanged("availableProducts");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
问题陈述:
按下/单击导航菜单中的项菜单时,不会触发命令。
我正在尝试执行ShowHcfCommand以将内容区域更改为HcfViewModel
ShowHcfCommand:
class ShowHcfCommand : BaseCommand
{
private readonly NavigationStore _navigationStore;
public ShowHcfCommand(NavigationStore navigationStore)
{
_navigationStore = navigationStore;
}
public override void Execute(object parameter)
{
_navigationStore.CurrentViewModel = new HcfContentViewModel();
Console.WriteLine("Command Executed!");
}
}
我希望提供的信息是充分和明确的,如果没有,请让我知道,以便我可以更新它。
可以从my github页面克隆整个项目:
我正在使用VS2017
如果有关于如何改进项目总体布局的提示,请让我知道
提前谢谢。
亲切问候,,
Sam在MainWindowViewModel.cs中,您从未实例化命令的实例
public ICommand navigateHcfCommand; //not instantiated
但在构造函数中使用:
UserControlMenuItem Item3 = new UserControlMenuItem(navigateHcfCommand, "HOSE CONNECTION FINDER", "/assets/hose_icon.png");
菜单项绑定到空命令。
如果更改,它仍然不会显示正确的contentviewmodel,因为您没有从navigationstore类调用property changed或任何其他事件。首先,感谢您的帮助 在听了T.Schwarz的评论后,我设法让它工作起来 我更新了MainWindowViewModel.cs以修复分配的null命令。 这最初修复了命令未被执行的问题,但正如T.Schwarz所提到的,它仍然不会改变视图。我必须在MainWindowViewModel中通知更改的属性,而不是从navigationStore。更新后的MainWindowViewModel如下所示:
class MainWindowViewModel : BaseViewModel, INotifyPropertyChanged
{
// Class fields
private string _MainWindowText;
private List<UserControlMenuItem> _MenuItems;
private string _ImagePath;
private readonly NavigationStore _navigationStore;
// Commands
public ICommand navigateHcfCommand;
public ICommand dummyCommand;
public MainWindowViewModel(NavigationStore navigationStore)
{
//Stores
_navigationStore = navigationStore;
//Commands used in this view
dummyCommand = new DummyCommand();
navigateHcfCommand = new ShowHcfCommand(this);
//Set name for window.
_MainWindowText = "My first MVVM application";
_ImagePath = "/assets/placeholder_image_name.png";
//Create MenuItems
UserControlMenuItem Item1 = new UserControlMenuItem(dummyCommand, "ISSUE LIST", "/assets/issue_list_icon.png");
UserControlMenuItem Item2 = new UserControlMenuItem(dummyCommand, "SYSTEM SHORTLOG DOWNLOAD","/assets/sld_icon.jpg");
UserControlMenuItem Item3 = new UserControlMenuItem(navigateHcfCommand, "HOSE CONNECTION FINDER", "/assets/hose_icon.png");
UserControlMenuItem Item4 = new UserControlMenuItem(dummyCommand, "GET CONFIG", "/assets/config_icon.png");
UserControlMenuItem Item5 = new UserControlMenuItem(dummyCommand, "KNOWLEDGE TRANSFER", "/assets/knowledge_transfer_icon.png");
UserControlMenuItem Item6 = new UserControlMenuItem(dummyCommand, "AMBITION LISTS", "/assets/ambition_list_icon.png");
//Properties
_MenuItems = new List<UserControlMenuItem> { Item1, Item2, Item3, Item4, Item5, Item6 };
}
//Class properties
public string ImagePath
{
get => _ImagePath;
set {
_ImagePath = ImagePath;
OnPropertyChanged("ImagePath");
}
}
public string MainWindowText
{
get => _MainWindowText;
set {
_MainWindowText = value;
OnPropertyChanged("MainWindowText");
}
}
public List<UserControlMenuItem> MenuItems
{
get => _MenuItems;
set {
_MenuItems = value;
OnPropertyChanged("MenuItems");
}
}
public BaseViewModel CurrentViewModel
{
get => _navigationStore.CurrentViewModel;
set {
_navigationStore.CurrentViewModel = value;
OnPropertyChanged("CurrentViewModel");
}
}
public ICommand UpdateCommand
{
get;
private set;
}
//
// Events
//
//Declare the event
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}// Class
class MainWindowViewModel:BaseViewModel,INotifyPropertyChanged
{
//类字段
私有字符串MainWindowText;
私有列表(菜单项);;
私有字符串_ImagePath;
私有只读NavigationStore_NavigationStore;
//命令
公共ICommand和NavigateHCcommand;
公共ICommand dummyCommand;
公共主窗口视图模型(导航存储导航存储)
{
//商店
_导航存储=导航存储;
//此视图中使用的命令
dummyCommand=新的dummyCommand();
navigateHcfCommand=新的ShowHcfCommand(本);
//设置窗口的名称。
_MainWindowText=“我的第一个MVVM应用程序”;
_ImagePath=“/assets/placeholder\u image\u name.png”;
//创建菜单项
UserControlMenuItem1=新的UserControlMenuItem(dummyCommand,“问题列表”,“assets/ISSUE\u LIST\u icon.png”);
UserControlMenuItem2=新的UserControlMenuItem(dummyCommand,“系统短日志下载”,“/assets/sld_icon.jpg”);
UserControlMenuItem3=新的UserControlMenuItem(navigateHcfCommand,“软管连接查找器”、“/assets/HOSE_icon.png”);
UserControlMenuItem4=新的UserControlMenuItem(dummyCommand,“GET-CONFIG”,“/assets/CONFIG_-icon.png”);
UserControlMenuItem5=新的UserControlMenuItem(dummyCommand,“知识转移”,“assets/KNOWLEDGE\u TRANSFER\u icon.png”);
UserControlMenuItem6=新的UserControlMenuItem(dummyCommand,“野心列表”,“资产/野心列表图标.png”);
//性质
_MenuItems=新列表{Item1,Item2,Item3,Item4,Item5,Item6};
}
//类属性
公共字符串映像路径
{
get=>\u ImagePath;
设置{
_ImagePath=ImagePath;
OnPropertyChanged(“ImagePath”);
}
}
公共字符串MainWindowText
{
get=>\u MainWindowText;
设置{
_MainWindowText=值;
OnPropertyChanged(“MainWindowText”);
}
}
公共列表菜单项
{
获取=>\u菜单项;
设置{
_MenuItems=值;
OnPropertyChanged(“菜单项”);
}
}
公共基础视图模型CurrentViewModel
{
get=>\u navigationStore.CurrentViewModel;
设置{
_navigationStore.CurrentViewModel=值;
OnPropertyChanged(“CurrentViewModel”);
}
}
公共ICommand更新命令
{
收到
私人设置;
}
//
//事件
//
//宣布事件
公共事件属性更改事件处理程序属性更改;
//创建OnPropertyChanged方法以引发事件
//调用成员的名称将用作参数。
受保护的无效OnPropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
}//阶级
正如您从上面的代码中看到的,我现在将MainWindowViewModel传递给ShowHcfCommand,在这个命令中我更改了v
class ShowHcfCommand : BaseCommand
{
private readonly NavigationStore _navigationStore;
public ShowHcfCommand(NavigationStore navigationStore)
{
_navigationStore = navigationStore;
}
public override void Execute(object parameter)
{
_navigationStore.CurrentViewModel = new HcfContentViewModel();
Console.WriteLine("Command Executed!");
}
}
public ICommand navigateHcfCommand; //not instantiated
UserControlMenuItem Item3 = new UserControlMenuItem(navigateHcfCommand, "HOSE CONNECTION FINDER", "/assets/hose_icon.png");
class MainWindowViewModel : BaseViewModel, INotifyPropertyChanged
{
// Class fields
private string _MainWindowText;
private List<UserControlMenuItem> _MenuItems;
private string _ImagePath;
private readonly NavigationStore _navigationStore;
// Commands
public ICommand navigateHcfCommand;
public ICommand dummyCommand;
public MainWindowViewModel(NavigationStore navigationStore)
{
//Stores
_navigationStore = navigationStore;
//Commands used in this view
dummyCommand = new DummyCommand();
navigateHcfCommand = new ShowHcfCommand(this);
//Set name for window.
_MainWindowText = "My first MVVM application";
_ImagePath = "/assets/placeholder_image_name.png";
//Create MenuItems
UserControlMenuItem Item1 = new UserControlMenuItem(dummyCommand, "ISSUE LIST", "/assets/issue_list_icon.png");
UserControlMenuItem Item2 = new UserControlMenuItem(dummyCommand, "SYSTEM SHORTLOG DOWNLOAD","/assets/sld_icon.jpg");
UserControlMenuItem Item3 = new UserControlMenuItem(navigateHcfCommand, "HOSE CONNECTION FINDER", "/assets/hose_icon.png");
UserControlMenuItem Item4 = new UserControlMenuItem(dummyCommand, "GET CONFIG", "/assets/config_icon.png");
UserControlMenuItem Item5 = new UserControlMenuItem(dummyCommand, "KNOWLEDGE TRANSFER", "/assets/knowledge_transfer_icon.png");
UserControlMenuItem Item6 = new UserControlMenuItem(dummyCommand, "AMBITION LISTS", "/assets/ambition_list_icon.png");
//Properties
_MenuItems = new List<UserControlMenuItem> { Item1, Item2, Item3, Item4, Item5, Item6 };
}
//Class properties
public string ImagePath
{
get => _ImagePath;
set {
_ImagePath = ImagePath;
OnPropertyChanged("ImagePath");
}
}
public string MainWindowText
{
get => _MainWindowText;
set {
_MainWindowText = value;
OnPropertyChanged("MainWindowText");
}
}
public List<UserControlMenuItem> MenuItems
{
get => _MenuItems;
set {
_MenuItems = value;
OnPropertyChanged("MenuItems");
}
}
public BaseViewModel CurrentViewModel
{
get => _navigationStore.CurrentViewModel;
set {
_navigationStore.CurrentViewModel = value;
OnPropertyChanged("CurrentViewModel");
}
}
public ICommand UpdateCommand
{
get;
private set;
}
//
// Events
//
//Declare the event
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}// Class