1

I use custom renderer for ContextMenuStrip. It works fine, but I can't figure out how can I use fields from outer class Form1 inside of class MyColors? I should get customColor from Form1 instead of "hardcoded" Color.Green. How can I achieve this?

public partial class Form1
{
    private Color customColor = Color.Red;

    private class MyRenderer : ToolStripProfessionalRenderer
    {
        public MyRenderer() : base(new MyColors()) { }
    }

    private class MyColors : ProfessionalColorTable
    {
        public override Color MenuItemSelected
        {
            get { return Color.Green; }
        }
    }
}

Thanks in advance.

darx
  • 1,417
  • 1
  • 11
  • 25
  • I think you're looking at it the wrong way. A `ProfessionalColorTable` is the replaceable part. A `ToolStripProfessionalRenderer` uses the values provided by a `ProfessionalColorTable`. This table(s) should contain the definitions. Not the Form class. – Jimi Sep 28 '18 at 16:58
  • https://stackoverflow.com/questions/185124/whats-the-best-way-of-accessing-field-in-the-enclosing-class-from-the-nested-cl – Furkan Kambay Sep 28 '18 at 16:59

2 Answers2

4

In general, I agree with other posters that a class should stand alone. I think it gets a little fuzzier when dealing with a private class, though.

In the few cases I've needed something like this, I pass the parent object into the private class' constructor:

public partial class Form1
{
    public Color customColor = Color.Red;

    private class MyRenderer : ToolStripProfessionalRenderer
    {
        public MyRenderer(Form1 form) : base(new MyColors(form)) { }
    }

    private class MyColors : ProfessionalColorTable
    {
        Form1 _form;

        public MyColors(Form1 form)
        {
            _form = form;
        }

        public override Color MenuItemSelected
        {
            get { return _form.customColor; }
        }
    }
}

Note that I had to make Form1.customColor public for this to work. That's a bit smelly, especially since it can now be assigned from the outside. In real work, I'd make it a property with a public getter and a private setter, so outside classes couldn't modify it.

Matt Dillard
  • 14,677
  • 7
  • 51
  • 61
  • 1
    Yes, this works great! I left `customColor` private, and added just a public getter `CustomColor` to retrieve `customColor`. – darx Sep 28 '18 at 17:12
1

You would be breaking encapsulation that way. If you need a contained class to know something from its containing class, you should provide such information in the contained class' constructor.

Otherwise, you would be letting another class change your class' properties, losing control over what happens inside Form1.

Considering your code, it seems ProfessionalColorTable has a parameterless constructor, so you should include a validation in case MyColors' private variable pointing to the containing class' color is not set (as a result of using the wrong constructor).

Andrew
  • 7,602
  • 2
  • 34
  • 42
  • This is a good way to look at it. A class should be thought of as an independent unit (typically, IMO). If it directly depends on outside "stuff", that's just not right. Kind of if you had a `Car` inside of a `Garage` class, and the `Garage` affected how the `Car` functioned. It's just...weird. – Broots Waymb Sep 28 '18 at 16:45