Reseting label back to design-time .Text value - c#

I have a bunch of labels that I set their value in the designer and later during runtime update them, but after using them, I want to set them back to their default value. My intent with this is to reduce the amount of large code to help make it easier to read.
random example like, setting in the designer of lbl_fruit Text = no fruits available currently then
*code*
lbl_fruits.Text = "banana";
*code*
lbl_fruits.ResetText(); // I want something like this
lbl_fruits.Text = "no fruits available currently"; // Instead of this
The .ResetText(); doesn't work for this as the label text gets cleaned instead of returning to "no fruits available currently"
My current solution is making a custom label control.
public class ExLabel : Label
{
private string defaultValue = "";
public string DefaultValue
{
get { return defaultValue; }
set { defaultValue = value; this.Invalidate(); }
}
protected override void OnControlAdded(ControlEventArgs e)
{
defaultValue = this.Text;
MessageBox.Show("This code is being run");
base.OnControlAdded(e);
}
public void ResetValue()
{
this.Text = defaultValue;
}
}
This code currently solves my problem if I use the custom propriety I made, but for me the ideal solution would be to have the design-time text value as the default value and not an extra propriety I made. OnControlAdded() does not get executed, OnPaint() runs again when lbl_fruits.Text = "banana"; happens.
So the question is: Which event I can override so the code gets executed as soon as the label is loaded but doesn't run twice. And also, is there a simpler way of approaching this?

