public void Paint(Graphics g, Rectangle bounds) { // Lock the sheet and strokes using (Synchronizer.Lock(this.m_Sheet.SyncRoot)) { using (Synchronizer.Lock(this.m_Sheet.Ink.Strokes.SyncRoot)) { if (this.m_Sheet.Ink.Strokes.Count <= 0) { return; } // Make a copy of the set of all strokes to be painted. // The selected strokes will be removed from this and painted separately. Strokes strokes = this.m_Sheet.Ink.Strokes; Strokes selection = this.m_Sheet.Selection; if (selection != null) { strokes.Remove(selection); } // Create an image using temporary graphics and graphics buffer object Bitmap imageForPrinting = new Bitmap(bounds.Width, bounds.Height); using (Graphics graphicsImage = Graphics.FromImage(imageForPrinting)) using (DibGraphicsBuffer dib = new DibGraphicsBuffer()) { // Create temporary screen Graphics System.Windows.Forms.Form tempForm = new System.Windows.Forms.Form(); Graphics screenGraphics = tempForm.CreateGraphics(); // Create temporary Graphics from the Device Independent Bitmap using (Graphics graphicsTemp = dib.RequestBuffer(screenGraphics, bounds.Width, bounds.Height)) { graphicsTemp.Clear(System.Drawing.Color.Transparent); // Draw the unselected ink! // (Ink is not a published property of the InkSheetModel, so no need to obtain a lock.) this.m_Renderer.Draw(graphicsTemp, strokes); if (selection != null) { // Draw each stroke individually, adjusting its DrawingAttributes. // TODO: This is very inefficient compared to drawing them all as a group (make a selection of several hundred strokes to see -- a big slow-down). foreach (Stroke stroke in selection) { // It's possible to erase ink while it's selected, // either with the inverted end of the stylus or via the Undo service. // But even though the deleted ink won't be part of the main Ink.Strokes collection, // it won't have been removed from the selection Strokes collection. // TODO: Being able to delete strokes while they are selected might break more than this. // Evaluate what needs to change in the eraser and undo service to make this less hacky. if (stroke.Deleted) { continue; } // First draw a highlighted background for all the strokes. DrawingAttributes atts = stroke.DrawingAttributes.Clone(); float width = atts.Width, height = atts.Height; atts.RasterOperation = RasterOperation.CopyPen; atts.Color = SystemColors.Highlight; atts.Width += SELECTED_BORDER_WIDTH__HIMETRIC; atts.Height += SELECTED_BORDER_WIDTH__HIMETRIC; this.m_Renderer.Draw(graphicsTemp, stroke, atts); } foreach (Stroke stroke in selection) { if (stroke.Deleted) { continue; } // Second, draw the stroke itself, but with a contrastive color. DrawingAttributes atts = stroke.DrawingAttributes.Clone(); atts.RasterOperation = RasterOperation.CopyPen; atts.Color = SystemColors.HighlightText; this.m_Renderer.Draw(graphicsTemp, stroke, atts); } } // Use the buffer to paint onto the final image dib.PaintBuffer(graphicsImage, 0, 0); // Draw this image onto the printer graphics, // adjusting for printer margins g.DrawImage(imageForPrinting, bounds.Top, bounds.Left); } } } } }