using System; using System.Windows; using System.Windows.Documents; using System.Windows.Input; namespace Yahoo.SharedWPF { /// /// this is a class used primarily to work around a bug in /// WPF 3.0 where, if you have a custom command on a Hyperlink /// and you try to use ApplicationCommands.Copy the link, you /// get a crash because it tries to serialize the custom command /// and it is disallowed in the source. the workaround is to /// simply use this class to define the command rather than the /// Hyperlink.Command and everything else stays the same. /// public class HyperlinkHelper : DependencyObject { /// /// make the attached prop accessible from XAML /// /// /// public static ICommand GetCommand(DependencyObject obj) { return (ICommand)obj.GetValue(CommandProperty); } /// /// make the attached prop accessible from XAML /// /// /// /// public static void SetCommand(DependencyObject obj, ICommand value) { obj.SetValue(CommandProperty, value); } /// /// DP for HyperlinkHelper.Command /// public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached ( "Command", typeof(ICommand), typeof(HyperlinkHelper), new UIPropertyMetadata ( null, delegate(DependencyObject obj, DependencyPropertyChangedEventArgs args) { Hyperlink link = (obj as Hyperlink); if (link != null) { ICommand command = (args.NewValue as ICommand); if (command != null) { AddHandlers(link); } else { RemoveHandlers(link); } } } ) ); /// /// add the Click and Unloaded handlers /// /// static void AddHandlers(Hyperlink link) { if (link != null) { // remove handlers in case we get called twice RemoveHandlers(link); // add handlers link.Unloaded += link_Unloaded; link.Click += link_Click; } } /// /// remove the Click and Unloaded handlers /// /// static void RemoveHandlers(Hyperlink link) { if (link != null) { link.Unloaded -= link_Unloaded; link.Click -= link_Click; } } /// /// make sure we clean up when we are unloaded /// /// /// static void link_Unloaded(object sender, RoutedEventArgs e) { RemoveHandlers(sender as Hyperlink); } /// /// when the link is clicked, simply check whether the command /// can execute and execute if so /// /// /// static void link_Click(object sender, RoutedEventArgs e) { Hyperlink link = (sender as Hyperlink); ICommand command = GetCommand(link); if (command != null) { if (command is RoutedCommand) { RoutedCommand rcmd = command as RoutedCommand; IInputElement target = link.CommandTarget; if (target == null) { target = link; } if (rcmd.CanExecute(link.CommandParameter, target)) { rcmd.Execute(link.CommandParameter, target); } } else if (command.CanExecute(link.CommandParameter)) { command.Execute(link.CommandParameter); } } } } }