Hey guys, I'm trying to set up a custom Panel called FormPanel from Panel
class FormPanel : Panel
{
bool previous;
FormPanel l;
public FormPanel()
{
previous = false;
l.Parent = this;
l.Dock = DockStyle.Fill;
}
}
This is pretty much where I am right now. I want the FormPanel to have a bool var and want to set it's default properties of Parent and Dock. How does this work? How can I set those?
In case you want your panel to have DockStyle.Fill as default for the Dock property, do this:
public class FormPanel : Panel
{
public FormPanel()
{
this.Dock = DockStyle.Fill;
}
[System.ComponentModel.DefaultValue(typeof(DockStyle), "Fill")]
public override DockStyle Dock
{
get { return base.Dock; }
set { base.Dock = value; }
}
}
This makes the Dock property default to Fill within the property window.
You shouldn't use an internal variable of your type, instead set the properties (that you inherit from the baseclass) directly:
class FormPanel : Panel
{
bool previous;
public FormPanel()
{
previous = false;
base.Parent = this;
base.Dock = DockStyle.Fill;
}
}
although I don't think that "base.Parent=this" will work ...
You need to add more info about what you're trying to achieve.
As it stands your FormPanel has a private field (l) which is itself a FormPanel:
FormPanel l;
You never instantiate this field, so it will always be null, and the assignments to properties in the constructor will fail with a NullReferenceException:
l.Parent = this;
l.Dock = DockStyle.Fill;
If you did instantiate this private field, you would have recursion, since your FormPanel contains a private FormPanel, which itself contains a private FormPanel, ...
l = new FormPanel();
l.Parent = this;
l.Dock = DockStyle.Fill;
You say you want to set a default Parent, but I don't see how a FormPanel can know what it's parent is in the constructor, unless you pass the parent as a parameter to the constructor, e.g. maybe you're looking for something like:
public FormPanel() : this(null)
{
}
public FormPanel(Control parent)
{
if (parent != null)
{
this.Parent = parent;
}
this.Dock = DockStyle.Fill;
...
}
Related
Now I have to create a form using custom control box, because of job request.
I have created a simple form class as BaseForm, done with the basic custom control box.
In order to control the Visible property of the Maximize and Minimize buttons, I re-write the original properties MaximizeBox and MinimizeBox with the keyword 'new' to hide them.
Then I create two new properties to control the visiblity of the custom buttons.
Code here.
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new bool MaximizeBox
{
get
{
return base.MaximizeBox;
}
set
{
base.MaximizeBox = value;
}
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new bool MinimizeBox
{
get
{
return base.MinimizeBox;
}
set
{
base.MinimizeBox = value;
}
}
[Category("Appearance"), DefaultValue(true)]
[Description("获取或设置当前窗体是否具有最大化按钮。")]
public virtual bool MaxBox
{
get
{
if (btnMaxBox == null)
return false;
return btnMaxBox.Visible;
}
set
{
if (btnMaxBox != null)
btnMaxBox.Visible = value;
}
}
[Category("Appearance"), DefaultValue(true)]
[Description("获取或设置当前窗体是否具有最小化按钮。")]
public virtual bool MinBox
{
get
{
if (btnMinBox == null)
return false;
return btnMinBox.Visible;
}
set
{
if (btnMinBox != null)
btnMinBox.Visible = value;
}
}
And here comes the problems.
These two properties seem work well on designer. And the ChildForm can also be changed if I switch the properties. But they will be re-set if I build the code or directly debug the program. And there's no code about the setting of these two properties in the designer code.
Does anyone know how to solve this?
Besides, the DefaultValueAttribute seem not work in designer.
I have a form and i created a new class for it.but i cant call Invalidate() inside the class
My Code -
public partial class CustomForm : Form
{
private bool showBorderLine;
private Color borderLineColor;
private int borderLineWidth;
public CustomForm()
{
InitializeComponent();
this.DoubleBuffered = true;
this.ResizeRedraw = true;
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.FormBorderStyle = FormBorderStyle.None;
borderLineColor = Color.DodgerBlue;
borderLineWidth = 1;
showBorderLine = true;
}
[Category("Form Editor")]
public bool ShowBorderLine
{
get { return showBorderLine; }
set
{
showBorderLine = value; // Here I can able to call invalidate
// and it works perfectly
this.Invalidate(true);
}
}
private ResizeOptions resizeOptions = new ResizeOptions();
[Category("Form Editor")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ResizeOptions ResizeOptions
{
get { return resizeOptions; }
set
{
resizeOptions = value;
this.Invalidate(true); // when I call invalidate here.it won't working. I hope I need to invalidate it in the Resize option Class for work perfectly
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class ResizeOptions // Inside this class i cant able to use invalidate method
{
private bool resizeTop;
private bool resizeBottom;
// more fields
public ResizeOptions()
{
resizeTop = true;
resizeBottom = true;
// more fields initialized
}
[Category("Form Editor")]
public bool ResizeTop
{
get { return resizeTop; }
set { resizeTop = value; } // I want to call invalidate method here
}
[Category("Form Editor")]
public bool ResizeBottom
{
get { return resizeBottom; }
set { resizeBottom = value; } // I want to call invalidate method here
}
// more of the same
}
You can see the invalidate method is possible inside the Form Class but i cant able to use it in ResizeOptions Class
i call invalidate method for get design time support for properties.
if you want i can provide the full code
please help me.
ResizeOptions is just a class that contains values. Even though you're using it in connection with a Form, it has no "awareness" that it is used within a form, and it shouldn't. It shouldn't need to know that when its values change, there is a form somewhere that should have its Invalidate() method called.
What's more, how can we even be sure there is a form to invalidate? We could do this:
var resizeOptions = new ResizeOptions();
Now there is no form at all. If we could somehow call Invalidate() from within this class, would would it invalidate?
What it can do is, when its values are changed, raise an event that says, "Hello, my values have changed!" and then other components, such as the form, can decide what they should do with that information.
To accomplish that you can create a delegate:
public delegate void ResizeOptionsChangedEventHandler(ResizeOptions sender);
Add an event in ResizeOptions:
public event ResizeOptionsChangedEventHandler ResizeOptionsChanged;
Raise it when you need to:
public bool ResizeTop
{
get { return resizeTop; }
set
{
resizeTop = value;
ResizeOptionsChanged?.Invoke(this);
}
}
Now ResizeOptions has done its part by letting anyone who cares know that it has changed. What, if anything, another class does with that information is up to that other class.
Now, in your form, you can subscribe to the event in the constructor:
public CustomForm()
{
// other constructor stuff
resizeOptions.ResizeOptionsChanged += ResizeOptions_ResizeOptionsChanged;
}
and in the property:
public ResizeOptions ResizeOptions
{
get { return resizeOptions; }
set
{
if (resizeOptions != null)
resizeOptions.ResizeOptionsChanged -= ResizeOptions_ResizeOptionsChanged;
resizeOptions = value;
resizeOptions.ResizeOptionsChanged += ResizeOptions_ResizeOptionsChanged;
this.Invalidate(true);
}
}
using this event handler:
private void ResizeOptions_ResizeOptionsChanged(ResizeOptions sender)
{
Invalidate(true);
}
I wrote a custom collection editor for a WinForms control. Its core code looks like this:
internal class MyCollectionEditor : CollectionEditor
{
public MyCollectionEditor(Type type) : base(type) { }
protected override System.ComponentModel.Design.CollectionEditor.CollectionForm CreateCollectionForm()
{
System.ComponentModel.Design.CollectionEditor.CollectionForm myForm = base.CreateCollectionForm();
#region Adjust the property grid
PropertyGrid myPropGrid = GetPropertyGrid(myForm);
if (myPropGrid != null)
{
myPropGrid.CommandsVisibleIfAvailable = true;
myPropGrid.HelpVisible = true;
myPropGrid.PropertySort = PropertySort.CategorizedAlphabetical;
}
#endregion
return myForm;
}
}
I need to set a custom size and location for the collection editor form, but I could not find a way to do that. It seems the collection editor form is always positioned by VS to its default location. Is there a way to do what I need?
It respects to the StartPosition, DesktopLocation and Size which you set for the form:
public class MyCollectionEditor : CollectionEditor
{
public MyCollectionEditor() : base(typeof(Collection<Point>)) { }
protected override CollectionForm CreateCollectionForm()
{
var form = base.CreateCollectionForm();
// Other Settings
// ...
form.StartPosition = FormStartPosition.Manual;
form.Size = new Size(900, 600);
form.DesktopLocation = new Point(10, 10);
return form;
}
}
Then decorate your property this way:
[Editor(typeof(MyCollectionEditor), typeof(UITypeEditor))]
public Collection<Point> MyPoints { get; set; }
I am creating a custom control in my C# application in order to add a new property (MyProperty below). It is inheriting from Label. One thing I would like it to do, is display at a particular size when I drag it on to my form (200x132). I'd also like it to display no text. However, no matter how I try to do this, it doesn't seem to work. I am able to set BackColor and BorderStyle with no problem, however. I'm fairly new to C#, so maybe I'm missing something obvious.
Here is my code:
using System.Drawing;
using System.Windows.Forms;
namespace MyProgram
{
public enum MyEnum
{
Value1, Value2, Value3
}
public partial class MyControl : Label
{
public MyControl()
{
BackColor = Color.LightCoral;
BorderStyle = BorderStyle.FixedSingle;
AutoSize = false;
Size = new Size(200, 132);
Text = "";
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
private MyEnum myProperty;
public MyEnum MyProperty
{
get { return myProperty; }
set { myPropery = value; }
}
}
}
The answer provided via Dispersia's link has a bug, in my opinion. The text reset should happen once and then whatever a user does after that shouldn't matter. In Dispersia's link you can't actually set the text back to the control name because it will keep blanking it out.
The answer provided by cramopy doesn't technically answer your question, it is a way to do it by using the defaults on a UserControl though. You'll also need to bind the Text property of the UserControl to the label's.
The following should work while inheriting from a Label and will only reset the Text property once.
public partial class MyControl : Label
{
#region fields
private IComponentChangeService _changeService;
private bool canResetText = false;
#endregion
#region properties
protected override Size DefaultSize
{
get { return new Size(200, 132); }
}
[Browsable(false)]
public override bool AutoSize
{
get { return false; }
set { base.AutoSize = false; }
}
public override ISite Site
{
get { return base.Site; }
set
{
base.Site = value;
if (!base.DesignMode)
return;
this._changeService = (IComponentChangeService)base.GetService(typeof(IComponentChangeService));
if (this._changeService != null)
this._changeService.ComponentChanged += new ComponentChangedEventHandler(this.OnComponentChanged);
}
}
#endregion
#region constructors
public MyControl()
{
base.BackColor = Color.LightCoral;
base.BorderStyle = BorderStyle.FixedSingle;
}
#endregion
#region methods
protected override void InitLayout()
{
base.InitLayout();
this.canResetText = true;
}
private void OnComponentChanged(object sender, ComponentChangedEventArgs ce)
{
if (ce.Component != null &&
ce.Component == this &&
ce.Member.Name == "Text" &&
base.DesignMode &&
this.canResetText)
{
((MyControl)ce.Component).Text = string.Empty;
this.canResetText = false;
if (this._changeService != null)
this._changeService.ComponentChanged -= new ComponentChangedEventHandler(this.OnComponentChanged);
}
}
#endregion
}
#Dispersia reply only answers the myControl1 thing. (deleted meanwhile)
Here comes a full guide for solving your problem:
Add a new UserControl named MyLabel
Change the following within Designer Mode:
BorderStyle:= FixedSingle
Size:= 200; 132
Now Drag&Drop a new Label onto the control
Edit those Label values (also within Designer Mode):
AutoSize:= false
BackColor:= LightCoral
Dock:= Fill
Text:= clear/empty this box!! (don't write this inside the box, you really have to clear it!)
TextAlign:= MiddleCenter
Just recompile your project && add a MyLabel control from the Toolbar.
Now it show up as you wanted!!
I am writing an application which is going to allows users to change the properties of a text box or label and these controls are user controls. Would it be easiest to create a separate class for each user control which implements the properties I want them to be able to change and then bind those back to the user control? Or is there another method I am overlooking?
Create a custom Attribute, and tag the properties you want the user to edit with this attribute. Then set the BrowsableAttribute property on the property grid to a collection containing only your custom attribute:
public class MyForm : Form
{
private PropertyGrid _grid = new PropertyGrid();
public MyForm()
{
this._grid.BrowsableAttributes = new AttributeCollection(new UserEditableAttribute());
this._grid.SelectedObject = new MyControl();
}
}
public class UserEditableAttribute : Attribute
{
}
public class MyControl : UserControl
{
private Label _label = new Label();
private TextBox _textBox = new TextBox();
[UserEditable]
public string Label
{
get
{
return this._label.Text;
}
set
{
this._label.Text = value;
}
}
[UserEditable]
public string Value
{
get
{
return this._textBox.Text;
}
set
{
this._textBox.Text = value;
}
}
}