Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Input / Stylus / StylusPlugInCollection.cs / 1305600 / StylusPlugInCollection.cs
//------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------- using System; using System.Windows; using System.Collections; using System.Collections.ObjectModel; using System.Windows.Media; using System.Windows.Threading; using System.Windows.Interop; using System.Security; using System.Security.Permissions; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace System.Windows.Input.StylusPlugIns { ////// Collection of StylusPlugIn objects /// ////// The collection order is based on the order that StylusPlugIn objects are /// added to the collection via the IList interfaces. The order of the StylusPlugIn /// objects in the collection is modifiable. /// Some of the methods are designed to be called from both the App thread and the Pen thread, /// but some of them are supposed to be called from one thread only. Please look at the /// comments of each method for such an information. /// public sealed class StylusPlugInCollection : Collection{ #region Protected APIs /// /// Insert a StylusPlugIn in the collection at a specific index. /// This method should be called from the application context only /// /// index at which to insert the StylusPlugIn object /// StylusPlugIn object to insert, downcast to an object protected override void InsertItem(int index, StylusPlugIn plugIn) { // Verify it's called from the app dispatcher _element.VerifyAccess(); // Validate the input parameter if (null == plugIn) { throw new ArgumentNullException("plugIn", SR.Get(SRID.Stylus_PlugInIsNull)); } if (IndexOf(plugIn) != -1) { throw new ArgumentException(SR.Get(SRID.Stylus_PlugInIsDuplicated), "plugIn"); } // Disable processing of the queue during blocking operations to prevent unrelated reentrancy // which a call to Lock() can cause. using (_element.Dispatcher.DisableProcessing()) { if (IsActiveForInput) { // If we are currently active for input then we have a _penContexts that we must lock! lock(PenContextsSyncRoot) { System.Diagnostics.Debug.Assert(this.Count > 0); // If active must have more than one plugin already base.InsertItem(index, plugIn); plugIn.Added(this); } } else { EnsureEventsHooked(); // Hook up events to track changes to the plugin's element base.InsertItem(index, plugIn); try { plugIn.Added(this); // Notify plugin that it has been added to collection } finally { UpdatePenContextsState(); // Add to PenContexts if element is in proper state (can fire isactiveforinput). } } } } ////// Remove all the StylusPlugIn objects from the collection. /// This method should be called from the application context only. /// protected override void ClearItems() { // Verify it's called from the app dispatcher _element.VerifyAccess(); if (this.Count != 0) { // Disable processing of the queue during blocking operations to prevent unrelated reentrancy // which a call to Lock() can cause. using (_element.Dispatcher.DisableProcessing()) { if (IsActiveForInput) { // If we are currently active for input then we have a _penContexts that we must lock! lock(PenContextsSyncRoot) { while (this.Count > 0) { RemoveItem(0); // Does work to fire event and remove from collection and pencontexts } } } else { while (this.Count > 0) { RemoveItem(0); // Does work to fire event and remove from collection. } } } } } ////// Remove the StylusPlugIn in the collection at the specified index. /// This method should be called from the application context only. /// /// protected override void RemoveItem(int index) { // Verify it's called from the app dispatcher _element.VerifyAccess(); // Disable processing of the queue during blocking operations to prevent unrelated reentrancy // which a call to Lock() can cause. using (_element.Dispatcher.DisableProcessing()) { if (IsActiveForInput) { // If we are currently active for input then we have a _penContexts that we must lock! lock(PenContextsSyncRoot) { StylusPlugIn removedItem = base[index]; base.RemoveItem(index); try { EnsureEventsAndPenContextsUnhooked(); // Clean up events and remove from pencontexts } finally { removedItem.Removed(); // Notify plugin it has been removed } } } else { StylusPlugIn removedItem = base[index]; base.RemoveItem(index); try { EnsureEventsAndPenContextsUnhooked(); // Clean up events and remove from pencontexts } finally { removedItem.Removed(); // Notify plugin it has been removed } } } } ////// Indexer to retrieve/set a StylusPlugIn at a given index in the collection /// Accessible from both the real time context and application context. /// protected override void SetItem(int index, StylusPlugIn plugIn) { // Verify it's called from the app dispatcher _element.VerifyAccess(); if (null == plugIn) { throw new ArgumentNullException("plugIn", SR.Get(SRID.Stylus_PlugInIsNull)); } if (IndexOf(plugIn) != -1) { throw new ArgumentException(SR.Get(SRID.Stylus_PlugInIsDuplicated), "plugIn"); } // Disable processing of the queue during blocking operations to prevent unrelated reentrancy // which a call to Lock() can cause. using (_element.Dispatcher.DisableProcessing()) { if (IsActiveForInput) { // If we are currently active for input then we have a _penContexts that we must lock! lock(PenContextsSyncRoot) { StylusPlugIn originalPlugIn = base[index]; base.SetItem(index, plugIn); try { originalPlugIn.Removed(); } finally { plugIn.Added(this); } } } else { StylusPlugIn originalPlugIn = base[index]; base.SetItem(index, plugIn); try { originalPlugIn.Removed(); } finally { plugIn.Added(this); } } } } #endregion #region Internal APIs ////// Constructor /// /// internal StylusPlugInCollection(UIElement element) { _element = element; _isEnabledChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsEnabledChanged); _isVisibleChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsVisibleChanged); _isHitTestVisibleChangedEventHandler = new DependencyPropertyChangedEventHandler(OnIsHitTestVisibleChanged); _sourceChangedEventHandler = new SourceChangedEventHandler(OnSourceChanged); _layoutChangedEventHandler = new EventHandler(OnLayoutUpdated); } ////// Get the UIElement /// This method is called from the real-time context. /// internal UIElement Element { get { return _element; } } ////// Update the rectangular bound of the element /// This method is called from the application context. /// internal void UpdateRect() { // The RenderSize is only valid if IsArrangeValid is true. if (_element.IsArrangeValid && _element.IsEnabled && _element.IsVisible && _element.IsHitTestVisible) { _rc = new Rect(new Point(), _element.RenderSize);// _element.GetContentBoundingBox(); Visual root = VisualTreeHelper.GetContainingVisual2D(InputElement.GetRootVisual(_element)); try { _viewToElement = root.TransformToDescendant(_element); } catch(System.InvalidOperationException) { // This gets hit if the transform is not invertable. In that case // we will just not allow this plugin to be hit. _rc = new Rect(); // empty rect so we don't hittest it. _viewToElement = Transform.Identity; } } else { _rc = new Rect(); // empty rect so we don't hittest it. } if (_viewToElement == null) { _viewToElement = Transform.Identity; } } ////// Check whether a point hits the element /// This method is called from the real-time context. /// /// a point to check ///true if the point is within the bound of the element; false otherwise internal bool IsHit(Point pt) { Point ptElement = pt; _viewToElement.TryTransform(ptElement, out ptElement); return _rc.Contains(ptElement); } ////// Get the transform matrix from the root visual to the current UIElement /// This method is called from the real-time context. /// internal GeneralTransform ViewToElement { get { return _viewToElement; } } ////// Get the current rect for the Element that the StylusPlugInCollection is attached to. /// May be empty rect if plug in is not in tree. /// internal Rect Rect { get { return _rc; } } ////// Get the current rect for the Element that the StylusPlugInCollection is attached to. /// May be empty rect if plug in is not in tree. /// ////// Critical - Accesses SecurityCritical data _penContexts. /// TreatAsSafe - Just returns if _pencontexts is null. No data goes in or out. Knowing /// the fact that you can recieve real time input is something that is safe /// to know and we want to expose. /// internal bool IsActiveForInput { [SecurityCritical, SecurityTreatAsSafe] get { return _penContexts != null; } } ////// Critical - Accesses SecurityCritical data _penContexts. /// TreatAsSafe - The [....] object on the _penContexts object is not considered security /// critical data. It is already internally exposed directly on the /// PenContexts object. /// internal object PenContextsSyncRoot { [SecurityCritical, SecurityTreatAsSafe] get { return _penContexts != null ? _penContexts.SyncRoot : null; } } ////// Fire the Enter notification. /// This method is called from pen threads and app thread. /// internal void FireEnterLeave(bool isEnter, RawStylusInput rawStylusInput, bool confirmed) { if (IsActiveForInput) { // If we are currently active for input then we have a _penContexts that we must lock! lock(PenContextsSyncRoot) { for (int i = 0; i < this.Count; i++) { base[i].StylusEnterLeave(isEnter, rawStylusInput, confirmed); } } } else { for (int i = 0; i < this.Count; i++) { base[i].StylusEnterLeave(isEnter, rawStylusInput, confirmed); } } } ////// Fire RawStylusInputEvent for all the StylusPlugIns /// This method is called from the real-time context (pen thread) only /// /// internal void FireRawStylusInput(RawStylusInput args) { try { if (IsActiveForInput) { // If we are currently active for input then we have a _penContexts that we must lock! lock(PenContextsSyncRoot) { for (int i = 0; i < this.Count; i++) { StylusPlugIn plugIn = base[i]; // set current plugin so any callback data gets an owner. args.CurrentNotifyPlugIn = plugIn; plugIn.RawStylusInput(args); } } } else { for (int i = 0; i < this.Count; i++) { StylusPlugIn plugIn = base[i]; // set current plugin so any callback data gets an owner. args.CurrentNotifyPlugIn = plugIn; plugIn.RawStylusInput(args); } } } finally { args.CurrentNotifyPlugIn = null; } } ////// Critical: Accesses critical member _penContexts. /// internal PenContexts PenContexts { [SecurityCritical] get { return _penContexts; } } #endregion #region Private APIs ////// Add this StylusPlugInCollection to the StylusPlugInCollectionList when it the first /// element is added. /// ////// Critical - Presentation source access /// TreatAsSafe: - PresentationSource makes a SecurityDemand /// - no data handed out or accepted /// - called by Add and Insert /// [SecurityCritical,SecurityTreatAsSafe] private void EnsureEventsHooked() { if (this.Count == 0) { // Grab current element info UpdateRect(); // Now hook up events to track on this element. _element.IsEnabledChanged += _isEnabledChangedEventHandler; _element.IsVisibleChanged += _isVisibleChangedEventHandler; _element.IsHitTestVisibleChanged += _isHitTestVisibleChangedEventHandler; PresentationSource.AddSourceChangedHandler(_element, _sourceChangedEventHandler); // has a security linkdemand _element.LayoutUpdated += _layoutChangedEventHandler; if (_element.RenderTransform != null && !_element.RenderTransform.IsFrozen) { if (_renderTransformChangedEventHandler == null) { _renderTransformChangedEventHandler = new EventHandler(OnRenderTransformChanged); _element.RenderTransform.Changed += _renderTransformChangedEventHandler; } } } } ////// Remove this StylusPlugInCollection from the StylusPlugInCollectionList when it the last /// element is removed for this collection. /// private void EnsureEventsAndPenContextsUnhooked() { if (this.Count == 0) { // Unhook events. _element.IsEnabledChanged -= _isEnabledChangedEventHandler; _element.IsVisibleChanged -= _isVisibleChangedEventHandler; _element.IsHitTestVisibleChanged -= _isHitTestVisibleChangedEventHandler; if (_renderTransformChangedEventHandler != null) { _element.RenderTransform.Changed -= _renderTransformChangedEventHandler; } PresentationSource.RemoveSourceChangedHandler(_element, _sourceChangedEventHandler); _element.LayoutUpdated -= _layoutChangedEventHandler; // Disable processing of the queue during blocking operations to prevent unrelated reentrancy // which a call to Lock() can cause. using (_element.Dispatcher.DisableProcessing()) { // Make sure we are unhooked from PenContexts if we don't have any plugins. UnhookPenContexts(); } } } private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) { System.Diagnostics.Debug.Assert(_element.IsEnabled == (bool)e.NewValue); UpdatePenContextsState(); } private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { System.Diagnostics.Debug.Assert(_element.IsVisible == (bool)e.NewValue); UpdatePenContextsState(); } private void OnIsHitTestVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { System.Diagnostics.Debug.Assert(_element.IsHitTestVisible == (bool)e.NewValue); UpdatePenContextsState(); } private void OnRenderTransformChanged(object sender, EventArgs e) { OnLayoutUpdated(sender, e); } private void OnSourceChanged(object sender, SourceChangedEventArgs e) { // This means that the element has been added or remvoed from its source. UpdatePenContextsState(); } private void OnLayoutUpdated(object sender, EventArgs e) { // Make sure our rect and transform is up to date on layout changes. // NOTE: We need to make sure we do this under a lock if we are active for input since we don't // want the PenContexts code to get a mismatched set of state for this element. if (IsActiveForInput) { // Disable processing of the queue during blocking operations to prevent unrelated reentrancy // which a call to Lock() can cause. using (_element.Dispatcher.DisableProcessing()) { // If we are currently active for input then we have a _penContexts that we must lock! lock(PenContextsSyncRoot) { UpdateRect(); } } } else { UpdateRect(); } if (_lastRenderTransform != _element.RenderTransform) { if (_renderTransformChangedEventHandler != null) { _lastRenderTransform.Changed -= _renderTransformChangedEventHandler; _renderTransformChangedEventHandler = null; } _lastRenderTransform = _element.RenderTransform; } if (_lastRenderTransform != null) { if (_lastRenderTransform.IsFrozen) { if (_renderTransformChangedEventHandler != null) { _renderTransformChangedEventHandler = null; } } else { if (_renderTransformChangedEventHandler == null) { _renderTransformChangedEventHandler = new EventHandler(OnRenderTransformChanged); _lastRenderTransform.Changed += _renderTransformChangedEventHandler; } } } } // On app ui dispatcher ////// Critical - Presentation source access /// Calls SecurityCritical routines PresentationSource.CriticalFromVisual and /// HwndSource.CriticalHandle. /// TreatAsSafe: /// - no data handed out or accepted /// [SecurityCritical,SecurityTreatAsSafe] private void UpdatePenContextsState() { bool unhookPenContexts = true; // Disable processing of the queue during blocking operations to prevent unrelated reentrancy // which a call to Lock() can cause. using (_element.Dispatcher.DisableProcessing()) { // See if we should be enabled if (_element.IsVisible && _element.IsEnabled && _element.IsHitTestVisible) { PresentationSource presentationSource = PresentationSource.CriticalFromVisual(_element as Visual); if (presentationSource != null) { unhookPenContexts = false; // Are we currently hooked up? If not then hook up. if (_penContexts == null) { InputManager inputManager = (InputManager)_element.Dispatcher.InputManager; PenContexts penContexts = inputManager.StylusLogic.GetPenContextsFromHwnd(presentationSource); // _penContexts must be non null or don't do anything. if (penContexts != null) { _penContexts = penContexts; lock(penContexts.SyncRoot) { penContexts.AddStylusPlugInCollection(this); foreach (StylusPlugIn spi in this) { spi.InvalidateIsActiveForInput(); // Uses _penContexts being set to determine active state. } // NTRAID:WINDOWSOS#1677277-2006/06/05-WAYNEZEN, // Normally the Rect will be updated when we receive the LayoutUpdate. // However there could be a race condition which the LayoutUpdate gets received // before the properties like IsVisible being set. // So we should always force to call OnLayoutUpdated whenever the input is active. OnLayoutUpdated(this, EventArgs.Empty); } } } } } if (unhookPenContexts) { UnhookPenContexts(); } } } ////// Critical - _penContexts access /// TreatAsSafe: /// - no data handed out or accepted /// [SecurityCritical,SecurityTreatAsSafe] void UnhookPenContexts() { // Are we currently unhooked? If not then unhook. if (_penContexts != null) { lock(_penContexts.SyncRoot) { _penContexts.RemoveStylusPlugInCollection(this); // Can't recieve any more input now! _penContexts = null; // Notify after input is disabled to the PlugIns. foreach (StylusPlugIn spi in this) { spi.InvalidateIsActiveForInput(); } } } } #endregion #region Fields private UIElement _element; private Rect _rc; // In window root measured units private GeneralTransform _viewToElement; private Transform _lastRenderTransform; // Note that this is only set when the Element is in a state to receive input (visible,enabled,in tree). ////// Critical to prevent accidental spread to transparent code /// [SecurityCritical] private PenContexts _penContexts; private DependencyPropertyChangedEventHandler _isEnabledChangedEventHandler; private DependencyPropertyChangedEventHandler _isVisibleChangedEventHandler; private DependencyPropertyChangedEventHandler _isHitTestVisibleChangedEventHandler; private EventHandler _renderTransformChangedEventHandler; private SourceChangedEventHandler _sourceChangedEventHandler; private EventHandler _layoutChangedEventHandler; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FormViewInsertEventArgs.cs
- DetailsViewRowCollection.cs
- DesignerSerializerAttribute.cs
- RecognizerStateChangedEventArgs.cs
- TimeEnumHelper.cs
- ResXResourceSet.cs
- CriticalFinalizerObject.cs
- PropertyGridCommands.cs
- DSGeneratorProblem.cs
- BatchStream.cs
- EditorPartChrome.cs
- LowerCaseStringConverter.cs
- DataControlFieldCell.cs
- FlowLayoutSettings.cs
- ScriptControlDescriptor.cs
- TabPage.cs
- HtmlEncodedRawTextWriter.cs
- ClientData.cs
- XmlConvert.cs
- DependencyPropertyChangedEventArgs.cs
- MailAddress.cs
- PathData.cs
- XPathSingletonIterator.cs
- SystemGatewayIPAddressInformation.cs
- EntityKey.cs
- KeySplineConverter.cs
- SqlEnums.cs
- LowerCaseStringConverter.cs
- BasicBrowserDialog.designer.cs
- DownloadProgressEventArgs.cs
- DataConnectionHelper.cs
- Compilation.cs
- SchemaEntity.cs
- ToolStripItem.cs
- DrawListViewItemEventArgs.cs
- PngBitmapEncoder.cs
- ForwardPositionQuery.cs
- CrossContextChannel.cs
- StatusStrip.cs
- BaseComponentEditor.cs
- XmlSchemaValidationException.cs
- AttachedAnnotationChangedEventArgs.cs
- ServiceChannelManager.cs
- GZipStream.cs
- InfocardExtendedInformationCollection.cs
- SQLDecimal.cs
- FormatConvertedBitmap.cs
- BinaryParser.cs
- TypeLoadException.cs
- RequestSecurityTokenResponse.cs
- BufferBuilder.cs
- WarningException.cs
- ControlDesignerState.cs
- ParsedAttributeCollection.cs
- ContextActivityUtils.cs
- DoubleCollectionConverter.cs
- DataReceivedEventArgs.cs
- InteropEnvironment.cs
- ControlEvent.cs
- UnhandledExceptionEventArgs.cs
- SqlRowUpdatedEvent.cs
- CompositionCommandSet.cs
- PrtCap_Public.cs
- DataGridViewCellValueEventArgs.cs
- LookupNode.cs
- UpdateProgress.cs
- XmlNode.cs
- AttachmentService.cs
- DataControlFieldCell.cs
- DataObjectEventArgs.cs
- MachineKeyConverter.cs
- HeaderedContentControl.cs
- WhiteSpaceTrimStringConverter.cs
- ControlIdConverter.cs
- ScopedKnownTypes.cs
- DataSourceXmlSerializationAttribute.cs
- HighContrastHelper.cs
- GeometryConverter.cs
- OleDbErrorCollection.cs
- Comparer.cs
- TreeNode.cs
- _ShellExpression.cs
- Trace.cs
- WindowsFormsHelpers.cs
- MappingSource.cs
- WebPartCollection.cs
- MarshalDirectiveException.cs
- RoleService.cs
- RangeContentEnumerator.cs
- ConfigurationSettings.cs
- MenuCommands.cs
- AdornerLayer.cs
- XmlToDatasetMap.cs
- bindurihelper.cs
- ProfileEventArgs.cs
- LocatorBase.cs
- WindowsIPAddress.cs
- MainMenu.cs
- AnchoredBlock.cs
- MatrixCamera.cs