0
votes

I already implemented a Popup activation with ContextMenus which have ShowWindowCommand MenuItems whenever user right clicks at the taskbarIcon. It would maximize the window when user clicks that. Below is a code for the ContextMenus :

NotifyIcon.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:tb="http://www.hardcodet.net/taskbar"
                    xmlns:local="clr-namespace:MyProject.ViewModels">

    <ContextMenu x:Shared="false" x:Key="SysTrayMenu">
        <MenuItem Header="Show Window" Command="{Binding ShowWindowCommand}" />
        <MenuItem Header="Hide Window" Command="{Binding HideWindowCommand}" />
        <Separator />
        <MenuItem Header="Exit" Command="{Binding ExitApplicationCommand}" />
    </ContextMenu>

    <tb:TaskbarIcon x:Key="NotifyIcon"
                    IconSource="/tg_shield_copy.ico"
                    ToolTipText="MyProject"
                    DoubleClickCommand="{Binding ShowWindowCommand}"
                    ContextMenu="{StaticResource SysTrayMenu}">

        <tb:TaskbarIcon.DataContext>
            <local:NotifyIconViewModel/>
        </tb:TaskbarIcon.DataContext>
    </tb:TaskbarIcon>

</ResourceDictionary>

After the ShowWindowCommand is clicked, it would call an ICommand Property from NotifyIconViewModel class

NotifyIconViewModel.cs

 public class NotifyIconViewModel : BootstrapperBase
    {
        /// <summary>
        /// Shows a window, if none is already open.
        /// </summary>
        public ICommand ShowWindowCommand
        {
            get
            {
                return new DelegateCommand
                {
                    CanExecuteFunc = () => Application.Current.MainWindow == null,
                    CommandAction = () =>
                    {
                        DisplayRootViewFor<ShellViewModel>();
                    }
                };
            }
        }

        /// <summary>
        /// Hides the main window. This command is only enabled if a window is open.
        /// </summary>
        public ICommand HideWindowCommand
        {
            get
            {
                return new DelegateCommand
                {
                    CommandAction = () => Application.Current.MainWindow.Close(),
                    CanExecuteFunc = () => Application.Current.MainWindow != null
                };
            }
        }


        /// <summary>
        /// Shuts down the application.
        /// </summary>
        public ICommand ExitApplicationCommand
        {
            get
            {
                return new DelegateCommand { CommandAction = () => Application.Current.Shutdown() };
            }
        }
    }

    /// <summary>
    /// Simplistic delegate command for the demo.
    /// </summary>
    public class DelegateCommand : ICommand
    {
        public System.Action CommandAction { get; set; }
        public Func<bool> CanExecuteFunc { get; set; }

        public void Execute(object parameter)
        {
            CommandAction();
        }

        public bool CanExecute(object parameter)
        {
            return CanExecuteFunc == null || CanExecuteFunc();
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
       
    }

Right now i want to call the ICommand Property from another class for example like this :

ServerModule.cs

 public class ServerModule : NancyModule
{
   public ServerModule()
   {
      Post ("/Message", (args) =>
      {
        // Call ShowWindowCommand from here
      }
   }
}

My question is, how to call ICommand Property from ServerModule.cs class that same as i call using binding command in NotifyIcon.xaml

Update

Already using code suggestion but get an Exception

'MyProject.exe' (CLR v4.0.30319: MyProject.exe): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Dynamic\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Dynamic.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

The thread 0x550c has exited with code 0 (0x0).

The thread 0x52e4 has exited with code 0 (0x0).

Exception thrown: 'System.InvalidOperationException' in WindowsBase.dll

Exception thrown: 'System.InvalidOperationException' in WindowsBase.dll

The thread 0x43d8 has exited with code 0 (0x0).

Exception thrown: 'System.InvalidOperationException' in WindowsBase.dll

The thread 0x52b8 has exited with code 0 (0x0).

The thread 0x333c has exited with code 0 (0x0).

2
The question is too broad, as there are many different approaches one might take, and no clear path given the information so far, especially given the lack of a minimal reproducible example. That said, since it seems that even though the command can be executed from the notify window, it really is more global in nature, so you might look into creating a RoutedUICommand, with bindings to invoke it as necessary from any relevant context. I.e. it's wrong to think of the command itself as being owned by, or even referenced by, NotifyIconViewModelPeter Duniho

2 Answers

0
votes

ServerModule needs a reference to the object instance that exposes the required command:

public class ServerModule : NancyModule
{
   private NotifyIconViewModel CommandViewModel { get; }

   public ServerModule(NotifyIconViewModel commandViewModel)
   {
      this.CommandViewModel = commandViewModel;
      Post ("/Message", (args) =>
      {
        this.CommandViewModel.ShowWindowCommand.Execute();
      }
   }
}

If you are using MVVM then make sure that ServerModule is a class of the view or view model component. Otherwise you would violate the design pattern (because your model would make calls to either of them). If ServerModule is part of the model then you'd have to redesign your application.

0
votes

The solution from BionicCode help me, thanks alot. I just add an application dispacher to avoid cross-thread exception like code below

public class ServerModule : NancyModule
{
   private NotifyIconViewModel CommandViewModel { get; }

   public ServerModule(NotifyIconViewModel commandViewModel)
   {
     this.CommandViewModel = commandViewModel;

     Post ("/Message", (args) =>
     {
       Application.Current.Dispatcher.Invoke(delegate
       {
          CommandViewModel.ShowWindowCommand.Execute (null);
       });
     }
   }
}