In the end the solution I used was this:
public class ExLabel : Label
{
private string defaultValue = "";
public string DefaultValue
{
get { return defaultValue; }
set { defaultValue = value; this.Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
if(defaultValue == "" && !this.Text.Contains("exLabel"))
{
defaultValue = this.Text;
}
base.OnPaint(e);
}
public void ResetValue()
{
this.Text = defaultValue;
}
}

public class ExLabel : Label
{
private string defaultValue = "";
public string DefaultValue
{
get { return defaultValue; }
set { defaultValue = value; this.Invalidate(); }
}
protected override void OnControlAdded(ControlEventArgs e)
{
defaultValue = this.Text;
MessageBox.Show("This code is being run");
base.OnControlAdded(e);
}
public void ResetValue()
{
this.Text = defaultValue;
}
}

Related

How to use user defined property in construction method for a winform?

I made a textbox that only accepts numbers and a "-" for negative numbers. I would like there to be an option to disable negative numbers.
In the constructor method I want to reference the allowNegatives bool that is defined properties editor and do different things depending on if it allows negatives values. I'm running into the problem that the 'allowNegatives' bool is always its default value in the constructor. If I reference it elsewhere it is the correct value.
Is there an way to get the assigned property value rather than the default value in the constructor?
public partial class ControlIntEntry : TextBox
{
private bool allowNegatives = false;
[Description("Allow negative values"), Category("Behavior")]
public bool AllowNegatives
{
get { return allowNegatives; }
set { allowNegatives = value; }
}
public ControlIntEntry()
{
// user sets AllowNegatives to true using properties editor
InitializeComponent();
Console.WriteLine(allowNegatives); // returns false
if (allowNegatives)
{
//do one thing
}
else
{
// do something else.
}
Task.Run(() => AfterConstructor()); // use for testing
}
private async Task AfterConstructor()
{
await Task.Delay(1000);
Console.WriteLine(allowNegatives); //returns true
}
}
Before you can assign a value to an instance property, the class should be instantiated, so first constructor will run and then you can assign property values.
That said, to have a better understanding of what is happening here, when you drop an instance of a control on your form at design time and set some of its properties, designer will generate a code like this:
private void InitializeComponent()
{
...
this.myControl1 = new MyControl();
...
//
// myControl1
//
this.myControl1.Location = new System.Drawing.Point(0, 0);
this.myControl1.Name = "myControl1";
this.myControl1.Size = new System.Drawing.Size(100, 22);
this.myControl1.MyProperty = true;
...
}
I believe it's now clear that what is happening here. You see first the constructor of your control will run, then later property values will be set.
To use property values to configure your object can put the logic inside the setter of the property:
private bool myProperty = false;
public bool MyProperty
{
get { return myProperty;}
set
{
myProperty = value;
// some logic here.
}
}
It's the most common scenario.
Another option is delaying the initializations to some time later, for example when the control handle is created by overriding OnHandleCreated or another suitable time.
// This is just an example, the event may not be a good one for your requirement
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// some logic here
}
Another option for complex initialization scenarios which may involve multiple properties, you can implement ISupportInitialize and put the logic inside EndInit:
public class MyControl : TextBox, ISupportInitialize
{
public void BeginInit()
{
}
public void EndInit()
{
// some logic here
}
}
Then when you drop an instance of the control on the form, this code will be generated in addition to the common code that I showed at beginning of this answer:
...
((System.ComponentModel.ISupportInitialize)(this.myControl1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
...
(I expect it's obvious now, that) All above options will run after running the constructor.
Putting that code in the setter worked
public partial class ControlIntEntry : TextBox
{
private bool allowNegatives = false;
[Description("Allow negative values"), Category("Behavior")]
public bool AllowNegatives
{
get { return allowNegatives; }
set
{
allowNegatives = value;
if (allowNegatives)
this.KeyPress += KeyPress_AllowNegatives;
else
this.KeyPress += KeyPress_PositiveOnly;
}
}
public ControlIntEntry()
{
InitializeComponent();
}
private void KeyPress_PositiveOnly(object sender, KeyPressEventArgs e)
{
Char newChar = e.KeyChar;
if (!Char.IsDigit(newChar) && newChar != 8)
{
e.Handled = true;
}
}
private void KeyPress_AllowNegatives(object sender, KeyPressEventArgs e)
{
Char newChar = e.KeyChar;
int cursorIndex = this.SelectionStart;
if (cursorIndex == 0)
{
if (!Char.IsDigit(newChar) && newChar != 8 && newChar != 45)
{
e.Handled = true;
}
}
else
{
if (!Char.IsDigit(newChar) && newChar != 8)
{
e.Handled = true;
}
}
}
}

Can't Set Custom TextBox text via the properties window in visual studio

I am trying to set the text in my custom textbox with a variable that I can preset in the visual studio properties window, but the variable keeps ending up empty
namespace CustomControlTest
{
public partial class MyTextField : TextBox
{
public MyTextField()
{
InitializeComponent();
this.Text = "Potato";
this.Text = GhostText;
if(GhostText == null)
{
this.Text = "Orange";
}
}
public string GhostText { get; set; }
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
}
}
The textbox text gets set to "Orange" which i don't understand because I have set it to "Something" in the visual studio properties.
I want to be able to set the value of GhostText from her
What am I doing wrong here ?
I think this may help you to solve your problem:
namespace CustomControlTest
{
public partial class MyTextField : TextBox
{
public MyTextField()
{
InitializeComponent();
}
private string _ghostText;
public string GhostText
{
get
{
return _ghostText;
}
set
{
this.Text = value;
_ghostText = value;
}
}
}
}
and in some other class:
var ctr = new MyTextField ();
ctr.GhostText = "Something";

Textbox rendered as label

I have created a custom web server control that will have a bool property 'RenderAsLabel' so that I can convert textboxes to labels, for Read-only forms. I was wondering if there is any reason why this code should not be safe, or work as intended. Upon initial testing it seems fine, but I just want to make sure I'm not doing something that will end up causing issues.
namespace OrmControlLibrary
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:OrmTextBox ID='' runat=server ></{0}:OrmTextBox>")]
public class OrmTextBox : TextBox
{
private Label lbl;
public virtual bool RenderAsLabel
{
get
{
if (ViewState["OrmTextBox"] == null)
{
return false;
}
else
{
return (bool)ViewState["OrmTextBox"];
}
}
set
{
ViewState["OrmTextBox"] = value;
}
}
protected override void Render(HtmlTextWriter w)
{
if (RenderAsLabel)
{
SetLabelProperties();
lbl.RenderControl(w);
}
else
{
base.Render(w);
}
}
private void SetLabelProperties()
{
lbl = new Label();
lbl.ID = this.ID;
lbl.CssClass = this.CssClass;
lbl.Text = this.Text;
}
}
}

C# swap in Designer

I have my Control.When I change the properties of the control. I get this:
this.myLabel1.BorderShadow = true;
this.myLabel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
And I need to get this:
this.myLabel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.myLabel1.BorderShadow = true;
How to do so is done automatically in Form.Desinger.cs ?
If you say Why?
private bool BorderShadow_ = false;
public bool BorderShadow
{
get
{
return BorderShadow_;
}
set
{
if (Border_Style_ == BorderStyle.FixedSingle)
{
BorderShadow_ = value;
}
else
{
throw new ArgumentOutOfRangeException("BorderShadow", "BorderShadow can be true if BorderStyle=FixedSingle");
}
}
}
You could look into the ISupportInitialize interface. It allows you to skip the validity check when initializing your controls. For example (adapted from one of my projects):
public class MyControl : Control, ISupportInitialize
{
private bool _created = true;
public void BeginInit()
{
_created = false;
}
public void EndInit()
{
_created = true;
//check all your properties here too
}
private bool BorderShadow_ = false;
public bool BorderShadow
{
get
{
return BorderShadow_;
}
set
{
BorderShadow_ = value;
if (_created && Border_Style_ != BorderStyle.FixedSingle)
throw new ArgumentOutOfRangeException();
}
}
}
If I remember correctly, the VS designer will automatically add calls to BeginInit and EndInit for you as well.
I think they will appears in the same order as they are defined. So you can override with new old setting:
public new BorderStyle BorderStyle
{
get {return base.BorderStyle;}
set {base.BorderStyle = value;}
}
and then declare your BorderShadow setting.
The designer will always order the properties alphabetically and this can't be changed.
The sense of a property is that it is side effect free and that it can be changed at any time in any order. This means that if you have multiple properties which representing some kind of complex state and not all combinations are making sense, this error should not be reported while switching the property itself.
So to accomplish these problems you have two possibilities:
Like #Andrew already mentioned implement ISupportInitialize and take care if you are within this state.
Within the property setter call a method that checks if all settings currently made are making sense and perform the desired action only in this case:
public class MyControl : Control
{
private bool _BorderShadow;
private BorderStyle _BorderStyle;
public bool BorderShadow
{
get { return _BorderShadow; }
set
{
if(_BorderShadow != value)
{
_BordeShadow = value;
ApplyBorderShadowIfNeeded();
}
}
}
public BorderStyle BorderStyle
{
get { return _BorderStyle; }
set
{
if(_BorderStyle != value)
{
_BorderStyle = value;
ApplyBorderShadowIfNeeded();
}
}
}
private void ApplyBorderShadowIfNeeded()
{
if(_BorderStyle == BorderStyle.FixedSingle
&& _BorderShadow)
{
// ToDo: Apply the shadow to the border.
}
}
}

Can I hide Value in NumericUpDown control?

Lets say we have 0 displayed in value field of the control and I want that if the value is 0 - display string.Empty (I know that the type of value is decimal and there can be no string inserted instead of decimals in it, but still... Maybe there is some formatting possible there?).
Note: This is dependent on the current implementation of NumericUpDown.
What you need to do is create a new control that inherits from NumericUpDown such that:
public partial class SpecialNumericUpDown : NumericUpDown
{
public SpecialNumericUpDown()
{
InitializeComponent();
}
protected override void UpdateEditText()
{
if (this.Value != 0)
{
base.UpdateEditText();
}
else
{
base.Controls[1].Text = "";
}
}
}
public partial class MyNumericUpDown : NumericUpDown
{
public override string Text
{
get
{
if (base.Text.Length == 0)
{
return "0";
}
else
{
return base.Text;
}
}
set
{
if (value.Equals("0"))
{
base.Text = "";
}
else
{
base.Text = value;
}
}
}
}
It seems that there is only very limited support for changing the formatting.
I have not tried this myself. But you could create a subclass and override the UpdateEditText method to support your custom format. Something like this:
protected override void UpdateEditText()
{
this.Text = Value.ToString(); // Insert your formatting here
}
An easier solution is calling the ResetText() method. You can restore the text changing the Value property.
Example code to hide text when NumericUpDown control is disabled, and restore it on enabled
private void NumericUpDown_EnabledChanged(object sender, EventArgs e)
{
if (numericUpDown.Enabled)
{
if (numericUpDown.Tag != null)
{
// Restore last value
numericUpDown.Value = (decimal)numericUpDown.Tag;
}
}
else
{
// Save last value
numericUpDown.Tag = numericUpDown.Value;
// Just to force value change
numericUpDown.Value = (numericUpDown.Value > numericUpDown.Minimum ? numericUpDown.Minimum : numericUpDown.Maximum);
// Clear text
numericUpDown.ResetText();
}
}
If you only want to hide the value from the user, you can make ForeColor the same as BackColor so the value inside NumericUpDown will be invisible to the user.

Categories

Resources