Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / Ink / Renderer.cs / 1305600 / Renderer.cs
//------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------- using MS.Utility; using System; using System.Windows; using System.Windows.Media; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using MS.Internal.Ink; using MS.Internal; using MS.Internal.PresentationCore; namespace System.Windows.Ink { ////// The Renderer class is used to render a stroke collection. /// This class listens to stroke added and removed events on the /// stroke collection and updates the internal visual tree. /// It also listens to the Invalidated event on Stroke (fired when /// DrawingAttributes changes, packet data changes, DrawingAttributes /// replaced, as well as Stroke developer calls Stroke.OnInvalidated) /// and updates the visual state as necessary. /// /// [FriendAccessAllowed] // Built into Core, also used by Framework. internal class Renderer { #region StrokeVisual ////// A retained visual for rendering a single stroke in a stroke collection view /// private class StrokeVisual : System.Windows.Media.DrawingVisual { ////// Constructor /// /// a stroke to render into this visual /// a renderer associated to this visual internal StrokeVisual(Stroke stroke, Renderer renderer) : base() { Debug.Assert(renderer != null); if (stroke == null) { throw new System.ArgumentNullException("stroke"); } _stroke = stroke; _renderer = renderer; // The original value of the color and IsHighlighter are cached so // when Stroke.Invalidated is fired, Renderer knows whether re-arranging // the visual tree is needed. _cachedColor = stroke.DrawingAttributes.Color; _cachedIsHighlighter = stroke.DrawingAttributes.IsHighlighter; // Update the visual contents Update(); } ////// The Stroke rendedered into this visual. /// internal Stroke Stroke { get { return _stroke; } } ////// Updates the contents of the visual. /// internal void Update() { using (DrawingContext drawingContext = RenderOpen()) { bool highContrast = _renderer.IsHighContrast(); if (highContrast == true && _stroke.DrawingAttributes.IsHighlighter) { // we don't render highlighters in high contrast return; } DrawingAttributes da; if (highContrast) { da = _stroke.DrawingAttributes.Clone(); da.Color = _renderer.GetHighContrastColor(); } else if (_stroke.DrawingAttributes.IsHighlighter == true) { // Get the drawing attributes to use for a highlighter stroke. This can be a copied DA with color.A // overridden if color.A != 255. da = StrokeRenderer.GetHighlighterAttributes(_stroke, _stroke.DrawingAttributes); } else { // Otherwise, usethe DA on this stroke da = _stroke.DrawingAttributes; } // Draw selected stroke as hollow _stroke.DrawInternal (drawingContext, da, _stroke.IsSelected ); } } ////// StrokeVisual should not be hittestable as it interferes with event routing /// protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParams) { return null; } ////// The previous value of IsHighlighter /// internal bool CachedIsHighlighter { get {return _cachedIsHighlighter;} set {_cachedIsHighlighter = value;} } ////// The previous value of Color /// internal Color CachedColor { get {return _cachedColor;} set {_cachedColor = value;} } private Stroke _stroke; private bool _cachedIsHighlighter; private Color _cachedColor; private Renderer _renderer; } ////// Private helper that helps reverse map the highlighter dictionary /// private class HighlighterContainerVisual : ContainerVisual { internal HighlighterContainerVisual(Color color) { _color = color; } ////// The Color of the strokes in this highlighter container visual /// internal Color Color { get { return _color; } } private Color _color; } #endregion #region Internal interface ////// Public Constructor /// internal Renderer() { // Initialize the data members. // We intentionally don't use lazy initialization for the core members to avoid // hidden bug situations when one thing has been created while another not. // If the user is looking for lazy initialization, she should do that on her // own and create Renderer only when there's a need for it. // Create visuals that'll be the containers for all other visuals // created by the Renderer. This visuals are created once and are // not supposed to be replaced nor destroyed while the Renderer is alive. _rootVisual = new ContainerVisual(); _highlightersRoot = new ContainerVisual(); _regularInkVisuals = new ContainerVisual(); _incrementalRenderingVisuals = new ContainerVisual(); // Highlighters go to the bottom, then regular ink, and regular // ink' incremental rendering in on top. VisualCollection rootChildren = _rootVisual.Children; rootChildren.Add(_highlightersRoot); rootChildren.Add(_regularInkVisuals); rootChildren.Add(_incrementalRenderingVisuals); // Set the default value of highcontrast to be false. _highContrast = false; // Create a stroke-visual dictionary _visuals = new Dictionary(); } /// /// Returns a reference to a visual tree that can be used to render the ink. /// This property may be either a single visual or a container visual with /// children. The element uses this visual as a child visual and arranges /// it with respects to the other siblings. /// Note: No visuals are actually generated until the application gets /// this property for the first time. If no strokes are set then an empty /// visual is returned. /// internal Visual RootVisual { get { return _rootVisual; } } ////// Set the strokes property to the collection of strokes to be rendered. /// The Renderer will then listen to changes to the StrokeCollection /// and update its state to reflect the changes. /// internal StrokeCollection Strokes { get { // We should never return a null value. if ( _strokes == null ) { _strokes = new StrokeCollection(); // Start listening on events from the stroke collection. _strokes.StrokesChangedInternal += new StrokeCollectionChangedEventHandler(OnStrokesChanged); } return _strokes; } set { if (value == null) { throw new System.ArgumentNullException("value"); } if (value == _strokes) { return; } // Detach the current stroke collection if (null != _strokes) { // Stop listening on events from the stroke collection. _strokes.StrokesChangedInternal -= new StrokeCollectionChangedEventHandler(OnStrokesChanged); foreach (StrokeVisual visual in _visuals.Values) { StopListeningOnStrokeEvents(visual.Stroke); // Detach the visual from the tree DetachVisual(visual); } _visuals.Clear(); } // Set it. _strokes = value; // Create visuals foreach (Stroke stroke in _strokes) { // Create a visual per stroke StrokeVisual visual = new StrokeVisual(stroke, this); // Store the stroke-visual pair in the dictionary _visuals.Add(stroke, visual); StartListeningOnStrokeEvents(visual.Stroke); // Attach it to the visual tree AttachVisual(visual, true/*buildingStrokeCollection*/); } // Start listening on events from the stroke collection. _strokes.StrokesChangedInternal += new StrokeCollectionChangedEventHandler(OnStrokesChanged); } } ////// User supposed to use this method to attach IncrementalRenderer's root visual /// to the visual tree of a stroke collection view. /// /// visual to attach /// drawing attributes that used in the incremental rendering internal void AttachIncrementalRendering(Visual visual, DrawingAttributes drawingAttributes) { // Check the input parameters if (visual == null) { throw new System.ArgumentNullException("visual"); } if (drawingAttributes == null) { throw new System.ArgumentNullException("drawingAttributes"); } //harden against eaten exceptions bool exceptionRaised = false; // Verify that the visual hasn't been attached already if (_attachedVisuals != null) { foreach(Visual alreadyAttachedVisual in _attachedVisuals) { if (visual == alreadyAttachedVisual) { exceptionRaised = true; throw new System.InvalidOperationException(SR.Get(SRID.CannotAttachVisualTwice)); } } } else { // Create the list to register attached visuals in _attachedVisuals = new List(); } if (!exceptionRaised) { // The position of the visual in the tree depends on the drawingAttributes // Find the appropriate parent visual to attach this visual to. ContainerVisual parent = drawingAttributes.IsHighlighter ? GetContainerVisual(drawingAttributes) : _incrementalRenderingVisuals; // Attach the visual to the tree parent.Children.Add(visual); // Put the visual into the list of visuals attached via this method _attachedVisuals.Add(visual); } } /// /// Detaches a visual previously attached via AttachIncrementalRendering /// /// the visual to detach internal void DetachIncrementalRendering(Visual visual) { if (visual == null) { throw new System.ArgumentNullException("visual"); } // Remove the visual in the list of attached via AttachIncrementalRendering if ((_attachedVisuals == null) || (_attachedVisuals.Remove(visual) == false)) { throw new System.InvalidOperationException(SR.Get(SRID.VisualCannotBeDetached)); } // Detach it from the tree DetachVisual(visual); } ////// Internal helper used to indicate if a visual was previously attached /// via a call to AttachIncrementalRendering /// internal bool ContainsAttachedIncrementalRenderingVisual(Visual visual) { if (visual == null || _attachedVisuals == null) { return false; } return _attachedVisuals.Contains(visual); } ////// Internal helper used to determine if a visual is in the right spot in the visual tree /// internal bool AttachedVisualIsPositionedCorrectly(Visual visual, DrawingAttributes drawingAttributes) { if (visual == null || drawingAttributes == null || _attachedVisuals == null || !_attachedVisuals.Contains(visual)) { return false; } ContainerVisual correctParent = drawingAttributes.IsHighlighter ? GetContainerVisual(drawingAttributes) : _incrementalRenderingVisuals; ContainerVisual currentParent = VisualTreeHelper.GetParent(visual) as ContainerVisual; if (currentParent == null || correctParent != currentParent) { return false; } return true; } ////// TurnOnHighContrast turns on the HighContrast rendering mode /// /// The stroke color under high contrast internal void TurnHighContrastOn(Color strokeColor) { if ( !_highContrast || strokeColor != _highContrastColor ) { _highContrast = true; _highContrastColor = strokeColor; UpdateStrokeVisuals(); } } ////// ResetHighContrast turns off the HighContrast mode /// internal void TurnHighContrastOff() { if ( _highContrast ) { _highContrast = false; UpdateStrokeVisuals(); } } ////// Indicates whether the renderer is in high contrast mode. /// ///internal bool IsHighContrast() { return _highContrast; } /// /// returns the stroke color for the high contrast rendering. /// ///public Color GetHighContrastColor() { return _highContrastColor; } #endregion #region Event handlers /// /// StrokeCollectionChanged event handler /// private void OnStrokesChanged(object sender, StrokeCollectionChangedEventArgs eventArgs) { System.Diagnostics.Debug.Assert(sender == _strokes); // Read the args StrokeCollection added = eventArgs.Added; StrokeCollection removed = eventArgs.Removed; // Add new strokes foreach (Stroke stroke in added) { // Verify that it's not a dupe if (_visuals.ContainsKey(stroke)) { throw new System.ArgumentException(SR.Get(SRID.DuplicateStrokeAdded)); } // Create a visual for the new stroke and add it to the dictionary StrokeVisual visual = new StrokeVisual(stroke, this); _visuals.Add(stroke, visual); // Start listening on the stroke events StartListeningOnStrokeEvents(visual.Stroke); // Attach it to the visual tree AttachVisual(visual, false/*buildingStrokeCollection*/); } // Deal with removed strokes first foreach (Stroke stroke in removed) { // Verify that the event is in [....] with the view StrokeVisual visual = null; if (_visuals.TryGetValue(stroke, out visual)) { // get rid of both the visual and the stroke DetachVisual(visual); StopListeningOnStrokeEvents(visual.Stroke); _visuals.Remove(stroke); } else { throw new System.ArgumentException(SR.Get(SRID.UnknownStroke3)); } } } ////// Stroke Invalidated event handler /// private void OnStrokeInvalidated(object sender, EventArgs eventArgs) { System.Diagnostics.Debug.Assert(_strokes.IndexOf(sender as Stroke) != -1); // Find the visual associated with the changed stroke. StrokeVisual visual; Stroke stroke = (Stroke)sender; if (_visuals.TryGetValue(stroke, out visual) == false) { throw new System.ArgumentException(SR.Get(SRID.UnknownStroke1)); } // The original value of IsHighligher and Color are cached in StrokeVisual. // if (IsHighlighter value changed or (IsHighlighter == true and not changed and color changed) // detach and re-attach the corresponding visual; // otherwise Invalidate the corresponding StrokeVisual if (visual.CachedIsHighlighter != stroke.DrawingAttributes.IsHighlighter || (stroke.DrawingAttributes.IsHighlighter && StrokeRenderer.GetHighlighterColor(visual.CachedColor) != StrokeRenderer.GetHighlighterColor(stroke.DrawingAttributes.Color))) { // The change requires reparenting the visual in the tree. DetachVisual(visual); AttachVisual(visual, false/*buildingStrokeCollection*/); // Update the cached values visual.CachedIsHighlighter = stroke.DrawingAttributes.IsHighlighter; visual.CachedColor = stroke.DrawingAttributes.Color; } // Update the visual. visual.Update(); } #endregion #region Helper methods ////// Update the stroke visuals /// private void UpdateStrokeVisuals() { foreach ( StrokeVisual strokeVisual in _visuals.Values ) { strokeVisual.Update(); } } ////// Attaches a stroke visual to the tree based on the stroke's /// drawing attributes and/or its z-order (index in the collection). /// private void AttachVisual(StrokeVisual visual, bool buildingStrokeCollection) { System.Diagnostics.Debug.Assert(_strokes != null); if (visual.Stroke.DrawingAttributes.IsHighlighter) { // Find or create a container visual for highlighter strokes of the color ContainerVisual parent = GetContainerVisual(visual.Stroke.DrawingAttributes); Debug.Assert(visual is StrokeVisual); //insert StrokeVisuals under any non-StrokeVisuals used for dynamic inking int i = 0; for (int j = parent.Children.Count - 1; j >= 0; j--) { if (parent.Children[j] is StrokeVisual) { i = j + 1; break; } } parent.Children.Insert(i, visual); } else { // For regular ink we have to respect the z-order of the strokes. // The implementation below is not optimal in a generic case, but the // most simple and should work ok in most common scenarios. // Find the nearest non-highlighter stroke with a lower z-order // and insert the new visual right next to the visual of that stroke. StrokeVisual precedingVisual = null; int i = 0; if (buildingStrokeCollection) { Stroke visualStroke = visual.Stroke; //we're building up a stroke collection, no need to start at IndexOf, i = Math.Min(_visuals.Count, _strokes.Count); //not -1, we're about to decrement while (--i >= 0) { if (object.ReferenceEquals(_strokes[i], visualStroke)) { break; } } } else { i = _strokes.IndexOf(visual.Stroke); } while (--i >= 0) { Stroke stroke = _strokes[i]; if ((stroke.DrawingAttributes.IsHighlighter == false) && (_visuals.TryGetValue(stroke, out precedingVisual) == true) && (VisualTreeHelper.GetParent(precedingVisual) != null)) { VisualCollection children = ((ContainerVisual)(VisualTreeHelper.GetParent(precedingVisual))).Children; int index = children.IndexOf(precedingVisual); children.Insert(index + 1, visual); break; } } // If found no non-highlighter strokes with a lower z-order, insert // the stroke at the very bottom of the regular ink visual tree. if (i < 0) { ContainerVisual parent = GetContainerVisual(visual.Stroke.DrawingAttributes); parent.Children.Insert(0, visual); } } } ////// Detaches a visual from the tree, also removes highligher parents if empty /// when true is passed /// private void DetachVisual(Visual visual) { ContainerVisual parent = (ContainerVisual)(VisualTreeHelper.GetParent(visual)); if (parent != null) { VisualCollection children = parent.Children; children.Remove(visual); // If the parent is a childless highlighter, detach it too. HighlighterContainerVisual hcVisual = parent as HighlighterContainerVisual; if (hcVisual != null && hcVisual.Children.Count == 0 && _highlighters != null && _highlighters.ContainsValue(hcVisual)) { DetachVisual(hcVisual); _highlighters.Remove(hcVisual.Color); } } } ////// Attaches event handlers to stroke events /// private void StartListeningOnStrokeEvents(Stroke stroke) { System.Diagnostics.Debug.Assert(stroke != null); stroke.Invalidated += new EventHandler(OnStrokeInvalidated); } ////// Detaches event handlers from stroke /// private void StopListeningOnStrokeEvents(Stroke stroke) { System.Diagnostics.Debug.Assert(stroke != null); stroke.Invalidated -= new EventHandler(OnStrokeInvalidated); } ////// Finds a container for a new visual based on the drawing attributes /// of the stroke rendered into that visual. /// /// drawing attributes ///visual private ContainerVisual GetContainerVisual(DrawingAttributes drawingAttributes) { System.Diagnostics.Debug.Assert(drawingAttributes != null); HighlighterContainerVisual hcVisual; if (drawingAttributes.IsHighlighter) { // For a highlighter stroke, the color.A is neglected. Color color = StrokeRenderer.GetHighlighterColor(drawingAttributes.Color); if ((_highlighters == null) || (_highlighters.TryGetValue(color, out hcVisual) == false)) { if (_highlighters == null) { _highlighters = new Dictionary(); } hcVisual = new HighlighterContainerVisual(color); hcVisual.Opacity = StrokeRenderer.HighlighterOpacity; _highlightersRoot.Children.Add(hcVisual); _highlighters.Add(color, hcVisual); } else if (VisualTreeHelper.GetParent(hcVisual) == null) { _highlightersRoot.Children.Add(hcVisual); } return hcVisual; } else { return _regularInkVisuals; } } #endregion #region Fields // The renderer's top level container visuals private ContainerVisual _rootVisual; private ContainerVisual _highlightersRoot; private ContainerVisual _incrementalRenderingVisuals; private ContainerVisual _regularInkVisuals; // Stroke-to-visual map private Dictionary _visuals; // Color-to-visual map for highlighter ink container visuals private Dictionary _highlighters = null; // Collection of strokes this Renderer renders private StrokeCollection _strokes = null; // List of visuals attached via AttachIncrementalRendering private List _attachedVisuals = null; // Whhen true, will render in high contrast mode private bool _highContrast; private Color _highContrastColor = Colors.White; #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
- XmlSchemas.cs
- RewritingValidator.cs
- ProtocolsConfigurationHandler.cs
- InternalConfigEventArgs.cs
- DictionaryChange.cs
- DescendantOverDescendantQuery.cs
- DependencyPropertyValueSerializer.cs
- DbExpressionVisitor.cs
- ConfigurationElementProperty.cs
- SqlDataAdapter.cs
- SchemaImporterExtensionsSection.cs
- NetworkInformationPermission.cs
- InstanceNotReadyException.cs
- PermissionListSet.cs
- LoadGrammarCompletedEventArgs.cs
- PathNode.cs
- COM2AboutBoxPropertyDescriptor.cs
- TransactionFlowAttribute.cs
- XmlBinaryWriter.cs
- IteratorFilter.cs
- CodeValidator.cs
- MissingSatelliteAssemblyException.cs
- Variant.cs
- FormView.cs
- shaperfactory.cs
- ConnectionStringSettings.cs
- PEFileEvidenceFactory.cs
- OrderedDictionary.cs
- StatusBarPanel.cs
- EntitySetBase.cs
- ImplicitInputBrush.cs
- SoundPlayerAction.cs
- CorePropertiesFilter.cs
- BaseAsyncResult.cs
- LabelAutomationPeer.cs
- ExpandSegment.cs
- PageTextBox.cs
- HttpVersion.cs
- TemplateBamlRecordReader.cs
- ApplicationInfo.cs
- Constants.cs
- FlowDocumentPage.cs
- User.cs
- UnaryNode.cs
- InfoCardSymmetricCrypto.cs
- XomlDesignerLoader.cs
- ClientSettings.cs
- XmlNamespaceDeclarationsAttribute.cs
- DataGridColumnHeaderItemAutomationPeer.cs
- GlyphsSerializer.cs
- QilUnary.cs
- PrimitiveSchema.cs
- MtomMessageEncoder.cs
- TextServicesProperty.cs
- DefinitionProperties.cs
- TypeToken.cs
- XmlSchemaImporter.cs
- PageAsyncTaskManager.cs
- ConfigurationValidatorBase.cs
- ParameterReplacerVisitor.cs
- GcHandle.cs
- CodeDelegateCreateExpression.cs
- RequestCache.cs
- CodeSubDirectoriesCollection.cs
- TrackingDataItemValue.cs
- Encoder.cs
- QuaternionAnimation.cs
- ContentFileHelper.cs
- Accessible.cs
- ExceptionNotification.cs
- BinaryEditor.cs
- InputBinder.cs
- PenThreadPool.cs
- ScaleTransform3D.cs
- SqlPersonalizationProvider.cs
- EntitySetDataBindingList.cs
- DataGridViewRowCancelEventArgs.cs
- ListControlBuilder.cs
- SiteMapProvider.cs
- MenuItemStyleCollection.cs
- ResourceReferenceExpressionConverter.cs
- SmtpNetworkElement.cs
- DirectoryNotFoundException.cs
- ClientConfigurationHost.cs
- CompositeFontFamily.cs
- WSSecureConversationFeb2005.cs
- BitmapImage.cs
- HtmlInputFile.cs
- PeerTransportListenAddressValidator.cs
- FileFormatException.cs
- ParenthesizePropertyNameAttribute.cs
- CommandBindingCollection.cs
- SmtpFailedRecipientException.cs
- CardSpaceSelector.cs
- DBSchemaTable.cs
- StrongNameHelpers.cs
- UidPropertyAttribute.cs
- processwaithandle.cs
- DateRangeEvent.cs
- AQNBuilder.cs