Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / MS / Internal / Ink / Renderer.cs / 1 / 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. //------------------------------------------------------------------------ // // 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
- ObjectHelper.cs
- EntityTypeEmitter.cs
- FormsAuthenticationUser.cs
- CachedPathData.cs
- FontTypeConverter.cs
- BindingMemberInfo.cs
- CodeDOMUtility.cs
- HttpHostedTransportConfiguration.cs
- HierarchicalDataBoundControlAdapter.cs
- EnumerableCollectionView.cs
- WorkBatch.cs
- ShaderRenderModeValidation.cs
- Substitution.cs
- SqlConnectionFactory.cs
- IgnoreSectionHandler.cs
- GuidTagList.cs
- ThreadAttributes.cs
- ResXDataNode.cs
- Debug.cs
- ApplicationFileParser.cs
- ThicknessAnimationBase.cs
- CurrencyManager.cs
- ConfigurationSectionCollection.cs
- ImagingCache.cs
- ConfigurationSettings.cs
- EncryptedKey.cs
- GridViewRowEventArgs.cs
- BatchParser.cs
- PopupEventArgs.cs
- TargetPerspective.cs
- ListViewCommandEventArgs.cs
- SspiHelper.cs
- AnonymousIdentificationModule.cs
- WsdlWriter.cs
- Transform3D.cs
- AddressAlreadyInUseException.cs
- PageAsyncTaskManager.cs
- Crc32.cs
- Attributes.cs
- ImageConverter.cs
- CommandValueSerializer.cs
- MetabaseSettingsIis7.cs
- sqlstateclientmanager.cs
- Model3DGroup.cs
- MailWriter.cs
- ScalarOps.cs
- BaseParaClient.cs
- Visual.cs
- StrictAndMessageFilter.cs
- DataGridViewComboBoxColumnDesigner.cs
- DesignerValidationSummaryAdapter.cs
- DecoderExceptionFallback.cs
- SafeEventLogWriteHandle.cs
- Roles.cs
- PathFigureCollectionConverter.cs
- ContentType.cs
- FileDialog.cs
- prompt.cs
- TabControlEvent.cs
- AssemblyInfo.cs
- MultiSelectRootGridEntry.cs
- AppliedDeviceFiltersDialog.cs
- ProgressBarAutomationPeer.cs
- Int32Converter.cs
- WebHeaderCollection.cs
- TextTreeExtractElementUndoUnit.cs
- TargetException.cs
- SpeechDetectedEventArgs.cs
- XpsTokenContext.cs
- DataColumnChangeEvent.cs
- DocumentationServerProtocol.cs
- DataListGeneralPage.cs
- EntityDataSourceEntitySetNameItem.cs
- FlowNode.cs
- ListViewInsertEventArgs.cs
- ClientScriptManager.cs
- GridViewColumnCollectionChangedEventArgs.cs
- CompositeCollectionView.cs
- KoreanLunisolarCalendar.cs
- HttpClientCertificate.cs
- PreProcessor.cs
- GAC.cs
- TrackingRecord.cs
- PeerToPeerException.cs
- XmlSchemaAttributeGroupRef.cs
- ScriptingScriptResourceHandlerSection.cs
- ExtentKey.cs
- EnumConverter.cs
- AuthenticationManager.cs
- SerialReceived.cs
- ConfigurationSectionGroup.cs
- ParamArrayAttribute.cs
- ObjectPersistData.cs
- HttpWriter.cs
- _SslSessionsCache.cs
- JoinElimination.cs
- SpecialFolderEnumConverter.cs
- MsmqHostedTransportConfiguration.cs
- TemplateFactory.cs
- SetState.cs