Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / Hyperlink.cs / 1305600 / Hyperlink.cs
//---------------------------------------------------------------------------- // File: Hyperlink.cs // // Description: // Implementation of Underline element. // // Copyright (C) 2004 by Microsoft Corporation. All rights reserved. // //--------------------------------------------------------------------------- using System.ComponentModel; using System.Diagnostics; using System.IO.Packaging; using System.Security; using System.Security.Permissions; using System.Text; using System.Windows.Automation.Peers; using System.Windows.Controls; // using System.Windows.Input; using System.Windows.Markup; using System.Windows.Navigation; using System.Windows.Shapes; using MS.Internal; using MS.Internal.AppModel; using System.Windows.Threading; using CommonDependencyProperty=MS.Internal.PresentationFramework.CommonDependencyPropertyAttribute; using SecurityHelper=MS.Internal.PresentationFramework.SecurityHelper; namespace System.Windows.Documents { ////// Implements a Hyperlink element /// [UIPermissionAttribute(SecurityAction.InheritanceDemand, Unrestricted = true)] [TextElementEditingBehaviorAttribute(IsMergeable = false, IsTypographicOnly = false)] public class Hyperlink : Span, ICommandSource, IUriContext { //------------------------------------------------------------------- // // Constructors // //--------------------------------------------------------------------- #region Constructors // // Static Ctor to create default style sheet // static Hyperlink() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Hyperlink), new FrameworkPropertyMetadata(typeof(Hyperlink))); _dType = DependencyObjectType.FromSystemTypeInternal(typeof(Hyperlink)); FocusableProperty.OverrideMetadata(typeof(Hyperlink), new FrameworkPropertyMetadata(true)); EventManager.RegisterClassHandler(typeof(Hyperlink), Mouse.QueryCursorEvent, new QueryCursorEventHandler(OnQueryCursor)); } ////// Initializes a new instance of Hyperlink element. /// ////// To become fully functional this element requires at least one other Inline element /// as its child, typically Run with some text. /// public Hyperlink() : base() { } ////// Initializes a new instance of Hyperlink element and adds a given Inline element as its first child. /// /// /// Inline element added as an initial child to this Hyperlink element /// public Hyperlink(Inline childInline) : base(childInline) { } ////// Creates a new Span instance. /// /// /// Optional child Inline for the new Span. May be null. /// /// /// Optional position at which to insert the new Span. May be null. /// public Hyperlink(Inline childInline, TextPointer insertionPosition) : base(childInline, insertionPosition) { } ////// Creates a new Hyperlink instance covering existing content. /// /// /// Start position of the new Hyperlink. /// /// /// End position of the new Hyperlink. /// ////// start and end must both be parented by the same Paragraph, otherwise /// the method will raise an ArgumentException. /// public Hyperlink(TextPointer start, TextPointer end) : base(start, end) { // After inserting this Hyperlink, we need to extract any child Hyperlinks. TextPointer navigator = this.ContentStart.CreatePointer(); TextPointer stop = this.ContentEnd; while (navigator.CompareTo(stop) < 0) { Hyperlink hyperlink = navigator.GetAdjacentElement(LogicalDirection.Forward) as Hyperlink; if (hyperlink != null) { hyperlink.Reposition(null, null); } else { navigator.MoveToNextContextPosition(LogicalDirection.Forward); } } } #endregion Constructors //-------------------------------------------------------------------- // // Public Methods // //--------------------------------------------------------------------- #region Public Methods ////// This method does exactly the same operation as clicking the Hyperlink with the mouse, except the navigation is not treated as user-initiated. /// public void DoClick() { DoNonUserInitiatedNavigation(this); } #region ICommandSource ////// The DependencyProperty for RoutedCommand /// public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command", typeof(ICommand), typeof(Hyperlink), new FrameworkPropertyMetadata((ICommand)null, new PropertyChangedCallback(OnCommandChanged))); ////// Get or set the Command property /// [Bindable(true), Category("Action")] [Localizability(LocalizationCategory.NeverLocalize)] public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Hyperlink h = (Hyperlink)d; h.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue); } private void OnCommandChanged(ICommand oldCommand, ICommand newCommand) { if (oldCommand != null) { UnhookCommand(oldCommand); } if (newCommand != null) { HookCommand(newCommand); } } private void UnhookCommand(ICommand command) { EventHandler handler = CanExecuteChangedHandler.GetValue(this); if (handler != null) { command.CanExecuteChanged -= handler; CanExecuteChangedHandler.ClearValue(this); } UpdateCanExecute(); } private void HookCommand(ICommand command) { EventHandler handler = new EventHandler(OnCanExecuteChanged); CanExecuteChangedHandler.SetValue(this, handler); command.CanExecuteChanged += handler; UpdateCanExecute(); } private void OnCanExecuteChanged(object sender, EventArgs e) { UpdateCanExecute(); } private void UpdateCanExecute() { if (Command != null) { CanExecute = MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource(this); } else { CanExecute = true; } } private bool CanExecute { get { return _canExecute; } set { if (_canExecute != value) { _canExecute = value; CoerceValue(IsEnabledProperty); } } } // Returns true when this Hyperlink is hosted by an enabled // TextEditor (eg, within a RichTextBox). private bool IsEditable { get { return (this.TextContainer.TextSelection != null && !this.TextContainer.TextSelection.TextEditor.IsReadOnly); } } ////// Fetches the value of the IsEnabled property /// ////// The reason this property is overridden is so that Hyperlink /// can infuse the value for CanExecute into it. /// protected override bool IsEnabledCore { get { return base.IsEnabledCore && CanExecute; } } ////// The DependencyProperty for the CommandParameter /// public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register( "CommandParameter", typeof(object), typeof(Hyperlink), new FrameworkPropertyMetadata((object)null)); ////// Reflects the parameter to pass to the CommandProperty upon execution. /// [Bindable(true), Category("Action")] [Localizability(LocalizationCategory.NeverLocalize)] public object CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } ////// The DependencyProperty for Target property /// Flags: None /// Default Value: null /// public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register( "CommandTarget", typeof(IInputElement), typeof(Hyperlink), new FrameworkPropertyMetadata((IInputElement)null)); ////// The target element on which to fire the command. /// [Bindable(true), Category("Action")] public IInputElement CommandTarget { get { return (IInputElement)GetValue(CommandTargetProperty); } set { SetValue(CommandTargetProperty, value); } } #endregion #endregion Public Methods //-------------------------------------------------------------------- // // Public Properties // //---------------------------------------------------------------------- #region Public Properties ////// Contains the target URI to navigate when hyperlink is clicked /// [CommonDependencyProperty] public static readonly DependencyProperty NavigateUriProperty = DependencyProperty.Register( "NavigateUri", typeof(Uri), typeof(Hyperlink), new FrameworkPropertyMetadata( (Uri)null, new PropertyChangedCallback(OnNavigateUriChanged), new CoerceValueCallback(CoerceNavigateUri))); ////// Coerce value callback for NavigateUri. /// /// Element to coerce NavigateUri for. /// New value for NavigateUri. ///Coerced value. ////// Critical: Implements part of the anti-spoofing feature. /// TreatAsSafe: This method changes no state and returns no protected info. /// [SecurityCritical, SecurityTreatAsSafe] internal static object CoerceNavigateUri(DependencyObject d, object value) { // // If the element for which NavigateUri is being changed is the protected element, // we don't let the update go through. This cancels NavigateUri modifications in // the critical period when the URI is shown on the status bar. // An example attack: // void hl_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) // { // hl.NavigateUri = null; // hl.DoClick(); // hl.NavigateUri = new Uri("http://www.evil.com"); // } // (Or, instead of setting NavigateUri=null, add a handler for Hyperlink.RequestNavigateEvent and // set e.Handled=true.) // if (s_criticalNavigateUriProtectee.Value == d.GetHashCode() && ShouldPreventUriSpoofing) { value = DependencyProperty.UnsetValue; } return value; } ////// Provide public access to NavigateUriProperty property. Content the URI to navigate. /// [Bindable(true), CustomCategory("Navigation")] [Localizability(LocalizationCategory.Hyperlink)] public Uri NavigateUri { get { return (Uri)GetValue(NavigateUriProperty); } set { SetValue(NavigateUriProperty, value); } } ////// Contains the target window to navigate when hyperlink is clicked /// public static readonly DependencyProperty TargetNameProperty = DependencyProperty.Register("TargetName", typeof(String), typeof(Hyperlink), new FrameworkPropertyMetadata(string.Empty)); ////// Provide public access to TargetNameProperty property. The target window to navigate. /// [Bindable(true), CustomCategory("Navigation")] [Localizability( LocalizationCategory.None, Modifiability = Modifiability.Unmodifiable) ] public string TargetName { get { return (string)GetValue(TargetNameProperty); } set { SetValue(TargetNameProperty, value); } } #endregion Public Properties //------------------------------------------------------------------- // // Public Events // //---------------------------------------------------------------------- #region Public Events // ** ////// Navigate Event /// public static readonly RoutedEvent RequestNavigateEvent = EventManager.RegisterRoutedEvent( "RequestNavigate", RoutingStrategy.Bubble, typeof(RequestNavigateEventHandler), typeof(Hyperlink)); ////// Add / Remove RequestNavigateEvent handler /// public event RequestNavigateEventHandler RequestNavigate { add { AddHandler(RequestNavigateEvent, value); } remove { RemoveHandler(RequestNavigateEvent, value); } } ////// Event correspond to left mouse button click /// public static readonly RoutedEvent ClickEvent = System.Windows.Controls.Primitives.ButtonBase.ClickEvent.AddOwner(typeof(Hyperlink)); ////// Add / Remove ClickEvent handler /// [Category("Behavior")] public event RoutedEventHandler Click { add { AddHandler(ClickEvent, value); } remove { RemoveHandler(ClickEvent, value); } } ////// StatusBar event /// internal static readonly RoutedEvent RequestSetStatusBarEvent = EventManager.RegisterRoutedEvent( "RequestSetStatusBar", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Hyperlink)); #endregion Public Events //------------------------------------------------------------------- // // Protected Methods // //--------------------------------------------------------------------- #region Protected Methods ////// This is the method that responds to the MouseButtonEvent event. /// /// Event arguments ///Kept around for backward compatibility in derived classes. protected internal override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); if (IsEnabled && (!IsEditable || ((Keyboard.Modifiers & ModifierKeys.Control) != 0))) { OnMouseLeftButtonDown(this, e); } } ////// This is the method that responds to the MouseButtonEvent event. /// /// Event arguments ////// Added for the NavigateUri = null case, which won't have event handlers hooked /// up since OnNavigateUriChanged isn't ever called. However, we want to have the /// sequence of commands and Click event triggered even in this case for Hyperlink. /// ////// Critical - Calls critical static OnMouseLeftButtonUp. /// [SecurityCritical] protected internal override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); OnMouseLeftButtonUp(this, e); } #region Spoofing prevention and status bar access ////// Cached URI for spoofing countermeasures. /// ////// We keep one per thread in case multiple threads would be involved in the spoofing attack. /// ////// Critical for set - Changing the cached URI can open up for spoofing attacks. /// [ThreadStatic] private static SecurityCriticalDataForSets_cachedNavigateUri; /// /// Identification code of the hyperlink element currently protected against spoofing attacks. /// This code is checked during the NavigateUri coerce value callback in order to protect the /// NavigateUri from changing during the critical period between showing the URI on the status /// bar and clearing it, which is the timeframe where spoofing attacks can occur. /// ////// We keep one per thread in case multiple threads would be involved in the spoofing attack. /// ////// Critical for set - Changing the identification code will make the element vulnerable /// for spoofing. /// [ThreadStatic] private static SecurityCriticalDataForSets_criticalNavigateUriProtectee; /// /// Caches a target URI for spoofing prevention. /// /// Hyperlink object for which the target URI is to be cached. /// Target URI the user expects to be navigate to. ////// Critical - Sets the cached URI that prevents spoofing attacks. /// [SecurityCritical] private static void CacheNavigateUri(DependencyObject d, Uri targetUri) { // // This prevents against multi-threaded spoofing attacks. // d.VerifyAccess(); s_cachedNavigateUri.Value = targetUri; } ////// Navigates to the specified URI if it matches the pre-registered cached target URI (spoofing prevention). /// /// Source for the RequestNavigateEventArgs. /// URI to navigate to. /// Target window for the RequestNavigateEventArgs. ////// Critical - Implements the anti-spoofing mechanism and clears the anti-spoofing cache after navigation took place. /// TreatAsSafe - Navigation is considered safe; if the target is a browser window the UserInitiatedNavigationPermission will be demanded. /// Only if navigation took place, the anti-spoofing cache will be cleared. /// [SecurityCritical, SecurityTreatAsSafe] private static void NavigateToUri(IInputElement sourceElement, Uri targetUri, string targetWindow) { Debug.Assert(targetUri != null); // // This prevents against multi-threaded spoofing attacks. // DependencyObject dObj = (DependencyObject)sourceElement; dObj.VerifyAccess(); // // Spoofing countermeasure makes sure the URI hasn't changed since display in the status bar. // Uri cachedUri = Hyperlink.s_cachedNavigateUri.Value; // ShouldPreventUriSpoofing is checked last in order to avoid incurring a first-chance SecurityException // in common scenarios. if (cachedUri == null || cachedUri.Equals(targetUri) || !ShouldPreventUriSpoofing) { // // We treat FixedPage seperately to maintain backward compatibility // with the original separate FixedPage implementation of this, which // calls the GetLinkUri method. if (!(sourceElement is Hyperlink)) { targetUri = FixedPage.GetLinkUri(sourceElement, targetUri); } RequestNavigateEventArgs navigateArgs = new RequestNavigateEventArgs(targetUri, targetWindow); navigateArgs.Source = sourceElement; sourceElement.RaiseEvent(navigateArgs); if (navigateArgs.Handled) { // // The browser's status bar should be cleared. Otherwise it will still show the // hyperlink address after navigation has completed. // !! We have to do this after the current callstack is unwound in order to keep // the anti-spoofing state valid. A particular attach is to do a bogus call to // DoClick() in a mouse click preview event and then change the NavigateUri. // dObj.Dispatcher.BeginInvoke(DispatcherPriority.Send, new System.Threading.SendOrPostCallback(ClearStatusBarAndCachedUri), sourceElement); } } } ////// Updates the status bar to reflect the current NavigateUri. /// ////// Critical - Sets the cached URI (CacheNavigateUri) and s_criticalNavigateUriProtectee /// which prevent spoofing attacks. /// Calls the critical RequestSetStatusBarEventArgs ctor. /// [SecurityCritical] private static void UpdateStatusBar(object sender) { IInputElement element = (IInputElement)sender; DependencyObject dObject = (DependencyObject)sender; Uri targetUri = (Uri)dObject.GetValue(GetNavigateUriProperty(element)); // // Keep the identification code for the element that's to be protected against spoofing // attacks because its URI is shown on the status bar. // s_criticalNavigateUriProtectee.Value = dObject.GetHashCode(); // // Cache URI for spoofing countermeasures. // CacheNavigateUri(dObject, targetUri); RequestSetStatusBarEventArgs args = new RequestSetStatusBarEventArgs(targetUri); element.RaiseEvent(args); } // The implementation of Hyperlink.NavigateUri and FixedPage.NavigateUri are unified, // but the DPs themselves are not. FixedPage.NavigateUri is attached; Hyperlink.Navigate // is a regular DP. Use this method to get the property DP based on the element. private static DependencyProperty GetNavigateUriProperty(object element) { Hyperlink hl = element as Hyperlink; return (hl == null) ? FixedPage.NavigateUriProperty : NavigateUriProperty; } ////// Clears the status bar. /// ////// Critical - Clears the cached URI and s_criticalNavigateUriProtectee which prevent /// spoofing attacks. /// Note: Upstream spoofing should be prevented (e.g. OnMouseLeave) because /// clearing the identification code in s_criticalNavigateUriProtectee /// will disable spoofing detection. /// [SecurityCritical] private static void ClearStatusBarAndCachedUri(object sender) { IInputElement element = (IInputElement)sender; // // Clear the status bar first, from this point on we're not protecting against spoofing // anymore. // element.RaiseEvent(RequestSetStatusBarEventArgs.Clear); // // Invalidate cache URI for spoofing countermeasures. // CacheNavigateUri((DependencyObject)sender, null); // // Clear the identification code for the element that was protected against spoofing. // s_criticalNavigateUriProtectee.Value = null; } #endregion ////// Navigate to URI specified in NavigateUri property and mark the hyperlink as visited /// ////// Some forms of navigation are not allowed in the internet zone. /// As such there are cases where this API will demand for fulltrust. /// /// This method is kept of backward compatibility and isn't a real event handler anymore. /// It should remain in here however for subclasses that want to override it either to /// redefine behavior or to get notified about the click event. /// protected virtual void OnClick() { if (AutomationPeer.ListenerExists(AutomationEvents.InvokePatternOnInvoked)) { AutomationPeer peer = ContentElementAutomationPeer.CreatePeerForElement(this); if (peer != null) peer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked); } DoNavigation(this); RaiseEvent(new RoutedEventArgs(Hyperlink.ClickEvent, this)); MS.Internal.Commands.CommandHelpers.ExecuteCommandSource(this); } ////// This is the method that responds to the KeyDown event. /// ////// This method is kept for backward compatibility. /// ////// Critical - Calls into static critical OnKeyDown method. /// [SecurityCritical] protected internal override void OnKeyDown(KeyEventArgs e) { if (!e.Handled && e.Key == Key.Enter) { OnKeyDown(this, e); } else { base.OnKeyDown(e); } } // // This property // 1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject // 2. This is a performance optimization // internal override int EffectiveValuesInitialSize { get { return 19; } } ////// Creates AutomationPeer ( protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer() { return new System.Windows.Automation.Peers.HyperlinkAutomationPeer(this); } #endregion Protected Methods #region IUriContext implementation ///) /// /// IUriContext interface is implemented by Hyperlink element so that it /// can hold on to the base URI used by parser. /// The base URI is needed to resolve NavigateUri property /// ///Base Uri Uri IUriContext.BaseUri { get { return BaseUri; } set { BaseUri = value; } } ////// Implementation for BaseUri /// protected virtual Uri BaseUri { get { return (Uri)GetValue(BaseUriHelper.BaseUriProperty); } set { SetValue(BaseUriHelper.BaseUriProperty, value); } } #endregion IUriContext implementation //------------------------------------------------------------------- // // Internal Properties // //---------------------------------------------------------------------- #region Internal Properties ////// The content spanned by this Hyperlink represented as plain text. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] internal string Text { get { return TextRangeBase.GetTextInternal(this.ContentStart, this.ContentEnd); } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //---------------------------------------------------------------------- #region Private Methods // QueryCursorEvent callback. // If this Hyperlink is editable, use the editor cursor unless // the control key is down. private static void OnQueryCursor(object sender, QueryCursorEventArgs e) { Hyperlink link = (Hyperlink)sender; if (link.IsEnabled && link.IsEditable) { if ((Keyboard.Modifiers & ModifierKeys.Control) == 0) { e.Cursor = link.TextContainer.TextSelection.TextEditor._cursor; e.Handled = true; } } } #endregion Private Methods #region Private Properties //-------------------------------------------------------------------- // // Private Properties // //--------------------------------------------------------------------- ////// Critical: Sets s_shouldPreventUriSpoofing. /// Not TreatAsSafe just to help prevent the remote possibility of calling this under elevation /// from framework code, since the result of the Demand is cached. /// static bool ShouldPreventUriSpoofing { [SecurityCritical] get { if (!s_shouldPreventUriSpoofing.Value.HasValue) { try { (new System.Net.WebPermission(PermissionState.Unrestricted)).Demand(); s_shouldPreventUriSpoofing.Value = false; } catch (SecurityException) { s_shouldPreventUriSpoofing.Value = true; } } return (bool)s_shouldPreventUriSpoofing.Value; } } static SecurityCriticalDataForSets_shouldPreventUriSpoofing; #endregion Private Properties //-------------------------------------------------------------------- // // Private Fields // //--------------------------------------------------------------------- #region Private Fields private bool _canExecute = true; private static readonly UncommonField CanExecuteChangedHandler = new UncommonField (); #endregion Private Fields //------------------------------------------------------------------- // // Navigation control // //--------------------------------------------------------------------- #region Navigation control /// /// Records the IsPressed property attached to elements with hyperlink functionality. /// private static readonly DependencyProperty IsHyperlinkPressedProperty = DependencyProperty.Register( "IsHyperlinkPressed", typeof(bool), typeof(Hyperlink), new FrameworkPropertyMetadata(false)); internal static void OnNavigateUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { IInputElement element = d as IInputElement; // // We only set up spoofing prevention for known objects that are IInputElements. // However, for backward compatibility we shouldn't make this callback fail since // other places such as FixedTextBuilder use NavigateUri e.g. for serialization. // if (element != null) { Uri navigateUri = (Uri)e.NewValue; // // We use a different code path for Path, Canvas, Glyphs and FixedPage to maintain backward compatibility // with the original separate Hyperlink implementation of this (which didn't execute CanNavigateToUri). // if (navigateUri != null) { FrameworkElement fe = d as FrameworkElement; if (fe != null && ((fe is Path) || (fe is Canvas) || (fe is Glyphs) || (fe is FixedPage))) { if (FixedPage.CanNavigateToUri(navigateUri)) { SetUpNavigationEventHandlers(element); fe.Cursor = Cursors.Hand; } else { fe.Cursor = Cursors.No; } } else { FrameworkContentElement fce = d as FrameworkContentElement; if (fce != null && (fce is Hyperlink)) { SetUpNavigationEventHandlers(element); } } } } } ////// Critical - Hooks up event handlers that are responsible to set up anti-spoofing mitigations /// and event handlers that are critical because of the risk for replay attacks. /// TreatAsSafe - We're hooking up event handlers for trusted events from the input system. /// [SecurityCritical, SecurityTreatAsSafe] private static void SetUpNavigationEventHandlers(IInputElement element) { // // We only support FixedPage.NavigateUri to be attached to those four elements (aka pseudo-hyperlinks): // Path, Canvas, Glyph, FixedPage. // // We can get away with the UIElement events event for the Hyperlink which is a ContentElement // because of the aliasing present on those. // // // Hyperlink already has instance handlers for the following events. To avoid handling the event twice, // we only hook up the static handlers for pseudo-hyperlinks. // if (!(element is Hyperlink)) { SetUpEventHandler(element, UIElement.KeyDownEvent, new KeyEventHandler(OnKeyDown)); //initiates navigation SetUpEventHandler(element, UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonDown)); //capture hyperlink pressed state SetUpEventHandler(element, UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(OnMouseLeftButtonUp)); //can initiate navigation } SetUpEventHandler(element, UIElement.MouseEnterEvent, new MouseEventHandler(OnMouseEnter)); //set status bar SetUpEventHandler(element, UIElement.MouseLeaveEvent, new MouseEventHandler(OnMouseLeave)); //clear status bar } private static void SetUpEventHandler(IInputElement element, RoutedEvent routedEvent, Delegate handler) { // // Setting NavigateUri causes navigation event handlers to be set up. // Doing this repeatedly would keep adding handlers; therefore remove any handler first. // element.RemoveHandler(routedEvent, handler); element.AddHandler(routedEvent, handler); } ////// This is the method that responds to the KeyDown event. /// ////// Critical - Calls DoUserInitiatedNavigation. We also want to protect against replay attacks. /// [SecurityCritical] private static void OnKeyDown(object sender, KeyEventArgs e) { if (!e.Handled && e.Key == Key.Enter) { // // Keyboard navigation doesn't reveal the URL on the status bar, so there's no spoofing // attack possible. We clear the cache here and allow navigation to go through. // CacheNavigateUri((DependencyObject)sender, null); if (e.UserInitiated) { DoUserInitiatedNavigation(sender); } else { DoNonUserInitiatedNavigation(sender); } e.Handled = true; } } ////// This is the method that responds to the MouseLeftButtonEvent event. /// private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { IInputElement element = (IInputElement)sender; DependencyObject dp = (DependencyObject)sender; // Hyperlink should take focus when left mouse button is clicked on it // This is consistent with all ButtonBase controls and current Win32 behavior element.Focus(); // It is possible that the mouse state could have changed during all of // the call-outs that have happened so far. if (e.ButtonState == MouseButtonState.Pressed) { // Capture the mouse, and make sure we got it. Mouse.Capture(element); if (element.IsMouseCaptured) { // Though we have already checked this state, our call to CaptureMouse // could also end up changing the state, so we check it again. // // ISSUE - Leave this here because of 1111993. // if (e.ButtonState == MouseButtonState.Pressed) { dp.SetValue(IsHyperlinkPressedProperty, true); } else { // Release capture since we decided not to press the button. element.ReleaseMouseCapture(); } } } e.Handled = true; } ////// This is the method that responds to the MouseLeftButtonUpEvent event. /// ////// Critical - Calls DoUserInitiatedNavigation. We also want to protect against replay attacks /// and can't assume the IsHyperlinkPressed DP hasn't been tampered with. /// [SecurityCritical] private static void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { IInputElement element = (IInputElement)sender; DependencyObject dp = (DependencyObject)sender; if (element.IsMouseCaptured) { element.ReleaseMouseCapture(); } // // ISSUE - Leave this here because of 1111993. // if ((bool)dp.GetValue(IsHyperlinkPressedProperty)) { dp.SetValue(IsHyperlinkPressedProperty, false); // Make sure we're mousing up over the hyperlink if (element.IsMouseOver) { if (e.UserInitiated) { DoUserInitiatedNavigation(sender); } else { DoNonUserInitiatedNavigation(sender); } } } e.Handled = true; } ////// Fire the event to change the status bar. /// ////// Critical - Calls UpdateStatusBar to set the cached URI that prevents spoofing attacks. /// [SecurityCritical] private static void OnMouseEnter(object sender, MouseEventArgs e) { UpdateStatusBar(sender); } ////// Set the status bar text back to empty /// ////// Critical - Calls ClearStatusBarAndCachedUri to clear the cached URI that prevents spoofing attacks. /// [SecurityCritical] private static void OnMouseLeave(object sender, MouseEventArgs e) { IInputElement ee = (IInputElement)sender; // // Prevent against replay attacks. We expect the mouse not to be over the // element, otherwise someone tries to circumvent the spoofing countermeasures // while we're in the critical period between OnMouseEnter and OnMouseLeave. // if (!ee.IsMouseOver) { ClearStatusBarAndCachedUri(sender); } } ////// Critical - Asserts UserInitatedNavigationPermission. /// [SecurityCritical] private static void DoUserInitiatedNavigation(object sender) { CodeAccessPermission perm = SecurityHelper.CreateUserInitiatedNavigationPermission(); perm.Assert(); try { DispatchNavigation(sender); } finally { CodeAccessPermission.RevertAssert(); } } ////// Critical - Sets the cached URI that prevents spoofing attacks. /// TreatAsSafe - We don't prevent spoofing in non user-initiated scenarios. /// [SecurityCritical, SecurityTreatAsSafe] private static void DoNonUserInitiatedNavigation(object sender) { CacheNavigateUri((DependencyObject)sender, null); DispatchNavigation(sender); } ////// Dispatches navigation; if the object is a Hyperlink we go through OnClick /// to preserve the original event chain, otherwise we call our DoNavigation /// method. /// private static void DispatchNavigation(object sender) { Hyperlink hl = sender as Hyperlink; if (hl != null) { // // Call the virtual OnClick on Hyperlink to keep old behavior. // hl.OnClick(); } else { DoNavigation(sender); } } ////// Navigate to URI specified in the object's NavigateUri property. /// private static void DoNavigation(object sender) { IInputElement element = (IInputElement)sender; DependencyObject dObject = (DependencyObject)sender; Uri inputUri = (Uri)dObject.GetValue(GetNavigateUriProperty(element)); string targetWindow = (string)dObject.GetValue(TargetNameProperty); RaiseNavigate(element, inputUri, targetWindow); } ////// Navigate to URI. Used by OnClick and by automation. /// /// Source for the RequestNavigateEventArgs. /// URI to navigate to. /// Target window for the RequestNavigateEventArgs. internal static void RaiseNavigate(IInputElement element, Uri targetUri, string targetWindow) { // // Do secure (spoofing countermeasures) navigation. // if (targetUri != null) { NavigateToUri(element, targetUri, targetWindow); } } #endregion #region DTypeThemeStyleKey // Returns the DependencyObjectType for the registered ThemeStyleKey's default // value. Controls will override this method to return approriate types. internal override DependencyObjectType DTypeThemeStyleKey { get { return _dType; } } private static DependencyObjectType _dType; #endregion DTypeThemeStyleKey } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- CompositeDispatchFormatter.cs
- Clock.cs
- nulltextnavigator.cs
- HttpCacheParams.cs
- _ProxyRegBlob.cs
- ScriptResourceInfo.cs
- ToolStripMenuItem.cs
- NetworkInterface.cs
- EntityDataSourceChangedEventArgs.cs
- LeaseManager.cs
- ValueType.cs
- DataControlFieldCell.cs
- processwaithandle.cs
- MessageContractMemberAttribute.cs
- WebControl.cs
- XPathNodeIterator.cs
- Descriptor.cs
- PublisherIdentityPermission.cs
- HwndStylusInputProvider.cs
- CategoryEditor.cs
- Icon.cs
- TogglePattern.cs
- PropertyMappingExceptionEventArgs.cs
- MetadataItemSerializer.cs
- InheritanceRules.cs
- PopOutPanel.cs
- recordstate.cs
- _FtpControlStream.cs
- LocalizedNameDescriptionPair.cs
- TextModifier.cs
- FileLoadException.cs
- DataGridViewImageColumn.cs
- InputLangChangeRequestEvent.cs
- XPathItem.cs
- ZipIOExtraFieldZip64Element.cs
- Semaphore.cs
- IsolatedStorageFilePermission.cs
- Stack.cs
- ToolboxItemFilterAttribute.cs
- PropertyPath.cs
- GridViewItemAutomationPeer.cs
- AbandonedMutexException.cs
- XmlSchemaCompilationSettings.cs
- NetStream.cs
- ArgumentException.cs
- FrameDimension.cs
- NullableLongSumAggregationOperator.cs
- SqlDataSourceCommandEventArgs.cs
- EntityDataSourceDesigner.cs
- OdbcCommandBuilder.cs
- AnimationTimeline.cs
- HtmlContainerControl.cs
- _TimerThread.cs
- XmlIlTypeHelper.cs
- FixUpCollection.cs
- TextBoxView.cs
- HitTestParameters3D.cs
- SqlLiftWhereClauses.cs
- DiagnosticStrings.cs
- TdsParserSafeHandles.cs
- BaseCollection.cs
- DecoratedNameAttribute.cs
- TypeResolver.cs
- GenericIdentity.cs
- EnumValAlphaComparer.cs
- ConfigXmlSignificantWhitespace.cs
- SecurityContextTokenValidationException.cs
- ValueUnavailableException.cs
- AmbiguousMatchException.cs
- DesignerAttribute.cs
- XmlDataSourceNodeDescriptor.cs
- uribuilder.cs
- DeviceSpecificChoice.cs
- BinHexDecoder.cs
- SchemaNamespaceManager.cs
- FontCollection.cs
- RoutedEventHandlerInfo.cs
- Enlistment.cs
- StringValidator.cs
- RouteParameter.cs
- ResourcePermissionBase.cs
- ViewgenGatekeeper.cs
- XmlDictionaryString.cs
- DictionaryBase.cs
- FixedNode.cs
- SiblingIterators.cs
- CodeSnippetCompileUnit.cs
- WebServiceData.cs
- DateTimeUtil.cs
- ListViewItem.cs
- BulletChrome.cs
- OleDbCommandBuilder.cs
- ScriptModule.cs
- ChildrenQuery.cs
- ImageKeyConverter.cs
- PerformanceCounterPermissionEntryCollection.cs
- FileReservationCollection.cs
- ProfessionalColors.cs
- InstanceNotReadyException.cs
- Preprocessor.cs