Search code examples
c#winformsuser-controls.net-3.5gdi

Unable to use the overridden BackColor property of a UserControl


Scenario

I am using a UserControl for creating a customized control.

I am trying to override the BackColor property of the UserControl, so that, on BackColor property change of the UserControl, the BackColor of the control doesn't gets changed and the value is stored in the variable named BackColor_Value:

Here is the code for it:

Color BackColor_Value = Color.FromKnownColor(KnownColor.ActiveCaption);
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Bindable(true)]
//[AmbientValue(false)]
//[DefaultValue(typeof(Color), "ActiveCaption")]
public override Color BackColor
{
      get
      {
          return BackColor_Value;
      }
      set
      {
          BackColor_Value = value;
      }
 }

Note: The BackColor is just stored in a variable but not used anywhere. enter image description here

EDIT: What I'm trying to accomplish is to change the BackColor of a selection of controls when the UserControl's BackColor property is set, leaving the UserControl's background Color unchanged.

Problem

For some reason the Backcolor of the control is getting changed according to the variable BackColor_Value I have specified.

  • Why is the default functionality still happening even after I have overridden the property?
  • What attribute should I use to stop this from happening?

Complete Code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;

namespace MaterialUI_Control
{
    public partial class MaterialPanel : UserControl
    {
        public MaterialPanel()
        {
            InitializeComponent();
        }

        Color BackColor_Value = Color.FromKnownColor(KnownColor.ActiveCaption);
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Bindable(true)]
        [AmbientValue(false)]
        [DefaultValue(typeof(Color), "ActiveCaption")]
        public override Color BackColor
        {
            get
            {
                return BackColor_Value;
            }
            set
            {
                BackColor_Value = value;
                this.Refresh();
            }
        }
    }
}

Solution

  • BackColor property will be used by OnPaintBackground method to render the control. If you want to use the BackColor property for another purpose, you can use either of the following options:

    • Override OnPaintBackground and paint the background yourself (ignore the BackColor)
    • Shadow/hide the BackColor property

    You also need to consider another fact about the BackColor property, it's an ambient property, which means if you don't set it explicitly, it will follow the value of the parent control's BackColor property.

    Example 1 - Override OnPaintBackground and paint the background yourself

    You can override the OnPaintBackground method and ignore the value of BackColor property:

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        var method = typeof(Control).GetMethod("PaintBackground",
            System.Reflection.BindingFlags.Instance |
            System.Reflection.BindingFlags.NonPublic,
            null,
            new Type[] { typeof(PaintEventArgs), typeof(Rectangle), typeof(Color) },
            null);
    
        //Paint with a default constant back color, here for example Color.Red
        method.Invoke(this, new object[] { e, ClientRectangle, Color.Red });
    }
    

    In this case, changing the back color will not change the rendering of your control, however it will change the BackColor of the child controls which doesn't explicitly have a BackColor assigned.

    Example 2 - Shadow/hide the BackColor property

    You can shadow/hide the BackColor property:

    public new Color BackColor { get; set; }
    

    In this case, changing the back color will not change the rendering of your control, it also have no impact on the child controls and if you want to change back color of child controls, you need to add some logic in setter of the property.

    Also to set the color which is used by OnPaintBackground, in the constructor, you can set base.BackColor = Color.Blue; or something.