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);
}
}
}
}
}