WPF 用户控件中的命令
Commands in WPF UserControls
我只是想了解 WPF 和 MVVM,但我完全糊涂了。
实际上我需要帮助完成以下任务:
我有一个带有菜单的主窗口。从这个菜单中,我想将一些数据加载到嵌套在用户控件中的树视图中。
据我目前所学,我应该使用命令。
我在哪里定义它们?
假设我有菜单,我会在菜单中使用'inside the MainWindow.xaml.<br>
I also would (of course) implement the
Command`-属性。
执行代码应嵌套在单独的 class 或需要数据的 UserControl 的代码隐藏内。
这是我的用户控件:
namespace PlcGenerator.Views
{
public partial class ProjectView : UserControl
{
public static RoutedCommand cmdLoadEcad = new RoutedCommand();
public ProjectView()
{
InitializeComponent();
}
private void CanExecuteCmdLoadEcad(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void ExecutedCmdLoadEcad(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Command executed.");
}
}
}
现在这是主窗口的(简化)部分:
<ribbon:RibbonWindow
x:Class="PlcGenerator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:System.Windows.Controls.Ribbon;assembly=System.Windows.Controls.Ribbon"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PlcGenerator"
xmlns:viewmodels="clr-namespace:PlcGenerator.ViewModels"
xmlns:views="clr-namespace:PlcGenerator.Views"
mc:Ignorable="d"
Loaded="Window_Loaded"
Closing="ClosingApp"
Title="Plc Generator" Height="600" Width="1200">
<Window.CommandBindings>
<CommandBinding Command="{x:Static views:ProjectView.cmdLoadEcad}"
Executed="ProjectView.ExecutedCmdLoadEcad"
CanExecute="ProjectView.CanExecuteCmdLoadEcad"/>
</Window.CommandBindings>
<Window.Resources>
<DataTemplate x:Name="settingsViewTemplate" DataType="{x:Type viewmodels:SettingsViewModel}">
<views:SettingsView DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate x:Name="projectsViewTemplate" DataType="{x:Type viewmodels:ProjectViewModel}">
<views:ProjectView DataContext="{Binding ProjectVM, Source={StaticResource Locator}}"/>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<ribbon:Ribbon DockPanel.Dock="Top">
<Ribbon.ApplicationMenu>
<RibbonApplicationMenu SmallImageSource="Icons/ApplicationMenu.png">
<RibbonApplicationMenuItem Header="Neues Projekt" ImageSource="Icons/NewEntry.png" Command="{x:Static views:ProjectView.cmdLoadEcad}"/>
</RibbonApplicationMenu>
</Ribbon.ApplicationMenu>
</ribbon:Ribbon>
<!-- Fensterinhalt-->
<ContentControl Margin="5" Content="{Binding}"/>
</DockPanel>
这里出现错误,找不到命令元素,我想是因为它不在代码隐藏 MainWindow 中?
那么我怎样才能在单独的 class 或用户控件中从 MainWindow-Menu 获得该命令?
我真的很闲!
UPDATE(如第一条评论中所述,我试图理解链接的答案):
我创建了一个 ViewModelLocator:
using PlcGenerator.ViewModels;
namespace PlcGenerator
{
public class ViewModelLocator
{
public ViewModelLocator()
{
this.ProjectVM = new ProjectViewModel();
this.SettingsVM = new SettingsViewModel();
}
public ProjectViewModel ProjectVM{ get; set; }
public SettingsViewModel SettingsVM { get; set; }
}
}
我想让它对所有视图和控件可用,所以我将它插入 App.xaml:
<Application x:Class="PlcGenerator.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PlcGenerator"
StartupUri="MainWindow.xaml">
<Application.Resources>
<local:ViewModelLocator x:Key="Locator" />
</Application.Resources>
</Application>
第一个问题,当它位于 ViewModel 命名空间时,我无法将其插入。这是如何工作的?
现在,在使用命令执行任何操作之前,我想在显示没有用户控件的主窗口时填充虚拟机,调用菜单事件。所以我在 MainWindow 的代码隐藏中写了以下内容:
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModelLocator();
}
public MnuOpenProject(object sender, RoutedEventArgs e)
{
//How can I now access the ProjectViewModel (ProjectVM) of the Datacontext?
}
在 MnuOpenProject 方法中,我无法访问 DataContext.ProjectVM。如何在 VM 定位器中创建此对象?
我解决了之后,我会继续命令。然后我会把所有的逻辑,比如在视图模型中打开一个项目吗?
下次尝试
还在 <Window.Resources...
部分编辑了 <DataTemplate...
,见上文
必须这样吗?:
public partial class MainWindow : RibbonWindow
{
#region Data
public ViewModelLocator viewModelLocator;
#endregion
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModelLocator();
viewModelLocator = (ViewModelLocator)this.DataContext;
}
public MnuOpenProject(object sender, RoutedEventArgs e)
{
viewModelLocator.ProjectVM.Name = "ProjectName";
}
}
还有所有其他视图?
如果您尝试使用 MVVM 模式,则需要有一个 ViewModel,您可以在其中定义命令。您需要将视图中的 DataContext 设置为 ViewModel - 如果您需要帮助,请参阅 this 答案。
您正在使用 App.xaml
中的以下资源创建 ViewModelLocator
class 的实例:
<local:ViewModelLocator x:Key="Locator" />
然后您可以直接在 XAM 标记中将 window 的 DataContext
绑定到 ViewModelLocator
的 属性,如下所示:
<Window ... DataContext="{Binding ProjectViewModel, Source={StaticResource Locator}}" />
使用此方法,无需在代码隐藏中以编程方式设置 DataContext
。
将 DataContext
设置为从 ViewModelLocator
返回的视图模型实例后,您可以绑定到任何 public 属性 视图模型在视图中,例如:
<TextBlock Text="{Binding SomePropertyInProjectViewModel" />
我只是想了解 WPF 和 MVVM,但我完全糊涂了。 实际上我需要帮助完成以下任务:
我有一个带有菜单的主窗口。从这个菜单中,我想将一些数据加载到嵌套在用户控件中的树视图中。
据我目前所学,我应该使用命令。
我在哪里定义它们?
假设我有菜单,我会在菜单中使用'inside the MainWindow.xaml.<br>
I also would (of course) implement the
Command`-属性。
执行代码应嵌套在单独的 class 或需要数据的 UserControl 的代码隐藏内。
这是我的用户控件:
namespace PlcGenerator.Views
{
public partial class ProjectView : UserControl
{
public static RoutedCommand cmdLoadEcad = new RoutedCommand();
public ProjectView()
{
InitializeComponent();
}
private void CanExecuteCmdLoadEcad(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void ExecutedCmdLoadEcad(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Command executed.");
}
}
}
现在这是主窗口的(简化)部分:
<ribbon:RibbonWindow
x:Class="PlcGenerator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:System.Windows.Controls.Ribbon;assembly=System.Windows.Controls.Ribbon"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PlcGenerator"
xmlns:viewmodels="clr-namespace:PlcGenerator.ViewModels"
xmlns:views="clr-namespace:PlcGenerator.Views"
mc:Ignorable="d"
Loaded="Window_Loaded"
Closing="ClosingApp"
Title="Plc Generator" Height="600" Width="1200">
<Window.CommandBindings>
<CommandBinding Command="{x:Static views:ProjectView.cmdLoadEcad}"
Executed="ProjectView.ExecutedCmdLoadEcad"
CanExecute="ProjectView.CanExecuteCmdLoadEcad"/>
</Window.CommandBindings>
<Window.Resources>
<DataTemplate x:Name="settingsViewTemplate" DataType="{x:Type viewmodels:SettingsViewModel}">
<views:SettingsView DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate x:Name="projectsViewTemplate" DataType="{x:Type viewmodels:ProjectViewModel}">
<views:ProjectView DataContext="{Binding ProjectVM, Source={StaticResource Locator}}"/>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<ribbon:Ribbon DockPanel.Dock="Top">
<Ribbon.ApplicationMenu>
<RibbonApplicationMenu SmallImageSource="Icons/ApplicationMenu.png">
<RibbonApplicationMenuItem Header="Neues Projekt" ImageSource="Icons/NewEntry.png" Command="{x:Static views:ProjectView.cmdLoadEcad}"/>
</RibbonApplicationMenu>
</Ribbon.ApplicationMenu>
</ribbon:Ribbon>
<!-- Fensterinhalt-->
<ContentControl Margin="5" Content="{Binding}"/>
</DockPanel>
这里出现错误,找不到命令元素,我想是因为它不在代码隐藏 MainWindow 中?
那么我怎样才能在单独的 class 或用户控件中从 MainWindow-Menu 获得该命令?
我真的很闲!
UPDATE(如第一条评论中所述,我试图理解链接的答案):
我创建了一个 ViewModelLocator:
using PlcGenerator.ViewModels;
namespace PlcGenerator
{
public class ViewModelLocator
{
public ViewModelLocator()
{
this.ProjectVM = new ProjectViewModel();
this.SettingsVM = new SettingsViewModel();
}
public ProjectViewModel ProjectVM{ get; set; }
public SettingsViewModel SettingsVM { get; set; }
}
}
我想让它对所有视图和控件可用,所以我将它插入 App.xaml:
<Application x:Class="PlcGenerator.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PlcGenerator"
StartupUri="MainWindow.xaml">
<Application.Resources>
<local:ViewModelLocator x:Key="Locator" />
</Application.Resources>
</Application>
第一个问题,当它位于 ViewModel 命名空间时,我无法将其插入。这是如何工作的?
现在,在使用命令执行任何操作之前,我想在显示没有用户控件的主窗口时填充虚拟机,调用菜单事件。所以我在 MainWindow 的代码隐藏中写了以下内容:
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModelLocator();
}
public MnuOpenProject(object sender, RoutedEventArgs e)
{
//How can I now access the ProjectViewModel (ProjectVM) of the Datacontext?
}
在 MnuOpenProject 方法中,我无法访问 DataContext.ProjectVM。如何在 VM 定位器中创建此对象?
我解决了之后,我会继续命令。然后我会把所有的逻辑,比如在视图模型中打开一个项目吗?
下次尝试
还在 <Window.Resources...
部分编辑了 <DataTemplate...
,见上文
必须这样吗?:
public partial class MainWindow : RibbonWindow
{
#region Data
public ViewModelLocator viewModelLocator;
#endregion
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModelLocator();
viewModelLocator = (ViewModelLocator)this.DataContext;
}
public MnuOpenProject(object sender, RoutedEventArgs e)
{
viewModelLocator.ProjectVM.Name = "ProjectName";
}
}
还有所有其他视图?
如果您尝试使用 MVVM 模式,则需要有一个 ViewModel,您可以在其中定义命令。您需要将视图中的 DataContext 设置为 ViewModel - 如果您需要帮助,请参阅 this 答案。
您正在使用 App.xaml
中的以下资源创建 ViewModelLocator
class 的实例:
<local:ViewModelLocator x:Key="Locator" />
然后您可以直接在 XAM 标记中将 window 的 DataContext
绑定到 ViewModelLocator
的 属性,如下所示:
<Window ... DataContext="{Binding ProjectViewModel, Source={StaticResource Locator}}" />
使用此方法,无需在代码隐藏中以编程方式设置 DataContext
。
将 DataContext
设置为从 ViewModelLocator
返回的视图模型实例后,您可以绑定到任何 public 属性 视图模型在视图中,例如:
<TextBlock Text="{Binding SomePropertyInProjectViewModel" />