Link to home
Start Free TrialLog in
Avatar of FALECoder
FALECoderFlag for Finland

asked on

C# OnPaint: How to custom paint background and default paint rest?

Hi!

I'm trying to create a DevExpress ComboBoxEdit with a linear gradient painted background, but the control itself doesn't support it directly (see: http://www.devexpress.com/Support/Center/p/Q233062.aspx).

I'd basically want to override OnPaint, in it manually draw the gradient background and then let the default drawing draw everything ELSE, but I can't seem to get this to happen.

Below is my current attempt at creating an overriden version of the ComboBoxEdit. There I basically try to do the background, then set the backgound color to transparent and call the base OnPaint so that it would not paint the background (since it is transparent) but paint everything else.

    public class ComboBoxEditWithGradient : ComboBoxEdit
    {
        protected override void OnPaint(PaintEventArgs e)
        {
            if (Properties.Appearance.BackColor2 != Properties.Appearance.BackColor)
            {
                LinearGradientBrush gradientBrush = new LinearGradientBrush(new Point(0, 0),
                                                                            new Point(ClientSize.Width, 0),
                                                                            Properties.Appearance.BackColor,
                                                                            Properties.Appearance.BackColor2);
                e.Graphics.FillRectangle(gradientBrush, e.ClipRectangle);
                Color oldColor = Properties.Appearance.BackColor;
                Properties.Appearance.BackColor = Color.Transparent;
                base.OnPaint(e);
                Properties.Appearance.BackColor = oldColor;
            }
            else
            {
                base.OnPaint(e);
            }
        }
    }

This seems like it could produce the desired result, BUT it really jams the GUI execution, i.e. the OnPaint events just keep firing, so clearly there's something wrong in here. I also tried with putting a boolean flag ignoreEvents to true when within the OnPaint and exiting it if coming to the method and that is on, but that didn't affect, so it doesn't seem to come directly recursively to itself at least.

If I leave out the setting of the properties and the calling of the base.OnPaint, then I just get the gradient rectangle and nothing else, as could be expected (and no jamming). If I just call the base.OnPaint without changing the properties, then I don't get the jamming problem, but the base-painting covers up the gradient background.

Sorry if I'm asking the obvious, but if anyone can point me to a (preferably simple) solution for creating a ComboBoxEdit with linear gradient, I'd greatly appreciate it!
Avatar of kaufmed
kaufmed
Flag of United States of America image

What's the intent of these two lines:

Properties.Appearance.BackColor = Color.Transparent;
...
Properties.Appearance.BackColor = oldColor;

Open in new window

Avatar of FALECoder

ASKER

The idea of those two lines is to change the background color to transparent for the duration of the base-call (ancestor implementation) so that the ancestor implementation would paint nothing in the background (and paint only the other stuff, text etc.), thus leaving the gradient that I've already drawn visible. The latter line is then to set to situation back to as it was after the base-call.
I don't have that control to test with, but it seems to me that assigning the BackColor inside of the Paint event is effectively creating a recursive loop. Any time the color of a control changes obviously a repaint of that control is needed. I believe this is why your GUI "jams up" when using the above code.

I'll have a think about this and respond a bit later.
I've been playing around a bit intermittently, and with the below solution I have the control looking ok and the GUI not jamming, but still sometimes the paint doesn't work correctly, i.e. it just paints a black box or something similar. Probably due to some events still getting lost that should not, but I'll continue investigating when I have time. Basically the new idea is to flag some paint events to be ignored (to resolve the recursive eventing) and also to do an immediate Update after setting the properties that assumably cause the recursive events.

        private bool ignoreNextPaintEvent = false;

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            return;

            if (ignoreNextPaintEvent)
            {
                ignoreNextPaintEvent = false;
                return;
            }
            if (!Properties.Appearance.BackColor2.IsEmpty && Properties.Appearance.BackColor2 != Properties.Appearance.BackColor && Properties.Appearance.BackColor != Color.Transparent)
            {
                LinearGradientBrush gradientBrush = new LinearGradientBrush(new Point(0, 0),
                                                                            new Point(ClientSize.Width, 0),
                                                                            Properties.Appearance.BackColor,
                                                                            Properties.Appearance.BackColor2);
                e.Graphics.FillRectangle(gradientBrush, e.ClipRectangle);
                ignoreNextPaintEvent = true;
                Color oldColor = Properties.Appearance.BackColor;
                Properties.Appearance.BackColor = Color.Transparent;
                if (ignoreNextPaintEvent) this.Update();    // Eat the paint event caused by the setting of the property above!
                base.OnPaint(e);
                ignoreNextPaintEvent = true;
                Properties.Appearance.BackColor = oldColor;
                if (ignoreNextPaintEvent) this.Update();    // Eat the paint event caused by the setting of the property above!


                //base.OnPaint(e);
                //e.Graphics.FillRectangle(gradientBrush, e.ClipRectangle.Left + 2, e.ClipRectangle.Top + 2, 5, 5);
            }
            else
            {
                base.OnPaint(e);
            }
        }
ASKER CERTIFIED SOLUTION
Avatar of FALECoder
FALECoder
Flag of Finland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I've requested that this question be deleted for the following reason:

The question has either no comments or not enough useful information to be called an "answer".
Hi!
My last comment describes the solution I ended up with, since that was the best I could do. It is not a perfect solution (in smaller clip rect cases gradient is ignored), so it is not a full answer to the question, but maybe it might be a usable solution for someone else working with a similar issue, so I'm wondering should this still not be deleted? I leave it to you to decide / guide me on how to do. If it is ok to include this partial solution as an "answer", then I can click "accept as solution" on my own last comment, so others may find it too, or if you think that is not a good decision, then it can be closed/deleted as you see fit.
The solution that I found myself is - although partial - the best that was received in this case. It covers most of the cases that were needed for me and I was able to accept that.