So today, I decided to create a custom TextButton control in C# using Visual Studio 2012. I quite like the design I've made, simple as it may be. However, when I decided I would move my completed component into a form using the Visual Studio Designer, I ran into a snag. Although the Text property shows up in the properties list, the property is not not actually being changed in the MainWindow.Designer.cs file. Below is the code that defines the property:
[Category("Appearance")]
[Description("The text displayed by the control.")]
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public override string Text
{
get
{
return Button.Text;
}
set
{
Button.Text = value;
}
}
And here is the code that my MainWindow.Designer.cs file is creating in the InitializeComponent method:
this.Open = new UI.Controls.TextButton();
this.Open.Location = new System.Drawing.Point(9, 3);
this.Open.Name = "Open";
this.Open.Size = new System.Drawing.Size(112, 28);
this.Open.TabIndex = 4;
this.Open.Click += new System.EventHandler(this.OpenButton_Click);
Part of the problem is that you are overriding the UserControl's Text Property. If you name your property another name besides Text such as myText it will work. In order to fix the problem you have using Text try adding the DesignerSerializationVisibility Attribute to your Property, that should take care of it.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
Related
I'm a beginner, and I think that the solution is very simple, but I can't find it all over the Internet.
I'm looking for a way of setting the back color of forms and controls to a certain color variable so if I change its value to green for exapmple, every control that its back color set to mainColor will turn green and that the changes will show up in the designer.
public class MainForm:Form
{
public static Color mainColor=[some color];
public static Color secColor=[some color];
public Main()
{
InitializeComponent();
BackColor=mainColor;
control1.BackColor=secColor;
control2.BackColor=secColor;
control3.BackColor=secColor;
}
}
Like that by changing mainColor and secColor. The controls are changed, but it wont show up in the designer. What is the right way of doing it?
Use the Colors class.
public static Color redColor = Colors.Red;
public static Color greenColor = Colors.Green;
public static Color blueColor = Colors.Blue;
public static Color whiteColor = Colors.White;
Here is a pallete of the available colors:
If you want to create a new color, use Color.FromArgb();
Check out this answer for more information on new colors.
Yes, that is called DataBinding, and it's done partly with the Designer and partly with code.
Instead of declaring
public static Color mainColor=[some color];
declare it as a property:
public Color MyColor
{
get
{
return myColor;
}
set
{
myColor = value;
}
}
In your main form, edit each of the controls that you want to be influenced by this variable to bind their color property to it. I'll use a Panel as the sample control, so add some Panel objects to your form. Then in each Panel object, in the Properties panel, click the + next to DataBindings, then click in the empty box next to (Advanced). Click the ellipsis (...) and select the BackColor property. Then, under the Binding dropdown, select Add Project Data Source. Select Object in the next dialog and navigate to your form, and select that. A list of properties will then appear in the Formatting and Advanced Binding dialog box and you can select your property MyColor.
Note that once you have created this data source for the first one, you won't need to recreate it for each Panel - just reference the one you created already.
You can then change the BackColor of any of the controls you did this databinding on by changing the value of the MyColor property in your program. They will all change together.
You will probably also need to arrange that property to broadcast the message that it has changed, so add this line to the set() method.
form1BindingSource.ResetBindings(false);
so that the set method looks like this.
set
{
myColor = value;
form1BindingSource.ResetBindings(false);
}
That tells the binding source object to notify all subscribers to update themselves, and it will happen automatically every time the MyColor property is changed.
I created a custom Button, called AcceptButton, inheriting from System.Windows.Forms.Button
On the constructor I set a few properties, but most important, an image (A green checkmark), like this:
this.Image = Proyecto.Controls.Bases.Properties.Resources.ok_16;
When I add this control using VS2013 form designer, in another project that references the DLL I just created, the image is displayed correctly. But if I go into my control, and change the image in code, for example, to:
this.Image = Proyecto.Controls.Bases.Properties.Resources.ok_32;
The image is not changed in the projects that use this control (even if the solution is cleaned and regenerated). I followed the code generated by VS2013 and I found that the designer adds this line:
this.botonAceptar1.Image = ((System.Drawing.Image)(resources.GetObject("botonAceptar1.Image")));
For some reason, this resource is "hardcoded" in a resource file generated by VS, but it's not updated when I regenerate the solution.
Removing this line makes it work as expected (I can change the image in the "upstream" class and it'll be updated when the solution is regenerated).
Why is this happening?
How can I avoid this?
This happens due to the DesignerSerializationVisibility (MSDN) attribute. Try adding this property and these methods (MSDN) to your class:
public class MyButton : System.Windows.Forms.Button
{
public bool ShouldSerializeImage()
{
return !object.ReferenceEquals(this.Image, _BaseImage);
}
public void ResetImage()
{
this.Image = _BaseImage;
}
[System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Visible)]
public new Image Image
{
get { return base.Image; }
set { base.Image = value; }
}
private Bitmap _BaseImage;
public MyButton()
{
_BaseImage = Proyecto.Controls.Bases.Properties.Resources.ok_16;
this.Image = _BaseImage;
}
}
This replaces the default Image property and prevents the serialization you encountered. Furthermore it allows the designer to check if the property has it's default value and if it needs to be serialized. The default value is stored in a private field in the button class. This should correctly serialize (or not serialize) the properties.
Remove all buttons you have, recompile, readd the buttons to make sure.
I have a customized button deriving from System.Windows.Forms.Button:
(class MyButton : Button)
This button has an extra property called IsSelected.
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
if (value)
this.Font = new Font(_storedFont.FontFamily, _storedFont.Size - 1); //Decrease font size by 1
else
this.Font = _storedFont; //Set font back to origin
}
}
If IsSelected is set true the font size of the button will be decreased by 1 point to show the user of the application, that this button is in "pressed" state.
If IsSelected is set false the font size of the button will be set back to original size to show the user that this button is now again in "normal" state.
The issue is now that I first need to store the original font size that has been set in the properties window in Visual Studio, before it is changed by IsSelected.
To hold the stored original font size I have property called StoredFont (class level field = _storedFont).
I then tried to store the original font size in a chained constructor in MyButton, but it appears that the constructor is called before Visual Studio has actually set the font that has been defined in the properties window.
Question 1:
Is it correct that the constructor is called before Visual Studio actually sets the font?
Question 2:
Any suggestions to how to save the font that has been set from the properties window when a new instance of MyButton is created?
Note!
I have already considered many other possibilities to show selected state (CheckBox instead of Button, other back color etc.), and this is not my question.
Thanks a lot in advance!
Question 1: Yes otherwise you'll endup with a NullReferenceException...
Question 2: Assuming the first Font assignment is the font you want to store, you could store the font in an override of Font
public override Font Font
{
get
{
return base.Font;
}
set
{
if(_storedFont == null)
_storedFont = Font;
base.Font = value;
}
}
This way you don't have to worry about the order of initialization.
I have a library. In the library, I have a button with a Green background color and Text as Go Green.
Now I made a winform project and dragged my Go green button in the form. On running the application, I noticed that the button color is changing to green but text is displayed as button1 (name of the class library).
My library looks like:
public class button : Button
{
public Seats()
{
button.BackColor = Color.Green;
button.Text = "Go Green";
}
}
I discovered that it is happening because InitializeComponent() method is called in the constructor of the form. And in designer.cs,
button.Text = "button1";
is called. How can I avoid that to happen. I want my text to be visible from my class library.
Note: When I manually removed the above code from the designer.cs, everything was working fine.
Easiest way - override button's Text property and make it hidden to designer serialization:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get { return base.Text; }
set { base.Text = value; }
}
Designer will add default button name, but when you build application, your text will be shown.
UPDATE: Another (harder) way - provide to designer default property value for your button. In this case you need reference System.Design.dll which is available only for full version of .net framework (not client profile version).
First: create control designer for your button
public class GoGreenButtonDesigner : System.Windows.Forms.Design.ControlDesigner
{
public override void OnSetComponentDefaults()
{
base.OnSetComponentDefaults();
Control.Text = "Go Green";
}
}
Last: add Designer attribute to your custom button class
[Designer(typeof(GoGreenButtonDesigner))]
public class GoGreenButton : Button
{
//...
}
That's it. Now when you drag button to form, it will have default text "Go Green" without any additional compilations.
I have a custom control that when I drag onto the form, creates the following designer.cs code:
//
// colorPickerBackground
//
this.colorPickerBackground.Color = Color.Empty;
this.colorPickerBackground.Location = new System.Drawing.Point(256, 175);
this.colorPickerBackground.Name = "colorPickerBackground";
this.colorPickerBackground.Size = new System.Drawing.Size(156, 21);
this.colorPickerBackground.TabIndex = 17;
this.colorPickerBackground.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(this.colorPicke
I'd like it (Visual Studio) to completely ignore the .Color attribute and leave it be. How can I tell it to do that?
Thank you!
You can derive a new class from the ColorPickerBackground class. Override (or new) the Color property and decorate with the attributes found in System.ComponentModel...
Take a look at these:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public Color Color { get; set; }
http://msdn.microsoft.com/en-us/library/system.componentmodel.designerserializationvisibilityattribute.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.browsableattribute.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.editorbrowsableattribute.aspx