I created a user control. It's basically a button with some custom properties.
public partial class CustomButton : Button {
// My custom properties, constructor and events
}
Everytime I add this CustomButton on a form, its default Text value is set to "customButtonX", where X is 1, 2, 3, ...
How can I change this value? I would like it to be "buttonX" (X = 1, 2, 3...).
EDIT : I would like the trick (or whatever it is I have to do) to be active when I add a button on a form via the design view also. Meaning when I drag-drop a CustomButton from my toolbox to a form, its Text value should be "buttonX".
The default is "yourControlNameX" thats right. But you can replace the name in the constructor.
Note that this only will work at Runtime (not at design time)
public partial class CustomButton : Button {
// My custom properties, constructor and events
public CustomButton()
{
this.Text = this.Text.Replace("customButton ", "button");
}
}
When you drag a control from the Toolbox to a form there are some events that are triggered. In your case you have to subscribe to the one that is fired when the text property of your control is changed from String.Empty to the default name and change it. To do this you have to get the service that exposes these events (an implementation of IComponentChangeService) before the control is added to the form. This can be done overriding the Site property of your control. Modifying the example that you can find here, this kind of code should work:
private IComponentChangeService _changeService;
public override System.ComponentModel.ISite Site
{
get
{
return base.Site;
}
set
{
_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
if (_changeService != null)
_changeService.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged);
base.Site = value;
if (!DesignMode)
return;
_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
if (_changeService != null)
_changeService.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged);
}
}
private void OnComponentChanged(object sender, ComponentChangedEventArgs ce)
{
CustomButton aBtn = ce.Component as CustomButton;
if (aBtn == null || !aBtn.DesignMode)
return;
if (((IComponent)ce.Component).Site == null || ce.Member == null || ce.Member.Name != "Text")
return;
if (aBtn.Text == aBtn.Name)
aBtn.Text = aBtn.Name.Replace("customButton", "button");
}
Just override the text and set whatever you want into it.
public partial class CustomButton : Button {
public override string Text
{
get
{
//return custom text
return base.Text;
}
set
{
//modify value to suit your needs
base.Text = value;
}
}
}
May be you could use a ControlDesigner and set the Text property after inizialized.
public class MultiDesigner : ControlDesigner
{
public MultiDesigner()
{
}
public override void InitializeNewComponent(IDictionary defaultValues)
{
base.InitializeNewComponent(defaultValues);
ICommonControl control = this.Component as ICommonControl;
control.Text = control.Tag.ToString();
}
}
decorate your control with..
[Designer("MultiPuntoDeVenta.Controls.Tickets.Editors.Designer.MultiDesigner, MultiPuntoDeVenta.Controls")]
public class LabelBase<T> : KryptonLabel, ICommonControl where T : ICommonControl
{
.....
Related
WHAT I'M TRYING TO DO
Hello everyone. I'm trying to make a dropdown inside a property grid. This dropdown for some objects will just place its text inside the property, like a StringConverter. But for other objects, it behaves like a button and will open up other forms or an OpenFileDialog. These forms and OpenFileDialog return a text, which is then put inside the property. I feel like I'm doing this very incorrectly so if there is a better way of doing this. But hopefully there is a simple solution.
WHAT I'VE TRIED
I'm very close. I can get the text to show up on a MessageBox. But I can't seem to put it in the property grid, which is in another form and is protected so I can't shove the value in. The way it works is on the other form, the property grid selected an object, which has an attribute called text.
WHAT I'M DOING NOW
When I click on the dropdown for my text attribute in my property grid. The context menu strip is created, all the click events are on, and then, it returns a value right away. Which is not what I want. I want it to wait for me to click on one of the items inside the context menu, the click events sets the string text, and then, the value returns.
public class text-editor: UITypeEditor
{
string text = "";
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.DropDown; }
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
ContextMenuStrip cms = new ContextMenuStrip();
cms = MakeCms(cms); // adds some ToolStripEditor, & their click events which updates value
ToolStripMenuItem add = new TooStripMenuItem("Add");
add.Click += new EventHandler(CmsClick); // updates value
cms.Items.Add(add);
ToolStripMenuItem remove = new TooStripMenuItem("Remove");
remove.Click += new EventHandler(CmsClick); // updates value
cms.Items.Add(remove);
cms.Show(Control.MousePosition);
if (text != "")
{
value = text;
}
return value;
}
The ContextMenuStrip.Show method does not pause the caller and cannot be used here. Create a custom ContextMenuStrip integrated with IWindowsFormsEditorService.
public class TextEditor : UITypeEditor {
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.DropDown; }
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if(editorService != null) {
MyContextMenuStrip cms = new MyContextMenuStrip(editorService, "Add", "Remove");
editorService.DropDownControl(cms);
if(cms.SelectedItem == "Add")
return "Value When Add";
else if(cms.SelectedItem == "Remove")
return "Value When Remove";
}
return value;
}
}
class MyContextMenuStrip : UserControl {
readonly IWindowsFormsEditorService editorService;
readonly ListBox listBox;
public MyContextMenuStrip(IWindowsFormsEditorService editorService, params string[] items) {
this.editorService = editorService;
listBox = new ListBox();
listBox.Items.AddRange(items);
listBox.Dock = DockStyle.Fill;
listBox.MouseClick += ListBox_MouseClick;
listBox.Parent = this;
}
public string SelectedItem => (string)listBox.SelectedItem;
private void ListBox_MouseClick(object sender, MouseEventArgs e) {
ListBox listBox = (ListBox)sender;
if(listBox.SelectedIndex >= 0) {
Rectangle selectedItemRect = listBox.GetItemRectangle(listBox.SelectedIndex);
if(selectedItemRect.Contains(e.Location))
editorService.CloseDropDown();
}
}
}
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!!
In a windows application project I have a form which used a user control. I want to hide a label and textbox on user control. In which event of form I can do this ?
This method in user control which named DoctorPermissionApprove:
public void LoadDoctorPermission(int fromWhere)
{
if (fromWhere == 0) // Başhekimden geldiyse?
{
labelDoctor.Visible = true;
editDoctorWithoutHead.Visible = true;
}
else if (fromWhere == 1) // Normal Hekimden geldiyse
{
labelDoctor.Visible = false;
editDoctorWithoutHead.Visible = false;
}
}
And in form:
private void ExistRequestAndNewEntryForm_Shown(object sender, EventArgs e)
{
var obj = new DoctorPermissionApprove();
obj.LoadDoctorPermission(0);
}
For example I tried in shown event. But it still visible
I want to hide or show this components when the anybody open the form
Thank you a lot
In the UserControl class add a public property to set the internal label visibility true or false. This can be accessed from your parent form where your usercontrol is added.
Example:
public class YourUserControl
{
//This code will be in designer class
private Label lblYourLabelToHide = new Label();
//Create this public property to hide the label
public bool IsLabelVisible
{
set { lblYourLabelToHide.Visible = value; }
}
}
public class YourParentForm
{
//This will be in designer
private YourUserControl userControl = new YourUserControl();
public void Form_Load()
{
//based on some criteria
userControl.IsLabelVisible = false;
}
}
I want to perform Trim() method on each TexBox control on my page, before value is returned. I dont' want to hard-code the same code for each TexBox control, I want to do it in more elegant way.
I've found made the following class
namespace System.Web.UI.WebControls
{
public partial class TrimmedTextBuox : TextBox
{
private string text;
public override string Text
{
get { return string.IsNullOrEmpty(text) ? text : text.Trim(); }
set { text = value; }
}
}
}
but it fails, while debuggind the compiler doesn't get inside get{} and set{}.
After that, I created a UserControl item, but it must be deriverd from System.Web.UI.UserControl, not System.Web.UI.WebControls.TextBox to get it work (there's an exception which points to that)
So, how can I do that ?
First you have to register your control in your .aspx page like that:
<%# Register TagPrefix="customControls" Namespace="WebApplication.Custom.Controls" Assembly="WebApplication"%>
Then you can call it using the markup
<customControls:TrimmedTextBuox ID="txtTrim" runat="server"/>
Plus you don't have to create another "text" property in your custom TextBox. Instead, it can be done like that:
namespace WebApplication.Custom.Controls
{
public class TrimmedTextBuox : TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (!String.IsNullOrEmpty(value))
base.Text = value.Trim();
}
}
}
}
This will trim recursively all text boxes before inserting.
public static void trimRecursive(Control root)
{
foreach (Control control in root.Controls)
{
if (control is TextBox)
{
var textbox = control as TextBox;
textbox.Text = textbox.Text.Trim();
}
else
{
trimRecursive(control);
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
trimRecursive(Page);
}
Simple Solution to your problem is to hide the Text property of your base class by using new keyword. sample code...
public class TrimmedTextBox : TextBox
{
public new string Text
{
get
{
var t = (string) GetValue(TextProperty);
return t != null ? t.Trim() : string.Empty;
}
}
}
For more info about how new keyword with property works refrer to this SO Question
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;
}
}
}