Registered command to commandmanager but it is not firing

136 Views Asked by At

I've a View that has a tabcontrol in it. Each tab is a different viewmodel. Above the tab is a Save button, that saves the active tab.

I try to use the CommandManager to pass the click of the button to the viewmodel, but it won't hit.

Here is my setup

using Catel.MVVM;
using Catel.Windows;
namespace Views
public partial class MainWindow : DataWindow
{
private readonly CommandManagerWrapper _commandManagerWrapper;
public MainWindow()
        : base(DataWindowMode.Custom, null, DataWindowDefaultButton.None, true, InfoBarMessageControlGenerationMode.None)
    {
        InitializeComponent();

        _commandManagerWrapper = new CommandManagerWrapper(this);
    }
}

This MainWindow calls a view

<catel:DataWindow x:Class="Views.CustomerOrderBlocksWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:catel="http://catel.codeplex.com"                   
              xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"                    
              xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
              xmlns:b="clr-namespace:TrendzzForYou.Helpers"       
              xmlns:controls="clr-namespace:Views"
              xmlns:helpers="clr-namespace:Helpers"
              xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"  
              ResizeMode="CanResize" SizeToContent="WidthAndHeight"
              WindowStartupLocation="CenterScreen" WindowState="Normal" 
              Icon="/Resources/Graphics/Filters64.png"
              MinHeight="1000" MinWidth="1800">

<catel:DataWindow.Resources>                
    <DataTemplate x:Key="TotalOrderTemplate">
        <controls:CustomerOrderTotalControl DataContext="{Binding CurrentTabContentViewModel}"/>
    </DataTemplate>
    <DataTemplate x:Key="NonDeliverableItemsTemplate">
        <controls:CustomerOrderNonDeliverableControl DataContext="{Binding CurrentTabContentViewModel}"/>
    </DataTemplate>
    <helpers:CustomerOrderBlocksTemplateSelector x:Key="selector"
                                                 TotalOrderTemplate="{StaticResource TotalOrderTemplate}"
                                                 NonDeliverableItemsTemplate="{StaticResource NonDeliverableItemsTemplate}"/>
</catel:DataWindow.Resources>

<Grid Margin="0,0,10,0">
    <Grid.RowDefinitions>            
        <RowDefinition Height="170"/>
        <RowDefinition MinHeight="750"/>            
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="1800"/>
    </Grid.ColumnDefinitions>
    
     <StackPanel>
        <telerik:RadButton Command="{catel:CommandManagerBinding Accept}" ToolTip="Sla gegevens op en voer volgende order in" TabIndex="99" Grid.Row="0">
            <StackPanel Orientation="Horizontal">
                <Image Source="/Resources/Graphics/Accept16.png" Height="16" />
                <telerik:Label Content="Opslaan" />
            </StackPanel>
        </telerik:RadButton>
    </StackPanel>
    
    <telerik:RadTabControl Grid.Row="1" Grid.Column="0" 
                           DisplayMemberPath="Header"
                           ContentTemplateSelector="{StaticResource selector}"                               
                           ItemsSource="{Binding Tabs}"
                           SelectedIndex="{Binding CustomerOrderTab}"/>

and a viewmodel

using Catel;
using Catel.Data;
using Catel.IoC;
using Catel.MVVM;
using Catel.Services;
using System.Collections.Generic;

public class CustomerOrderBlocksWindowViewModel : ViewModelBase
{
   public static readonly PropertyData CustomerOrderTabProperty = RegisterProperty("CustomerOrderTab", typeof(int));
   public static readonly PropertyData TabsProperty = RegisterProperty("Tabs", typeof(List<TabItemModel>));

   public int CustomerOrderTab { get { return GetValue<int>(CustomerOrderTabProperty); } set { SetValue(CustomerOrderTabProperty, value); } }
   public List<TabItemModel> Tabs { get { return GetValue<List<TabItemModel>>(TabsProperty); } set { SetValue(TabsProperty, value);  } }

