Search This Blog

Friday, March 20, 2015

Hardcodet Taskbar RoutedUICommand workaround.

I have found a way to use Taskbar command using bubbled routed UI commands.

Here is the object.


/// <summary>
/// Taskbar routed UI command.
/// </summary>
public class TaskbarRoutedUICommand : DependencyObject, ICommand
{
   #region Private
   /// <summary>
   /// Window to send command.
   /// </summary>
   private Window window = null;
   #endregion

   #region Parameters
   /// <summary>
   /// Command DependencyProperty
   /// </summary>
   public static readonly DependencyProperty CommandProperty =
       DependencyProperty.Register("Command", typeof(RoutedUICommand), typeof(TaskbarRoutedUICommand), new PropertyMetadata(null));

   /// <summary>
   /// Command
   /// </summary>
   public RoutedUICommand Command
   {
       get { return (RoutedUICommand)GetValue(CommandProperty); }
       set { SetValue(CommandProperty, value); }
   }

   public static bool IsDesignMode
   {
       get
       {
           return (bool)
               DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty,
                   typeof(FrameworkElement))
                   .Metadata.DefaultValue;
       }
   }

   /// <summary>
   /// Can Execute Change
   /// Not used
   /// </summary>
   public event EventHandler CanExecuteChanged;
   #endregion

   #region ICommand        
   public bool CanExecute(object parameter)
   {
       if (window == null)                
           window = GetTaskbarWindow(parameter);
       
       if (window == null)
           return true;
       else
           return this.Command.CanExecute(parameter, window);
   }

   public void Execute(object parameter)
   {
       if (window == null)
           window = GetTaskbarWindow(parameter);

       this.Command.Execute(parameter, window);
   }
   #endregion

   #region TryFindParent helper
   /// <summary>
   /// Resolves the window that owns the TaskbarIcon class.
   /// </summary>
   /// <param name="commandParameter"></param>
   /// <returns></returns>
   protected Window GetTaskbarWindow(object commandParameter)
   {
       if (IsDesignMode) return null;

       //get the showcase window off the TaskbarIcon
       var tb = commandParameter as TaskbarIcon;
       return tb == null ? null : TryFindParent<Window>(tb);
   }

   /// <summary>
   /// Finds a parent of a given item on the visual tree.
   /// </summary>
   /// <typeparam name="T">The type of the queried item.</typeparam>
   /// <param name="child">A direct or indirect child of the
   /// queried item.</param>
   /// <returns>The first parent item that matches the submitted
   /// type parameter. If not matching item can be found, a null
   /// reference is being returned.</returns>
   public static T TryFindParent<T>(DependencyObject child)
       where T : DependencyObject
   {
       //get parent item
       DependencyObject parentObject = GetParentObject(child);

       //we've reached the end of the tree
       if (parentObject == null) return null;

       //check if the parent matches the type we're looking for
       T parent = parentObject as T;
       if (parent != null)
       {
           return parent;
       }
       else
       {
           //use recursion to proceed with next level
           return TryFindParent<T>(parentObject);
       }
   }

   /// <summary>
   /// This method is an alternative to WPF's
   /// <see cref="VisualTreeHelper.GetParent"/> method, which also
   /// supports content elements. Keep in mind that for content element,
   /// this method falls back to the logical tree of the element!
   /// </summary>
   /// <param name="child">The item to be processed.</param>
   /// <returns>The submitted item's parent, if available. Otherwise
   /// null.</returns>
   public static DependencyObject GetParentObject(DependencyObject child)
   {
       if (child == null) return null;
       ContentElement contentElement = child as ContentElement;

       if (contentElement != null)
       {
           DependencyObject parent = ContentOperations.GetParent(contentElement);
           if (parent != null) return parent;

           FrameworkContentElement fce = contentElement as FrameworkContentElement;
           return fce != null ? fce.Parent : null;
       }

       //if it's not a ContentElement, rely on VisualTreeHelper
       return VisualTreeHelper.GetParent(child);
   }

   #endregion
}

Here is how to use it in the xaml file.
Place this in the resources section

<objects:taskbarrouteduicommand command="RoutedUICommand" x:key="ApplicationExit">
</objects:taskbarrouteduicommand><

Here is an example Taskbar be sure to pass the TaskbarIcon as the parameter.

<tb:TaskbarIcon x:Name="TaskbarIcon"
              Visibility="Visible" 
              MenuActivation="LeftOrRightClick"                                 
              DoubleClickCommand="{StaticResource ApplicationExit}"                        
              DoubleClickCommandParameter="{Binding RelativeSource={RelativeSource Self}}">            
  <tb:TaskbarIcon.ContextMenu>
      <ContextMenu>
          <MenuItem Header="Exit" Command="{StaticResource ApplicationExit}" CommandParameter="{Binding}"/>
      </ContextMenu>
  </tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>