I'm just trying to understand WPF and MVVM and I am totally confused. Actually I need help with the following task:
I have a MainWindow, that carries a menu. From this menu, I want to load some data into a treeview, that is nested inside a usercontrol.
As I learned so far, I should use commands.
Where do I define them?
Assuming I have the menu, I would use 'inside the MainWindow.xaml.<br> I also would (of course) implement theCommand`-property inside the menu.
The code for Execution should be nested inside a seperate class or inside the codebehind of the UserControl, that needs the data.
This is my 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."); } } } Now this is a (reduced) part of the mainWindow:
<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> Here I get the error, that the command-element is not found, I think because it's not located in the codebehind MainWindow?
So how can I get that command work from MainWindow-Menu inside a separate class or usercontrol?
I'm really off!
UPDATE (as mentioned in first comment, I tried to understand the linked answer):
I created a 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; } } } I wanted to make it available for all views and controls, so I inserted it into 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> First problem, I wasn't able to get it inserted while it was located in ViewModel-namespace. How does this work?
Now, before doing anything with commands, I'd like to fill the VMs while MainWindow is shown without UserControls, invoking a menu-event. So I wrote the following in codebehind of 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? } In the MnuOpenProject-method, I didn't manage to have any access to DataContext.ProjectVM. How do I create this object inside the VM-locator?
After I solve that, I will go on with commands. Will I then put all the logic, like opening a project inside the Viewmodels?
NEXT TRY
also edited <DataTemplate... in the <Window.Resources...-section, see above
Is that the way it has to be?:
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"; } } And also in all other views?