Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Input / Stylus / StylusPlugInCollection.cs / 2 / 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 Sync 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. } // 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
- WinFormsSecurity.cs
- PropertyGridEditorPart.cs
- WebSysDefaultValueAttribute.cs
- Send.cs
- Trace.cs
- ConfigurationStrings.cs
- WebPartsPersonalizationAuthorization.cs
- IndicShape.cs
- DockPattern.cs
- SiteMapDataSourceView.cs
- SchemaTypeEmitter.cs
- WriteFileContext.cs
- CodeMemberEvent.cs
- DataGridView.cs
- WebPartZoneBase.cs
- GeneralTransformGroup.cs
- TemplateControlBuildProvider.cs
- CodeGeneratorOptions.cs
- HttpsTransportBindingElement.cs
- FilterQuery.cs
- IChannel.cs
- ReadOnlyMetadataCollection.cs
- ExcCanonicalXml.cs
- FontSourceCollection.cs
- DetailsViewUpdateEventArgs.cs
- CustomError.cs
- SQLBinaryStorage.cs
- OverflowException.cs
- ImageSource.cs
- RoutedEventValueSerializer.cs
- TypeReference.cs
- ITextView.cs
- WrappedIUnknown.cs
- GeometryGroup.cs
- SiteMapDataSourceView.cs
- ValuePatternIdentifiers.cs
- GridViewDeletedEventArgs.cs
- ExeConfigurationFileMap.cs
- ProxyGenerationError.cs
- GeneralTransform3DGroup.cs
- XmlQueryType.cs
- Queue.cs
- ToolstripProfessionalRenderer.cs
- ListMarkerLine.cs
- ZipArchive.cs
- URLMembershipCondition.cs
- CompiledQuery.cs
- GridViewDeletedEventArgs.cs
- ScriptReference.cs
- AttributeSetAction.cs
- OneWayChannelListener.cs
- _ConnectOverlappedAsyncResult.cs
- ModelVisual3D.cs
- TdsParser.cs
- FontSourceCollection.cs
- DataKey.cs
- TrackingLocation.cs
- GridViewRow.cs
- ModelPropertyImpl.cs
- SafeUserTokenHandle.cs
- CommandHelper.cs
- PinnedBufferMemoryStream.cs
- WindowsTooltip.cs
- PasswordPropertyTextAttribute.cs
- HitTestResult.cs
- ImageListUtils.cs
- ResourceAttributes.cs
- TemplateKeyConverter.cs
- PaintEvent.cs
- DataServiceHost.cs
- ScriptResourceInfo.cs
- DataGridPagerStyle.cs
- EventLogPermissionHolder.cs
- HtmlTableCellCollection.cs
- PersonalizablePropertyEntry.cs
- TableCell.cs
- FixedSOMContainer.cs
- SecuritySessionClientSettings.cs
- LinqDataSource.cs
- _ProxyChain.cs
- ObjectReaderCompiler.cs
- Literal.cs
- UserCancellationException.cs
- DynamicResourceExtensionConverter.cs
- Geometry3D.cs
- DependencyPropertyChangedEventArgs.cs
- Exception.cs
- WebPartTracker.cs
- ContextQuery.cs
- DesignerProperties.cs
- ChangeNode.cs
- versioninfo.cs
- ResizeGrip.cs
- CodeComment.cs
- DPTypeDescriptorContext.cs
- DBNull.cs
- TextEditorContextMenu.cs
- MetricEntry.cs
- ComboBoxAutomationPeer.cs
- ArgumentNullException.cs