|
using System;
using System.Collections;
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Threading;
using System.Security;
using System.Security.Permissions;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Markup;
using System.Windows.Input;
using MS.Win32;
using MS.Utility;
using MS.Internal;
using MS.Internal.PresentationCore; // SecurityHelper
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
namespace System.Windows
{
/// <summary>
/// PresentationSource is the abstract base for classes that
/// present content in another technology. In addition, this
/// class provides static methods for working with these sources.
/// </summary>
/// <remarks>
/// We currently have one implementation - HwndSource - that
/// presents content in a Win32 HWND.
/// </remarks>
/// <SecurityNote>
/// Keep this from being derived from in partial-trust code.
/// </SecurityNote>
[UIPermissionAttribute(SecurityAction.InheritanceDemand,Unrestricted=true)]
public abstract class PresentationSource : DispatcherObject
{
//------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
/// <summary>
/// Constructs an instance of the PresentationSource object.
/// </summary>
/// <remarks>
/// This is protected since this is an abstract base class.
/// </remarks>
protected PresentationSource()
{
}
/// <SecurityNote>
/// This constructor exists since the code gen for managed code generates a static constructor
/// and in that code it initializes a critical field which causes an fxcop violation for the codegen
/// constructor.
/// </SecurityNote>
[SecurityCritical]
static PresentationSource()
{
}
#endregion
//------------------------------------------------------
//
// Public Methods
//
//------------------------------------------------------
#region Public Methods
/// <summary>
/// InputProvider given the Device type.
/// </summary>
/// <SecurityNote>
/// Critical: Sub classing this can let you provide fake input providers which
/// can compromise the input system
/// </SecurityNote>
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.InheritanceDemand, Unrestricted = true)]
internal virtual IInputProvider GetInputProvider(Type inputDevice)
{
return null;
}
#endregion
//------------------------------------------------------
//
// Public Static Methods
//
//------------------------------------------------------
#region Public Static Methods
/// <summary>
/// Returns the source in which the visual is being presented.
/// </summary>
/// <param name="visual">The visual to find the source for.</param>
/// <returns>The source in which the visual is being presented.</returns>
///<remarks>
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///</remarks>
/// <SecurityNote>
/// Critical - calls CriticalFromVisual. and returns the PresentationSource
/// PublicOK: There exists a demand
/// </SecurityNote>
[SecurityCritical]
public static PresentationSource FromVisual(Visual visual)
{
SecurityHelper.DemandUIWindowPermission();
return CriticalFromVisual(visual);
}
/// <summary>
/// Returns the source in which the Visual or Visual3D is being presented.
/// </summary>
/// <param name="dependencyObject">The dependency object to find the source for.</param>
/// <returns>The source in which the dependency object is being presented.</returns>
///<remarks>
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///</remarks>
/// <SecurityNote>
/// Critical - calls CriticalFromVisual. and returns the PresentationSource
/// PublicOK: There exists a demand
/// </SecurityNote>
[SecurityCritical]
public static PresentationSource FromDependencyObject(DependencyObject dependencyObject)
{
SecurityHelper.DemandUIWindowPermission();
return CriticalFromVisual(dependencyObject);
}
/// <summary>
/// Adds a handler for the SourceChanged event to the element.
/// </summary>
/// <param name="element">The element to add the handler too.</param>
/// <param name="handler">The hander to add.</param>
/// <remarks>
/// Even though this is a routed event handler, there are special
/// restrictions placed on this event.
/// 1) You cannot use the UIElement or ContentElement AddHandler() method.
/// 2) Class handlers are not allowed.
/// 3) The handlers will receive the SourceChanged event even if it was handled.
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
/// </remarks>
/// <SecurityNote>
/// Critical: This code lets you get access to a presentationSource object. Here the link demand
/// is defense in depth since , the object by itself has all public properties blocked off. Also this
/// is part of startup code.
/// </SecurityNote>
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.LinkDemand,Window=UIPermissionWindow.AllWindows)]
public static void AddSourceChangedHandler(IInputElement element, SourceChangedEventHandler handler)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
// Either UIElement or ContentElement
if (!InputElement.IsValid(element))
{
throw new ArgumentException(SR.Get(SRID.Invalid_IInputElement), "element");
}
DependencyObject o = (DependencyObject)element;
// o.VerifyAccess();
// I would rather throw an exception here, but the CLR doesn't
// so we won't either.
if (handler != null)
{
FrugalObjectList<RoutedEventHandlerInfo> info;
if (InputElement.IsUIElement(o))
{
UIElement uie = o as UIElement;
uie.AddHandler(SourceChangedEvent, handler);
info = uie.EventHandlersStore[SourceChangedEvent];
if (1 == info.Count)
{
uie.VisualAncestorChanged += new Visual.AncestorChangedEventHandler(uie.OnVisualAncestorChanged);
AddElementToWatchList(uie);
}
}
else if (InputElement.IsUIElement3D(o))
{
UIElement3D uie3D = o as UIElement3D;
uie3D.AddHandler(SourceChangedEvent, handler);
info = uie3D.EventHandlersStore[SourceChangedEvent];
if (1 == info.Count)
{
uie3D.VisualAncestorChanged += new Visual.AncestorChangedEventHandler(uie3D.OnVisualAncestorChanged);
AddElementToWatchList(uie3D);
}
}
else
{
ContentElement ce = o as ContentElement;
ce.AddHandler(SourceChangedEvent, handler);
info = ce.EventHandlersStore[SourceChangedEvent];
if (1 == info.Count)
AddElementToWatchList(ce);
}
}
}
/// <summary>
/// Removes a handler for the SourceChanged event to the element.
/// </summary>
/// <param name="e">The element to remove the handler from.</param>
/// <param name="handler">The hander to remove.</param>
/// <remarks>
/// Even though this is a routed event handler, there are special
/// restrictions placed on this event.
/// 1) You cannot use the UIElement or ContentElement RemoveHandler() method.
/// </remarks>
public static void RemoveSourceChangedHandler(IInputElement e, SourceChangedEventHandler handler)
{
if (e == null)
{
throw new ArgumentNullException("e");
}
if (!InputElement.IsValid(e))
{
throw new ArgumentException(SR.Get(SRID.Invalid_IInputElement), "e");
}
DependencyObject o = (DependencyObject)e;
// o.VerifyAccess();
// I would rather throw an exception here, but the CLR doesn't
// so we won't either.
if (handler != null)
{
FrugalObjectList<RoutedEventHandlerInfo> info = null;
EventHandlersStore store;
// Either UIElement or ContentElement.
if (InputElement.IsUIElement(o))
{
UIElement uie = o as UIElement;
uie.RemoveHandler(SourceChangedEvent, handler);
store = uie.EventHandlersStore;
if (store != null)
{
info = store[SourceChangedEvent];
}
if (info == null || info.Count == 0)
{
uie.VisualAncestorChanged -= new Visual.AncestorChangedEventHandler(uie.OnVisualAncestorChanged); ;
RemoveElementFromWatchList(uie);
}
}
else if (InputElement.IsUIElement3D(o))
{
UIElement3D uie3D = o as UIElement3D;
uie3D.RemoveHandler(SourceChangedEvent, handler);
store = uie3D.EventHandlersStore;
if (store != null)
{
info = store[SourceChangedEvent];
}
if (info == null || info.Count == 0)
{
uie3D.VisualAncestorChanged -= new Visual.AncestorChangedEventHandler(uie3D.OnVisualAncestorChanged); ;
RemoveElementFromWatchList(uie3D);
}
}
else
{
ContentElement ce = o as ContentElement;
ce.RemoveHandler(SourceChangedEvent, handler);
store = ce.EventHandlersStore;
if (store != null)
{
info = store[SourceChangedEvent];
}
if (info == null || info.Count == 0)
{
RemoveElementFromWatchList(ce);
}
}
}
}
/// <summary>
/// Called by FrameworkElements when a framework ancenstor link of
/// ContentElement has changed.
/// </summary>
/// <param name="ce">
/// The element whose ancestory may have changed.
/// </param>
/// <SecurityNote>
/// This API is not available in the internet zone.It was protected
/// as defense in depth since we did not want the PresentationSource
/// surface to be exposed.
/// </SecurityNote>
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.LinkDemand,Window=UIPermissionWindow.AllWindows)]
[FriendAccessAllowed] // Built into Core, also used by Framework.
internal static void OnAncestorChanged(ContentElement ce)
{
if (ce == null)
{
throw new ArgumentNullException("ce");
}
if (true == (bool)ce.GetValue(GetsSourceChangedEventProperty))
{
UpdateSourceOfElement(ce, null, null);
}
}
#endregion
//------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------
#region Public Properties
/// <summary>
/// The visual target for the visuals being presented in the source.
/// </summary>
/// <SecurityNote>
/// Critical: Calls GetCompositionTargetCore() and returns a CompositionTarget object, which is considered critical.
/// PublicOk: Protected by a LinkDemand
/// </SecurityNote>
public CompositionTarget CompositionTarget
{
[UIPermissionAttribute(SecurityAction.LinkDemand,Window=UIPermissionWindow.AllWindows)]
[SecurityCritical]
get
{
return GetCompositionTargetCore();
}
}
/// <summary>
/// The root visual being presented in the source.
/// </summary>
/// <remarks>
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
/// </remarks>
/// <SecurityNote>
/// Critical: This code is not safe to expose publicly since it lets you
/// change rootvisual which puts popup code at risk
/// PublicOK: Inheritance demand prevents random subclassing in partial trust
/// and Linkdemand prevents unauthorized public callers
/// </SecurityNote>
public abstract Visual RootVisual
{
get;
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.InheritanceDemand, Window = UIPermissionWindow.AllWindows)]
[UIPermissionAttribute(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)]
set;
}
/// <summary>
/// Causes this PresentationSource to enter "menu mode".
/// </summary>
internal void PushMenuMode()
{
_menuModeCount += 1;
if(1 == _menuModeCount)
{
OnEnterMenuMode();
}
}
/// <summary>
/// Causes this PresentationSource to enter "menu mode".
/// </summary>
internal void PopMenuMode()
{
if(_menuModeCount <= 0)
{
throw new InvalidOperationException();
}
_menuModeCount -= 1;
if(0 == _menuModeCount)
{
OnLeaveMenuMode();
}
}
/// <summary>
/// Notification to derived classes to enter menu mode.
/// </summary>
internal virtual void OnEnterMenuMode()
{
}
/// <summary>
/// Notification to derived classes to leave menu mode.
/// </summary>
internal virtual void OnLeaveMenuMode()
{
}
private int _menuModeCount;
/// <summary>
/// Whether or not the object is disposed.
/// </summary>
public abstract bool IsDisposed
{
get;
}
#endregion
//------------------------------------------------------
//
// Public Static Properties
//
//------------------------------------------------------
#region Public Static Properties
/// <summary>
/// Return a WeakReferenceList which supports returning an Enumerator
/// over a ReadOnly SnapShot of the List of sources. The Enumerator
/// skips over the any dead weak references in the list.
/// </summary>
/// <remarks>
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
/// </remarks>
/// <SecurityNote>
/// Critical: This code exposes the sources which are deemed as critical. This is defense in depth.
/// PublicOK: There exists a demand in this code
/// </SecurityNote>
public static IEnumerable CurrentSources
{
[SecurityCritical]
get
{
SecurityHelper.DemandUIWindowPermission();
return CriticalCurrentSources;
}
}
#endregion
//------------------------------------------------------
//
// Public Events
//
//------------------------------------------------------
#region Public Events
/// <summary>
/// This event fires when content is rendered and ready for user interaction.
/// </summary>
public event EventHandler ContentRendered;
#endregion
//------------------------------------------------------
//
// Protected Methods
//
//------------------------------------------------------
#region Protected Methods
/// <summary>
/// Returns visual target for the given source. Implemented by
/// the derived class.
/// </summary>
protected abstract CompositionTarget GetCompositionTargetCore();
//
[SecurityCritical, SecurityTreatAsSafe]
protected void RootChanged(Visual oldRoot, Visual newRoot)
{
PresentationSource oldSource = null;
if (oldRoot == newRoot)
{
return;
}
// Always clear the RootSourceProperty on the old root.
if (oldRoot != null)
{
oldSource = CriticalGetPresentationSourceFromElement(oldRoot, RootSourceProperty);
oldRoot.ClearValue(RootSourceProperty);
}
// Always set the SourceProperty on the new root.
if (newRoot != null)
{
newRoot.SetValue(RootSourceProperty, new SecurityCriticalDataForMultipleGetAndSet<PresentationSource>(this));
}
UIElement oldRootUIElement = oldRoot as UIElement;
UIElement newRootUIElement = newRoot as UIElement;
// The IsVisible property can only be true if root visual is connected to a presentation source.
// For Read-Only force-inherited properties, use a private update method.
if(oldRootUIElement != null)
{
oldRootUIElement.UpdateIsVisibleCache();
}
if(newRootUIElement != null)
{
newRootUIElement.UpdateIsVisibleCache();
}
// Broadcast the Unloaded event starting at the old root visual
if (oldRootUIElement != null)
{
oldRootUIElement.OnPresentationSourceChanged(false);
}
// Broadcast the Loaded event starting at the root visual
if (newRootUIElement != null)
{
newRootUIElement.OnPresentationSourceChanged(true);
}
// To fire PresentationSourceChanged when the RootVisual changes;
// rather than simulate a "parent" pointer change, we just walk the
// collection of all nodes that need the event.
foreach (DependencyObject element in _watchers)
{
// We only need to update those elements that are in the
// same context as this presentation source.
if (element.Dispatcher == Dispatcher)
{
PresentationSource testSource = CriticalGetPresentationSourceFromElement(element,CachedSourceProperty);
// 1) If we are removing the rootvisual, then fire on any node whos old
// PresetationSource was the oldSource.
// 2) If we are attaching a rootvisual then fire on any node whos old
// PresentationSource is null;
if (oldSource == testSource || null == testSource)
{
UpdateSourceOfElement(element, null, null);
}
}
}
}
/// <summary>
/// Called by derived classes to indicate that they need to be tracked.
/// </summary>
protected void AddSource()
{
_sources.Add(this);
}
/// <summary>
/// Called by derived classes to indicate that they no longer need to be tracked.
/// </summary>
protected void RemoveSource()
{
_sources.Remove(this);
}
/// <summary>
/// Sets the ContentRendered event to null.
/// </summary>
protected void ClearContentRenderedListeners()
{
ContentRendered = null;
}
#endregion
//------------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
// None
//------------------------------------------------------
//
// Internal Static Methods
//
//------------------------------------------------------
#region Internal Static Methods
/// <summary>
/// Called by UIElement(3D)s when a visual ancestor link has changed.
/// </summary>
/// <param name="uie">The UIElement whose ancestory may have changed.</param>
/// <param name="e"> Event Args.</param>
/// <SecurityNote>
/// Critical: This code calls into a critical code path UpdateSourceOfElement.
/// TreatAsSafe: This code does not access any critical data itself and does not expose
/// anything
/// </SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
internal static void OnVisualAncestorChanged(DependencyObject uie, AncestorChangedEventArgs e)
{
Debug.Assert(InputElement.IsUIElement3D(uie) || InputElement.IsUIElement(uie));
if (true == (bool)uie.GetValue(GetsSourceChangedEventProperty))
{
UpdateSourceOfElement(uie, e.Ancestor, e.OldParent);
}
}
/// <SecurityNote>
/// Critical - Returns the PresentationSource
/// </SecurityNote>
[FriendAccessAllowed] // To allow internal code paths to access this function
[SecurityCritical]
internal static PresentationSource CriticalFromVisual(DependencyObject v)
{
return CriticalFromVisual(v, true /* enable2DTo3DTransition */);
}
/// <SecurityNote>
/// Critical - uses RootSourceProperty. and returns the PresentationSource
/// </SecurityNote>
/// <param name="v">The dependency object to find the source for</param>
/// <param name="enable2DTo3DTransition">
/// Determines whether when walking the tree to enable transitioning from a 2D child
/// to a 3D parent or to stop once a 3D parent is encountered.
/// </param>
[FriendAccessAllowed] // To allow internal code paths to access this function
[SecurityCritical]
internal static PresentationSource CriticalFromVisual(DependencyObject v, bool enable2DTo3DTransition)
{
if (v == null)
{
throw new ArgumentNullException("v");
}
PresentationSource source = FindSource(v, enable2DTo3DTransition);
// Don't hand out a disposed source.
if (null != source && source.IsDisposed)
{
source = null;
}
return source;
}
/// <summary>
/// Fire the event when content is rendered and ready for user interaction.
/// </summary>
/// <param name="arg"></param>
internal static object FireContentRendered(object arg)
{
PresentationSource ps = (PresentationSource)arg;
if (ps.ContentRendered != null)
{
ps.ContentRendered(arg, EventArgs.Empty);
}
return null;
}
/// <summary>
/// Helper method which returns true when all the given visuals
/// are in the same presentation source.
/// </summary>
[FriendAccessAllowed] // To allow internal code paths to access this function
[SecurityCritical, SecurityTreatAsSafe]
internal static bool UnderSamePresentationSource(params DependencyObject[] visuals)
{
if (visuals == null || visuals.Length == 0)
{
return true;
}
PresentationSource baseSource = CriticalFromVisual(visuals[0]);
int count = visuals.Length;
for (int i = 1; i < count; i++)
{
PresentationSource currentSource = CriticalFromVisual(visuals[i]);
if (currentSource != baseSource)
{
return false;
}
}
return true;
}
#endregion
//------------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
// None
//------------------------------------------------------
//
// Internal Events
//
//------------------------------------------------------
// None
//------------------------------------------------------
//
// Private Static Methods
//
//------------------------------------------------------
#region Private Static Methods
/// <summary>
/// Return a WeakReferenceList which supports returning an Enumerator
/// over a ReadOnly SnapShot of the List of sources. The Enumerator
/// skips over the any dead weak references in the list.
/// </summary>
/// <SecurityNote>
/// Critical: This code exposes the sources which are deemed as critical. This is internal access point.
/// Public consumers should use CurrentSources
/// </SecurityNote>
internal static IEnumerable CriticalCurrentSources
{
[SecurityCritical]
get
{
return (IEnumerable)_sources;
}
}
/// <SecurityNote>
/// Critical: Returns a presentationsource given a canister
/// </SecurityNote>
[SecurityCritical]
private static PresentationSource CriticalGetPresentationSourceFromElement(DependencyObject dObject,DependencyProperty dp)
{
PresentationSource testSource;
SecurityCriticalDataForMultipleGetAndSet<PresentationSource> tempCriticalDataWrapper =
(SecurityCriticalDataForMultipleGetAndSet < PresentationSource > )
dObject.GetValue(dp);
if (tempCriticalDataWrapper == null || tempCriticalDataWrapper.Value == null)
{
testSource = null;
}
else
{
testSource = tempCriticalDataWrapper.Value;
}
return testSource;
}
/// <SecurityNote>
/// Critical: This code acceses PresentationSource and stores it.
/// </SecurityNote>
[SecurityCritical]
private static void AddElementToWatchList(DependencyObject element)
{
if(_watchers.Add(element))
{
element.SetValue(CachedSourceProperty,new
SecurityCriticalDataForMultipleGetAndSet<PresentationSource>(PresentationSource.FindSource(element)));
element.SetValue(GetsSourceChangedEventProperty, true);
}
}
/// <SecurityNote>
/// Critical: This code acceses PresentationSource
/// TreatAsSafe: This code is safe to expose.
/// </SecurityNote>
[SecurityCritical,SecurityTreatAsSafe]
private static void RemoveElementFromWatchList(DependencyObject element)
{
if(_watchers.Remove(element))
{
element.ClearValue(CachedSourceProperty);
element.ClearValue(GetsSourceChangedEventProperty);
}
}
///<SecurityNote>
/// Critical - Returns a PresentationSource.
///</SecurityNote>
[SecurityCritical]
private static PresentationSource FindSource(DependencyObject o)
{
return FindSource(o, true /* enable2DTo3DTransition */);
}
///<SecurityNote>
/// Critical - uses RootSourceProperty and returns the PresentationSource
///</SecurityNote>
/// <param name="o">The dependency object to find the source for</param>
/// <param name="enable2DTo3DTransition">
/// Determines whether when walking the tree to enable transitioning from a 2D child
/// to a 3D parent or to stop once a 3D parent is encountered.
/// </param>
[SecurityCritical]
private static PresentationSource FindSource(DependencyObject o, bool enable2DTo3DTransition)
{
PresentationSource source = null;
// For "Visual" nodes GetRootVisual() climbs to the top of the
// visual tree (parent==null)
// For "ContentElements" it climbs the logical parent until it
// reaches a visual then climbs to the top of the visual tree.
DependencyObject v = InputElement.GetRootVisual(o, enable2DTo3DTransition);
if (v != null)
{
source = CriticalGetPresentationSourceFromElement(v, RootSourceProperty);
}
return source;
}
/// <SecurityNote>
/// Critical: This code accesses PresentationSource which is a critical resource. It then
/// packages it into an event args and fires it into the tree.
/// </SecurityNote>
[SecurityCritical]
private static bool UpdateSourceOfElement(DependencyObject doTarget,
DependencyObject doAncestor,
DependencyObject doOldParent)
{
bool calledOut = false;
PresentationSource realSource = FindSource(doTarget);
PresentationSource cachedSource = CriticalGetPresentationSourceFromElement(doTarget, CachedSourceProperty);
if (cachedSource != realSource)
{
doTarget.SetValue(CachedSourceProperty, new SecurityCriticalDataForMultipleGetAndSet<PresentationSource>(realSource));
SourceChangedEventArgs args = new SourceChangedEventArgs(cachedSource, realSource);
args.RoutedEvent=SourceChangedEvent;
if (InputElement.IsUIElement(doTarget))
{
((UIElement)doTarget).RaiseEvent(args);
}
else if (InputElement.IsContentElement(doTarget))
{
((ContentElement)doTarget).RaiseEvent(args);
}
else
{
((UIElement3D)doTarget).RaiseEvent(args);
}
calledOut = true;
}
return calledOut;
}
#endregion
//------------------------------------------------------
//
// Private Static Members
//
//------------------------------------------------------
#region Private Static Members
// We use a private DP for the RootSource (the connection from the root
// element in a tree to the source it is displayed in). Use the public
// API FromVisual to get the source that a visual is displayed in.
///<SecurityNote>
/// Critical - used to store PresentationSource
///</SecurityNote>
[SecurityCritical]
private static readonly DependencyProperty RootSourceProperty
= DependencyProperty.RegisterAttached("RootSource", typeof(SecurityCriticalDataForMultipleGetAndSet<PresentationSource>), typeof(PresentationSource),
new PropertyMetadata((SecurityCriticalDataForMultipleGetAndSet<PresentationSource>)null));
// We use a private DP for the CachedSource (stored on the elements
// that we are watching, so that we can send a change notification).
// Use the public API FromVisual to get the source that a visual is
// displayed in.
///<SecurityNote>
/// Critical - used to store PresentationSource
///</SecurityNote>
[SecurityCritical]
private static readonly DependencyProperty CachedSourceProperty
= DependencyProperty.RegisterAttached("CachedSource", typeof(SecurityCriticalDataForMultipleGetAndSet<PresentationSource>), typeof(PresentationSource),
new PropertyMetadata((SecurityCriticalDataForMultipleGetAndSet<PresentationSource>)null));
// We use a private DP to mark elements that we are watchin.
private static readonly DependencyProperty GetsSourceChangedEventProperty = DependencyProperty.RegisterAttached("IsBeingWatched", typeof(bool), typeof(PresentationSource), new PropertyMetadata((bool)false));
// We use a private direct-only event to notify elements of when the
// source changes. Use the public APIs AddSourceChangedHandler and
// RemoveSourceChangedHandler to listen to this event.
private static readonly RoutedEvent SourceChangedEvent = EventManager.RegisterRoutedEvent("SourceChanged", RoutingStrategy.Direct, typeof(SourceChangedEventHandler), typeof(PresentationSource));
// The lock we use to protect our static data.
private static object _globalLock = new object();
// An array of weak-references to sources that we know about.
private static WeakReferenceList _sources = new WeakReferenceList(_globalLock);
// An array of weak-references to elements that need to know
// about source changes.
private static WeakReferenceList _watchers = new WeakReferenceList(_globalLock);
#endregion
}
}
|