In PropertyGrid default color picker dialog not allow to set alpha value of color.
I already made my own color picker dialog and want to use it in PropertyGrid but not sure how to do it.
I managed to use my custom color picker dialog in property grid and copying code of it here in case some need it too:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace HelpersLib
{
public class MyColorEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
if (value.GetType() != typeof(RGBA))
{
return value;
}
IWindowsFormsEditorService svc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if (svc != null)
{
using (DialogColor form = new DialogColor((RGBA)value))
{
if (svc.ShowDialog(form) == DialogResult.OK)
{
return form.NewColor.RGBA;
}
}
}
return value;
}
public override bool GetPaintValueSupported(ITypeDescriptorContext context)
{
return true;
}
public override void PaintValue(PaintValueEventArgs e)
{
using (SolidBrush brush = new SolidBrush((RGBA)e.Value))
{
e.Graphics.FillRectangle(brush, e.Bounds);
}
e.Graphics.DrawRectangleProper(Pens.Black, e.Bounds);
}
}
}
And this is how it looks in property grid:
When i click button of it, it will open custom color dialog.
But still have one problem which i can't solve.
I can't use Color struct with this UITypeEditor, therefore created RGBA class.
When i use color struct, it look like this:
I will open another question for it i guess: Custom ColorEditor does not work properly on Color struct
To interact with PropertyGrid, you have to create your own "property class" (as described here). You can customise different parts and thus there are multiple solutions for what you want. As a first approach to your problem, here you have a code for propertyGrid1:
Property curProperty = new Property();
propertyGrid1.SelectedObject = curProperty;
Where Property is defined by:
public class Property
{
private ColorDialog _dialog = new customColorDialogDialog();
public ColorDialog dialog
{
get { return _dialog; }
set { _dialog.ShowDialog(); }
}
}
class customColorDialogDialog : ColorDialog
{
}
In this code, your color dialog (customColorDialogDialog) is triggered when clicking on the cell on the right hand side of the property name ("dialog").
Related
I would like to create a customized control that inherits from GroupBox and have a property that is a collection of TextBox. I intent to create in Designer as many TextBoxes as I want, similarly what could be done with TabControl, which one could create pages in TabPages properties through the Collection Editor window.
I created the property TextBoxList that appears in properties window and when I click in the “…” Collection Editor window opens to create the TextBox and set its properties, but when I click the ok button, none TextBox is added to my GroupBox. The TextBox instances were created, but were not added to the GroupBox. Does somebody could help me with the TextBox addition to the GroupBox? Follows the code.
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Forms;
namespace CustomizedControl
{
public partial class GroupBoxWithTextBox : GroupBox
{
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor(typeof(System.ComponentModel.Design.CollectionEditor),
typeof(System.Drawing.Design.UITypeEditor))]
[Description("The TextBoxes in GroupBox control."), Category("Behavior")]
public Collection<TextBox> TextBoxList
{
get
{
return _textBoxList;
}
}
private Collection<TextBox> _textBoxList = new Collection<TextBox>();
public GroupBoxWithTextBox()
{
InitializeComponent();
}
}
}
Based on my research, we need to override the class CollectionEditor if we want to add the textbox in design.
I write the following code and you can have a look.
Code:
[Serializable]
public partial class GroupBoxWithTextBox : GroupBox
{
public GroupBoxWithTextBox()
{
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
Padding = new Padding(0);
textBox = new TextBox();
textBox.Size = new System.Drawing.Size(60, 30);
Controls1.Add(textBox);
textBox.Dock = DockStyle.Top;
}
[EditorAttribute(typeof(NewCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
public ControlCollection Controls1
{
get
{
return base.Controls;
}
set
{
}
}
private TextBox textBox;
}
public partial class NewCollectionEditor : CollectionEditor
{
public NewCollectionEditor(Type t) : base(t)
{
}
// *** Magic happens here: ***
// override the base class to SPECIFY the Type allowed
// rather than letting it derive the Types from the collection type
// which would allow any control to be added
protected override Type[] CreateNewItemTypes()
{
Type[] ValidTypes = new[] { typeof(TextBox) };
return ValidTypes;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
return base.EditValue(context, provider, value);
}
}
Result:(You need to set the textbox location manually)
Hope this could help you.
I'm building custom control by extending ScrollableControl.
Problem is that my custom control acts as container - I can drag controls into it:
My question is how can I disable container functionality in class that extends ScrollableControl
Below are two test controls, one extends Control, second ScrollableControl
public class ControlBasedControl : Control
{
protected override Size DefaultSize
{
get { return new Size(100, 100); }
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(Brushes.LightCoral, ClientRectangle);
}
}
public class ScrollableControlBasedControl : ScrollableControl
{
public ScrollableControlBasedControl()
{
AutoScrollMinSize = new Size(200, 200);
}
protected override Size DefaultSize
{
get { return new Size(100, 100); }
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(Brushes.LawnGreen, ClientRectangle);
}
}
You get "acts-like-a-container" behavior at design time from the [Designer] attribute. Copy-pasting from the Reference Source:
[
ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDispatch),
Designer("System.Windows.Forms.Design.ScrollableControlDesigner, " + AssemblyRef.SystemDesign)
]
public class ScrollableControl : Control, IArrangedElement {
// etc...
}
It is ScrollableControlDesigner that gets the job done. Doesn't do much by itself, but derived from ParentControlDesigner, the designer that permits a control to act as a parent for child controls and gives it container-like behavior at design time.
Fix is easy, you just have to use your own [Designer] attribute to select another designer. Add a reference to System.Design and make it look like this:
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms.Design; // Add reference to System.Design
[Designer(typeof(ControlDesigner))]
public class ScrollableControlBasedControl : ScrollableControl {
// etc...
}
There is probably more than one way to accomplish this, but here is what I would do...
First create a read-only version of ControlCollection
public class ReadOnlyControlCollection : Control.ControlCollection
{
public ReadOnlyControlCollection(Control owner)
: base(owner)
{
}
public override bool IsReadOnly
{
get { return true; }
}
public override void Add(Control control)
{
throw new ArgumentException("control");
}
}
Then make your ScrollableControlBasedControl create an instance of ReadOnlyControlCollection in stead of the default ControlCollection
public class ScrollableControlBasedControl : ScrollableControl
{
protected override Control.ControlCollection CreateControlsInstance()
{
return new ReadOnlyControlCollection(this);
}
// The rest of your class goes here...
}
I use Visual Studio 2010 and when I drop a control on an ScrollableControlBasedControl the control is magically moved back to where it came from, as if the action was cancelled.
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 have a custom textbox, which is just a standard textbox with a couple additional small features, and it all works as expected. The problem I am having is that clicking in the field to change the cursor location does not actually change the location of the cursor, the cursor just stays at the beginning of the field.
Below is the code I am working with, I am hoping someone will be able to tell me what I am missing:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Test.UI.Controls
{
public partial class TestTextBox : TextBox
{
private Color normalForegroundColor = Color.Gray;
private Color textChangedForegroundColor = Color.Red;
private string startingText = string.Empty;
[Description("TextBox border color when text is changed"), Category("Appearance")]
public Color TextChangedColor
{
get { return textChangedForegroundColor; }
set { textChangedForegroundColor = value; }
}
[Description("Set starting text of textbox, as well as the Text property"), Category("Appearance")]
public String StartingText
{
get { return startingText; }
set
{
startingText = value;
this.Text = startingText;
}
}
public TestTextBox()
{
InitializeComponent();
normalForegroundColor = this.ForeColor;
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
this.ForeColor = this.Text == startingText ? normalForegroundColor : textChangedForegroundColor;
}
}
}
Below is a screen grab of what the custom textbox looks like with data in it:
I am trying to customize the controls on my WinForms database application.
So far I have only tried to customize labels and buttons using the following code:
namespace MyNamespace
{
public class CMSLabel : Label
{
private Color cmsLabelBackColor = aSystem.LabelBackColor;
public CMSLabel()
{
this.BackColor = cmsLabelBackColor;
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Color BackColor
{
get { return cmsLabelBackColor; }
set { }
}
}
public class CMSButton : Button
{
private Color cmsButtonColor = aSystem.ButtonColor;
public CMSButton()
{
base.BackColor = cmsButtonColor;
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Color BackColor
{
get { return cmsButtonColor; }
set { }
}
}
}
The Button control works perfectly, but the Label controls exhibit no BackColor at all, yet I've used the same code for each control type. Can anyone spot what I have done wrong?
You have to change the "base" color:
public CMSLabel()
{
base.BackColor = cmsLabelBackColor;
}
In the CMSButton you set base.BackColor, but in CMSLabel you set this.BackColor, which has no code in the setter.