Search This Blog

Thursday, July 23, 2015

WPF Busy Indicator

After reading Better WPF Circular Progress Bar I knew I could do this in XAML with no code behind.  So I stole the design for the oracular progress bar and reworked the animation.

 <UserControl Name="BusyIndicator" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">    
   <Viewbox Width="{Binding Width, ElementName=BusyIndicator}" Height="{Binding Height, ElementName=BusyIndicator}"      
        HorizontalAlignment="Center" VerticalAlignment="Center">  
     <Grid Background="Transparent" ToolTip="Searching...." HorizontalAlignment="Center" VerticalAlignment="Center">  
       <Canvas Name="Canvas1"  
         RenderTransformOrigin="0.5,0.5"  
         HorizontalAlignment="Center"         
         VerticalAlignment="Center" Width="120" Height="120">  
         <Canvas.RenderTransform>  
           <RotateTransform Angle="0" />  
         </Canvas.RenderTransform>  
         <Canvas.Style>  
           <Style TargetType="Canvas">  
             <Style.Triggers>  
               <Trigger Property="IsVisible" Value="True">  
                 <Trigger.EnterActions>  
                   <BeginStoryboard Name="Storyboard_Rotate">  
                     <Storyboard RepeatBehavior="Forever">  
                       <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"   
                          From="0" To="360" Duration="0:0:2"/>  
                     </Storyboard>  
                   </BeginStoryboard>  
                 </Trigger.EnterActions>  
                 <Trigger.ExitActions>  
                   <StopStoryboard BeginStoryboardName="Storyboard_Rotate" />  
                 </Trigger.ExitActions>  
               </Trigger>  
             </Style.Triggers>  
           </Style>  
         </Canvas.Style>  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="1.0" Canvas.Left="50" Canvas.Top="0" />  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.9" Canvas.Left="20.6107373853764" Canvas.Top="9.54915028125262" />  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.8" Canvas.Left="2.44717418524233" Canvas.Top="34.5491502812526" />  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.7" Canvas.Left="2.44717418524232" Canvas.Top="65.4508497187474" />  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.6" Canvas.Left="20.6107373853763" Canvas.Top="90.4508497187474" />  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.5" Canvas.Left="50" Canvas.Top="100" />  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.4" Canvas.Left="79.3892626146236" Canvas.Top="90.4508497187474" />  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.3" Canvas.Left="97.5528258147577" Canvas.Top="65.4508497187474" />  
         <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.2" Canvas.Left="97.5528258147577" Canvas.Top="34.5491502812526" />  
       </Canvas>  
     </Grid>  
   </Viewbox>  
 </UserControl>  

License
I got the idea from the Code Project article linked above.  They use the The Code Project Open License (CPOL) and I derived my work from that and make no claim of ownership at all.

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>