/// <summary> /// Renders the visual content of the <see cref="ImageListBoxItem"/>.</summary> /// <param name="context"> /// The <see cref="DrawingContext"/> for the rendering.</param> /// <remarks><para> /// <b>OnRender</b> calls the base class implementation of <see cref="UIElement.OnRender"/>, /// and then attempts to display the current <see cref="ContentControl.Content"/> of the /// <see cref="ImageListBoxItem"/>, depending on its type: /// </para><list type="bullet"><item> /// If the element is an <see cref="EntityImage"/>, its first image frame is drawn above a /// text label showing its identifier. /// </item><item> /// If the element is an <see cref="ImageFrame"/>, the frame is drawn without a label. /// </item><item> /// If the element is a <see cref="RectI"/>, the corresponding region of the <see /// cref="ImageListBox.FrameBitmap"/> is drawn without a label. /// </item></list><para> /// If the element is of any other type, or if an error occurs, the "invalid" icon returned /// by <see cref="Images.Invalid"/> is drawn instead.</para></remarks> protected override void OnRender(DrawingContext context) { base.OnRender(context); // default to base class if not in an ImageListBox ImageListBox listBox = Parent as ImageListBox; if (listBox == null) { return; } // get drawing parameters of containing ImageListBox WriteableBitmap bitmap = listBox.FrameBitmap; ImageScaling scalingX = listBox.ScalingX, scalingY = listBox.ScalingY; // source within bitmap and target within context RectI source = RectI.Empty; Rect target = new Rect(0, 0, ActualWidth, ActualHeight); /* * The default Background brush of a ListBoxItem is transparent, meaning that an item * will not register clicks on anything but the non-transparent image and text label. * * This is very inconvenient, so we always draw a fully opaque background. We use the * ListBox.Background brush for regular items, and the system-defined HighlightBrush * for selected items. The Foreground brush changes automatically as appropriate. * * NOTE: The HighlightBrush must be drawn explicitly anyway, or else the Foreground * of a selected item would be invisible against the Background of the ListBox! */ Brush background = (listBox.SelectedItem == this ? SystemColors.HighlightBrush : listBox.Background); context.DrawRectangle(background, null, target); // check which content we're drawing if (Content is RectI) { source = (RectI)Content; } else { ImageFrame frame = Content as ImageFrame; if (frame == null) { EntityImage image = Content as EntityImage; if (image == null) { goto failure; } // get first image frame and scaling frame = image.Frames[0]; scalingX = image.ScalingX; scalingY = image.ScalingY; // compute bounds of image label Point textLocation = new Point(0, ActualHeight - this._labelHeight); Size textSize = new Size(ActualWidth, this._labelHeight); // reduce image bounds accordingly target.Height -= textSize.Height; // draw text for image label FormattedText text = FormatLabel(image.Id, textSize); context.DrawText(text, textLocation); } // final sanity check for valid image frame if (frame == null || frame.Source.Value == null) { goto failure; } // draw image frame with associated bitmap bitmap = frame.Source.Value.Bitmap; source = frame.Bounds; } // draw specified rectangle with desired bitmap & scaling if (ImageUtility.DrawOutlineFrame(context, Foreground, target, bitmap, source, listBox.Polygon, scalingX, scalingY, ColorVector.Empty, PointI.Empty, PointI.Empty)) { return; } failure: // draw "invalid" icon on failure ImageUtility.DrawInvalidIcon(context, Foreground, target, listBox.Polygon); }