|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Specialized;
using MS.Internal;
namespace System.Windows
{
/// <summary>
/// The container for all state associated
/// with a RoutedEvent
/// </summary>
/// <remarks>
/// <see cref="RoutedEventArgs"/>
/// constitutes the <para/>
/// <see cref="RoutedEventArgs.RoutedEvent"/>, <para/>
/// <see cref="RoutedEventArgs.Handled"/>, <para/>
/// <see cref="RoutedEventArgs.Source"/> and <para/>
/// <see cref="RoutedEventArgs.OriginalSource"/> <para/>
/// <para/>
///
/// Different <see cref="RoutedEventArgs"/>
/// can be used with a single <see cref="RoutedEvent"/> <para/>
/// <para/>
///
/// The <see cref="RoutedEventArgs"/> is responsible
/// for packaging the <see cref="RoutedEvent"/>,
/// providing extra event state info, and invoking the
/// handler associated with the RoutedEvent
/// </remarks>
public class RoutedEventArgs : EventArgs
{
#region Construction
/// <summary>
/// Constructor for <see cref="RoutedEventArgs"/>
/// </summary>
/// <remarks>
/// All members take default values <para/>
/// <para/>
///
/// <see cref="RoutedEventArgs.RoutedEvent"/>
/// defaults to null <para/>
/// <see cref="RoutedEventArgs.Handled"/> defaults to
/// false <para/>
/// <see cref="Source"/> defaults to null <para/>
/// <see cref="OriginalSource"/> also defaults to null
/// <para/>
/// </remarks>
public RoutedEventArgs()
{
}
/// <summary>
/// Constructor for <see cref="RoutedEventArgs"/>
/// </summary>
/// <param name="routedEvent">The new value that the RoutedEvent Property is being set to </param>
public RoutedEventArgs(RoutedEvent routedEvent) : this( routedEvent, null)
{
}
/// <summary>
/// Constructor for <see cref="RoutedEventArgs"/>
/// </summary>
/// <param name="source">The new value that the SourceProperty is being set to </param>
/// <param name="routedEvent">The new value that the RoutedEvent Property is being set to </param>
public RoutedEventArgs(RoutedEvent routedEvent, object source)
{
_routedEvent = routedEvent;
_source = _originalSource = source;
}
#endregion Construction
#region External API
/// <summary>
/// Returns the <see cref="RoutedEvent"/> associated
/// with this <see cref="RoutedEventArgs"/>
/// </summary>
/// <remarks>
/// The <see cref="RoutedEvent"/> cannot be null
/// at any time
/// </remarks>
public RoutedEvent RoutedEvent
{
get {return _routedEvent;}
set
{
if (UserInitiated && InvokingHandler)
throw new InvalidOperationException(SR.RoutedEventCannotChangeWhileRouting);
_routedEvent = value;
}
}
/// <summary>
/// Changes the RoutedEvent assocatied with these RoutedEventArgs
/// </summary>
/// <remarks>
/// Only used internally. Added to support cracking generic MouseButtonDown/Up events
/// into MouseLeft/RightButtonDown/Up events.
/// </remarks>
/// <param name="newRoutedEvent">
/// The new RoutedEvent to associate with these RoutedEventArgs
/// </param>
internal void OverrideRoutedEvent( RoutedEvent newRoutedEvent )
{
_routedEvent = newRoutedEvent;
}
/// <summary>
/// Returns a boolean flag indicating if or not this
/// RoutedEvent has been handled this far in the route
/// </summary>
/// <remarks>
/// Initially starts with a false value before routing
/// has begun
/// </remarks>
public bool Handled
{
get
{
return _flags[ HandledIndex ] ;
}
set
{
if (_routedEvent == null)
{
throw new InvalidOperationException(SR.RoutedEventArgsMustHaveRoutedEvent);
}
if( TraceRoutedEvent.IsEnabled )
{
TraceRoutedEvent.TraceActivityItem(
TraceRoutedEvent.HandleEvent,
value,
RoutedEvent.OwnerType.Name,
RoutedEvent.Name,
this );
}
// Note: We need to allow the caller to change the handled value
// from true to false.
//
// We are concerned about scenarios where a child element
// listens to a high-level event (such as TextInput) while a
// parent element listens tp a low-level event such as KeyDown.
// In these scenarios, we want the parent to not respond to the
// KeyDown event, in deference to the child.
//
// Internally we implement this by asking the parent to only
// respond to KeyDown events if they have focus. This works
// around the problem and is an example of an unofficial
// protocol coordinating the two elements.
//
// But we imagine that there will be some cases we miss or
// that third parties introduce. For these cases, we expect
// that the application author may need to mark the KeyDown
// as handled in the child, and then reset the event to
// being unhandled after the parent, so that default processing
// and promotion still occur.
//
// For more information see the following task:
// 20284: Input promotion breaks down when lower level input is intercepted
_flags[ HandledIndex ] = value;
}
}
/// <summary>
/// Returns Source object that raised the RoutedEvent
/// </summary>
public object Source
{
get {return _source;}
set
{
if (InvokingHandler && UserInitiated)
throw new InvalidOperationException(SR.RoutedEventCannotChangeWhileRouting);
if (_routedEvent == null)
{
throw new InvalidOperationException(SR.RoutedEventArgsMustHaveRoutedEvent);
}
object source = value ;
if (_source == null && _originalSource == null)
{
// Gets here when it is the first time that the source is set.
// This implies that this is also the original source of the event
_source = _originalSource = source;
OnSetSource(source);
}
else if (_source != source)
{
// This is the actiaon taken at all other times when the
// source is being set to a different value from what it was
_source = source;
OnSetSource(source);
}
}
}
/// <summary>
/// Changes the Source assocatied with these RoutedEventArgs
/// </summary>
/// <remarks>
/// Only used internally. Added to support cracking generic MouseButtonDown/Up events
/// into MouseLeft/RightButtonDown/Up events.
/// </remarks>
/// <param name="source">
/// The new object to associate as the source of these RoutedEventArgs
/// </param>
internal void OverrideSource( object source )
{
_source = source;
}
/// <summary>
/// Returns OriginalSource object that raised the RoutedEvent
/// </summary>
/// <remarks>
/// Always returns the OriginalSource object that raised the
/// RoutedEvent unlike <see cref="RoutedEventArgs.Source"/>
/// that may vary under specific scenarios <para/>
/// This property acquires its value once before the event
/// handlers are invoked and never changes then on
/// </remarks>
public object OriginalSource
{
get {return _originalSource;}
}
/// <summary>
/// Invoked when the source of the event is set
/// </summary>
/// <remarks>
/// Changing the source of an event can often
/// require updating the data within the event.
/// For this reason, the OnSource= method is
/// protected virtual and is meant to be
/// overridden by sub-classes of
/// <see cref="RoutedEventArgs"/> <para/>
/// Also see <see cref="RoutedEventArgs.Source"/>
/// </remarks>
/// <param name="source">
/// The new value that the SourceProperty is being set to
/// </param>
protected virtual void OnSetSource(object source)
{
}
/// <summary>
/// Invokes the generic handler with the
/// appropriate arguments
/// </summary>
/// <remarks>
/// Is meant to be overridden by sub-classes of
/// <see cref="RoutedEventArgs"/> to provide
/// more efficient invocation of their delegate
/// </remarks>
/// <param name="genericHandler">
/// Generic Handler to be invoked
/// </param>
/// <param name="genericTarget">
/// Target on whom the Handler will be invoked
/// </param>
protected virtual void InvokeEventHandler(Delegate genericHandler, object genericTarget)
{
ArgumentNullException.ThrowIfNull(genericHandler);
ArgumentNullException.ThrowIfNull(genericTarget);
if (_routedEvent == null)
{
throw new InvalidOperationException(SR.RoutedEventArgsMustHaveRoutedEvent);
}
InvokingHandler = true;
try
{
if (genericHandler is RoutedEventHandler)
{
((RoutedEventHandler)genericHandler)(genericTarget, this);
}
else
{
// Restricted Action - reflection permission required
genericHandler.DynamicInvoke(new object[] {genericTarget, this});
}
}
finally
{
InvokingHandler = false;
}
}
#endregion External API
#region Operations
// Calls the InvokeEventHandler protected
// virtual method
//
// This method is needed because
// delegates are invoked from
// RoutedEventHandler which is not a
// sub-class of RoutedEventArgs
// and hence cannot invoke protected
// method RoutedEventArgs.FireEventHandler
internal void InvokeHandler(Delegate handler, object target)
{
InvokingHandler = true;
try
{
InvokeEventHandler(handler, target);
}
finally
{
InvokingHandler = false;
}
}
internal bool UserInitiated
{
get
{
if (_flags [UserInitiatedIndex])
{
return true;
}
return false;
}
}
internal void MarkAsUserInitiated()
{
_flags [ UserInitiatedIndex ] = true;
}
internal void ClearUserInitiated()
{
_flags [ UserInitiatedIndex ] = false ;
}
private bool InvokingHandler
{
get
{
return _flags[InvokingHandlerIndex];
}
set
{
_flags[InvokingHandlerIndex] = value;
}
}
#endregion Operations
#region Data
private RoutedEvent _routedEvent;
private object _source;
private object _originalSource;
private BitVector32 _flags;
private const int HandledIndex = 1;
private const int UserInitiatedIndex = 2;
private const int InvokingHandlerIndex = 4;
#endregion Data
}
/// <summary>
/// RoutedEventHandler Definition
/// </summary>
/// <ExternalAPI/>
public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);
}
|