예제 #1
0
        /// <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);
        }