views:

962

answers:

4

Hi, I'm using .NET C# with standard WinForms, not WPF.

I have this situation. I'm creating a user control for a month calendar, similar to the .NET one but with a little more functionality. I have a user control form, that fills with button objects representing dates. The buttons can be colored with different color depending on their state(selected, mouse over, weekend...)

The way I'd like it to work is extending the button class to accept states, which determine colors, rather than coloring them from the parent (user control) class. There are 10 colors at the moment and I'd really wouldn't like to mess up the user control code with coloring conditions.

Also I would like to select all the colors at design time, using browsable designer properties. The problem is that the designer shows only properties defined in the user control class, and not its children (buttons).

Is there any workaround for this problem? So to put it short I want to change colors using internal button properties, and to be able to select them at design time, using designer properties, and not hard coding them manually.

+1  A: 

There are various things you can do here - you could (although it is a bad answer) expose the controls in question on the public interface - but I'm not sure that is a great idea.

Personally, I would just re-expose the properties I am interested in, perhaps putting them into a different [Category(...)] - making sure to have both setters and getters.

A bit like:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

class MyControl : UserControl
{
    private Button button;
    private Label label;
    public MyControl()
    {
        button = new Button { Dock = DockStyle.Right, Text = "Click me" };
        label = new Label { Dock = DockStyle.Left};
        Controls.Add(button);
        Controls.Add(label);
    }
    [Category("Wonder Control")]
    public string CaptionText { get { return label.Text; } set { label.Text = value; } }
    [Category("Wonder Control")]
    public Color ButtonBackColor { get { return button.BackColor; } set { button.BackColor = value; } }
}
static class Program
{

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        using (Form form = new Form())
        using (MyControl ctrl = new MyControl())
        using (PropertyGrid grid = new PropertyGrid())
        {
            ctrl.ButtonBackColor = Color.Red;
            ctrl.CaptionText = "Caption";
            ctrl.Dock = DockStyle.Fill;
            grid.Dock = DockStyle.Right;
            form.Controls.Add(ctrl);
            form.Controls.Add(grid);
            grid.SelectedObject = ctrl;
            Application.Run(form);
        }

    }
}
Marc Gravell
How do you mean re-expose?I can expose them in the parent class with [Category].Is there any way I can expose them only in child class?
Zoran Ivancevic
+1  A: 

For a property to be visible in the designer, they have to be public properties with a getter and setter - from what you're saying, the properties are only getters. You could also try specifying BrowsableAttribute and BindableAttribute on the properties to coerce the designer to display them...

thecoop
+2  A: 

Ok, I'll try to explain trough code:

For example, I have a user control and a button class. I want to expose Button properties, and make them visible among MyControl properties in designer.

class MyControl : UserControl
{
     private MyButton button;
     button.ChangeStyle("Selected");
}

class MyButton : Button
{
     private Color buttonColor;

     public void ChangeStyle(string styleName)
     {
          if (styleName == "Selected")
              this.BackColor = buttonColor;
     }

     [Browsable(true)]
     [Category("Button style")]
     public Color ButtonColor
     {
          get { return buttonColor; }
          set { buttonColor = value; }
     }
}

This is a simple example. Normally I have 5 different styles including background and foreground color for each of them. So instead of managing colors in MyControl class, I'd like to define them in MyButton class. But the problem this way is that the properties in the MyButton class aren't visible in designer, because it only focuses on MyControl properties.

Btw. ignore the missing constructors and other basic classes stuff in the code example

I can't use:

[Category("Wonder Control")]
public Color ButtonBackColor { get { return button.BackColor; } set { button.BackColor = value; }

because I have 30 buttons in MyControl (days in month), and I can't reference just a single object.

Zoran Ivancevic
A: 

If all of the buttons within the control will share the same appearance, why not put the property at the control level and have the property setter propogate any changes to all of the buttons? Also, using 30 individual button controls seems like lot of overhead... have you considered drawing the labels for the days and handling mouse click/hover events to determine when a particular day is clicked?

lJohnson
That is the current solution.I have control properties for colors and propagate them to buttons.I have considered manually drawing everything, but I want buttons to be active objects, not just plain graphics. I'd like to avoid hit testing the whole user control to determine the selected date.Also this way I don't have to redraw all the dates on each click, just the ones that have been changed.
Zoran Ivancevic
What do you mean by "a lot of overhead"? Performance issues or just a lot of unnecessary code? I was thinking of manually creating the button class, not just inheriting from Button and implementing just the features that I need
Zoran Ivancevic