/// <summary> /// StrokeCollectionChanged event handler /// </summary> 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 sync 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)); } } }
/// <summary> /// Attaches a stroke visual to the tree based on the stroke's /// drawing attributes and/or its z-order (index in the collection). /// </summary> 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); } } }
/// <summary> /// StrokeCollectionChanged event handler /// </summary> 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)); } } }