   public CustomerOrderBlocksWindowViewModel(IUIVisualizerService theVisualizerService, IMessageService theMessageService, IPleaseWaitService thePleaseWaitService)
   {            
       Argument.IsNotNull(() => theVisualizerService);
       Argument.IsNotNull(() => theMessageService);
       Argument.IsNotNull(() => thePleaseWaitService);
 
       uiVisualizer = theVisualizerService;
       messageService = theMessageService;
       pleaseWait = thePleaseWaitService;

       var dependencyResolver = IoCConfiguration.DefaultDependencyResolver;
       commandManager = dependencyResolver.Resolve<ICommandManager>();

       commandManager.CreateCommand("Accept");
    
       UpdateTabs()
   }
    
   private void UpdateTabs()
   {          
        
         Tabs = new List<TabItemModel>()
         {
             new TabItemModel()
             {
                Header="Totaal"
             }
         };
        
         switch(CustomerOrderTab)
         {
            case 0:
                Tabs[0].CurrentTabContentViewModel = new CustomerOrderTotalControlViewModel(uiVisualizer, messageService, pleaseWait, commandManager);
                break;          
            default:
                break;
        }
    }
}

And the CustomerOrderTotalControlViewModel is like

using Catel;
using Catel.Data;
using Catel.MVVM;
using Catel.Services;

namespace ViewModels
{
    public class CustomerOrderTotalControlViewModel : ViewModelBase
    {        
        public Command CmdAccept { get; private set; }
    #region private references
    private IMessageService messageService;
    private IPleaseWaitService pleaseWait;
    private IUIVisualizerService uiVisualizer;
    #endregion

    public CustomerOrderTotalControlViewModel(IUIVisualizerService theVisualizerService, IMessageService theMessageService, IPleaseWaitService thePleaseWaitService, ICommandManager commandManager)
    {            
        Argument.IsNotNull(() => theVisualizerService);
        Argument.IsNotNull(() => theMessageService);
        Argument.IsNotNull(() => thePleaseWaitService);
        Argument.IsNotNull(() => commandManager);

        uiVisualizer = theVisualizerService;
        messageService = theMessageService;
        pleaseWait = thePleaseWaitService;

        CmdAccept = new Command(OnAccept);
        commandManager.RegisterCommand("Accept", CmdAccept, this);
    }

    private void OnAccept()
    {
        WaitScreen("Order opslaan...");            

    }

    private void WaitScreen(string TheMessage)
    {
        if (TheMessage != null)
            pleaseWait.Show(TheMessage);
        else
            pleaseWait.Hide();
    }

}

}

And Finally The TabItemModel:

using Catel.MVVM;

namespace Models
{
public class TabItemModel
{
    /// <summary>
    /// Tab Header text
    /// </summary>
    public string Header { get; set; }

    /// <summary>
    /// Tab content
    /// </summary>
    public IViewModel CurrentTabContentViewModel { get; set; }
}
}

According to the documentation I expect the CmdAccept to fire in CustomerOrderTotalControlViewModel when clicked but it does not.

What do I miss or do wrong

Jeroen

2

There are 2 best solutions below

1
JeroenZenM On BEST ANSWER

I moved the CommandManagerWrapper from MainWindow.xaml.cs to CustomerOrderBlocks.xaml.cs

And in CustomerOrderTotalControlViewModel

changed the RegisterCommand to

commandManager.RegisterCommand("Accept", CmdAccept);

And it works.

Not sure why the remove of "this" in the last part of code makes the difference

0
Geert van Horrik On

It's a bit hard to tell, but did you check the Catel logging? What could be the case is the command being created inside the view model ctor. At that point, the view is probably already loaded and the CommandManagerBinding has already done it's part.

To solve this, it's recommended to register all commands at application startup (or in case of plugins / extensions, at plugin initialization). Then the actions or commands bound to this command can be set inside the ctor of your view model.

Here are a few examples of application-wide commands:

https://github.com/WildGums/LogViewer/tree/develop/src/LogViewer/Commands

A few side notes:

  1. I noticed that you are resolving the ICommandManager manually, but I recommend injecting the ICommandManager using dependency injection as well
  2. I see you are using the "long notation" for the Catel properties. I recommend looking into Catel.Fody so you can simplify your property definitions and overall Catel development