AdvancedInvokeCommandAction.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. using Microsoft.Xaml.Behaviors;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Data;
  10. using System.Windows.Input;
  11. using System.Windows;
  12. namespace PDF_Master.Helper
  13. {
  14. public class CompositeCommandParameter
  15. {
  16. public CompositeCommandParameter(EventArgs eventArgs, object parameter)
  17. {
  18. EventArgs = eventArgs;
  19. Parameter = parameter;
  20. }
  21. public EventArgs EventArgs { get; }
  22. public object Parameter { get; }
  23. }
  24. public sealed class AdvancedInvokeCommandAction : TriggerAction<DependencyObject>
  25. {
  26. private string commandName;
  27. public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(AdvancedInvokeCommandAction), null);
  28. public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(AdvancedInvokeCommandAction), null);
  29. public static readonly DependencyProperty EventArgsConverterProperty = DependencyProperty.Register("EventArgsConverter", typeof(IValueConverter), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null));
  30. public static readonly DependencyProperty EventArgsConverterParameterProperty = DependencyProperty.Register("EventArgsConverterParameter", typeof(object), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null));
  31. public static readonly DependencyProperty EventArgsParameterPathProperty = DependencyProperty.Register("EventArgsParameterPath", typeof(string), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null));
  32. /// <summary>
  33. /// Gets or sets the name of the command this action should invoke.
  34. /// </summary>
  35. /// <value>The name of the command this action should invoke.</value>
  36. /// <remarks>This property will be superseded by the Command property if both are set.</remarks>
  37. public string CommandName
  38. {
  39. get
  40. {
  41. this.ReadPreamble();
  42. return this.commandName;
  43. }
  44. set
  45. {
  46. if (this.CommandName != value)
  47. {
  48. this.WritePreamble();
  49. this.commandName = value;
  50. this.WritePostscript();
  51. }
  52. }
  53. }
  54. /// <summary>
  55. /// Gets or sets the command this action should invoke. This is a dependency property.
  56. /// </summary>
  57. /// <value>The command to execute.</value>
  58. /// <remarks>This property will take precedence over the CommandName property if both are set.</remarks>
  59. public ICommand Command
  60. {
  61. get { return (ICommand)this.GetValue(CommandProperty); }
  62. set { this.SetValue(CommandProperty, value); }
  63. }
  64. /// <summary>
  65. /// Gets or sets the command parameter. This is a dependency property.
  66. /// </summary>
  67. /// <value>The command parameter.</value>
  68. /// <remarks>This is the value passed to ICommand.CanExecute and ICommand.Execute.</remarks>
  69. public object CommandParameter
  70. {
  71. get { return this.GetValue(AdvancedInvokeCommandAction.CommandParameterProperty); }
  72. set { this.SetValue(AdvancedInvokeCommandAction.CommandParameterProperty, value); }
  73. }
  74. /// <summary>
  75. /// Gets or sets the IValueConverter that is used to convert the EventArgs passed to the Command as a parameter.
  76. /// </summary>
  77. /// <remarks>If the <see cref="Command"/> or <see cref="EventArgsParameterPath"/> properties are set, this property is ignored.</remarks>
  78. public IValueConverter EventArgsConverter
  79. {
  80. get { return (IValueConverter)GetValue(EventArgsConverterProperty); }
  81. set { SetValue(EventArgsConverterProperty, value); }
  82. }
  83. /// <summary>
  84. /// Gets or sets the parameter that is passed to the EventArgsConverter.
  85. /// </summary>
  86. public object EventArgsConverterParameter
  87. {
  88. get { return (object)GetValue(EventArgsConverterParameterProperty); }
  89. set { SetValue(EventArgsConverterParameterProperty, value); }
  90. }
  91. /// <summary>
  92. /// Gets or sets the parameter path used to extract a value from an <see cref= "EventArgs" /> property to pass to the Command as a parameter.
  93. /// </summary>
  94. /// <remarks>If the <see cref="Command"/> propert is set, this property is ignored.</remarks>
  95. public string EventArgsParameterPath
  96. {
  97. get { return (string)GetValue(EventArgsParameterPathProperty); }
  98. set { SetValue(EventArgsParameterPathProperty, value); }
  99. }
  100. /// <summary>
  101. /// Specifies whether the EventArgs of the event that triggered this action should be passed to the Command as a parameter.
  102. /// </summary>
  103. /// <remarks>If the <see cref="Command"/>, <see cref="EventArgsParameterPath"/>, or <see cref="EventArgsConverter"/> properties are set, this property is ignored.</remarks>
  104. public bool PassEventArgsToCommand { get; set; }
  105. /// <summary>
  106. /// Invokes the action.
  107. /// </summary>
  108. /// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param>
  109. protected override void Invoke(object parameter)
  110. {
  111. if (this.AssociatedObject != null)
  112. {
  113. ICommand command = this.ResolveCommand();
  114. if (command != null)
  115. {
  116. object eventArgs = null;
  117. object commandParameter = this.CommandParameter;
  118. //if no CommandParameter has been provided, let's check the EventArgsParameterPath
  119. if (!string.IsNullOrWhiteSpace(this.EventArgsParameterPath))
  120. {
  121. eventArgs = GetEventArgsPropertyPathValue(parameter);
  122. }
  123. //next let's see if an event args converter has been supplied
  124. if (eventArgs == null && this.EventArgsConverter != null)
  125. {
  126. eventArgs = this.EventArgsConverter.Convert(parameter, typeof(object), EventArgsConverterParameter, CultureInfo.CurrentCulture);
  127. }
  128. //last resort, let see if they want to force the event args to be passed as a parameter
  129. if (eventArgs == null && this.PassEventArgsToCommand)
  130. {
  131. eventArgs = parameter;
  132. }
  133. if (command.CanExecute(commandParameter))
  134. {
  135. var compositeCommandParameter = new CompositeCommandParameter((EventArgs)eventArgs, commandParameter);
  136. command.Execute(compositeCommandParameter);
  137. }
  138. }
  139. }
  140. }
  141. private object GetEventArgsPropertyPathValue(object parameter)
  142. {
  143. object commandParameter;
  144. object propertyValue = parameter;
  145. string[] propertyPathParts = EventArgsParameterPath.Split('.');
  146. foreach (string propertyPathPart in propertyPathParts)
  147. {
  148. PropertyInfo propInfo = propertyValue.GetType().GetProperty(propertyPathPart);
  149. propertyValue = propInfo.GetValue(propertyValue, null);
  150. }
  151. commandParameter = propertyValue;
  152. return commandParameter;
  153. }
  154. private ICommand ResolveCommand()
  155. {
  156. ICommand command = null;
  157. if (this.Command != null)
  158. {
  159. command = this.Command;
  160. }
  161. else if (this.AssociatedObject != null)
  162. {
  163. // todo jekelly 06/09/08: we could potentially cache some or all of this information if needed, updating when AssociatedObject changes
  164. Type associatedObjectType = this.AssociatedObject.GetType();
  165. PropertyInfo[] typeProperties = associatedObjectType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
  166. foreach (PropertyInfo propertyInfo in typeProperties)
  167. {
  168. if (typeof(ICommand).IsAssignableFrom(propertyInfo.PropertyType))
  169. {
  170. if (string.Equals(propertyInfo.Name, this.CommandName, StringComparison.Ordinal))
  171. {
  172. command = (ICommand)propertyInfo.GetValue(this.AssociatedObject, null);
  173. }
  174. }
  175. }
  176. }
  177. return command;
  178. }
  179. }
  180. }