ChildForm cannot change the properties of the BaseForm - c#

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.

Related

How do I call in a method in a Form when a property of a class referenced in that form changes?

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);
}

Setting default size/text of custom control in c#

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!!

Bind "Enabled" properties of controls to a variable

I am running into an issue that I have found on some similar post, however, they are not quite the same and I am not quite sure how to apply it to my scenario. They may or may not be the same as my case. So, I am posting my own question here hopefully, I will get an answer to my specific scenario.
Basically, I have a window form with a bunch of controls. I would like to have the ability to bind their Enabled property to a Boolean variable that I set so that they can be enable or disable to my discretion.
public partial class MyUI : Form
{
private int _myID;
public int myID
{
get
{
return _myID;;
}
set
{
if (value!=null)
{
_bEnable = true;
}
}
}
private bool _bEnable = false;
public bool isEnabled
{
get { return _bEnable; }
set { _bEnable = value; }
}
public myUI()
{
InitializeComponent();
}
public void EnableControls()
{
if (_bEnable)
{
ctl1.Enabled = true;
ctl2.Enabled = true;
......
ctl5.Enabled = true;
}
else
{
ctl1.Enabled = false;
ctl2.Enabled = false;
......
ctl5.Enabled = false;
}
}
}
}
The method EnableControls above would do what I need but it may not be the best approach. I prefer to have ctrl1..5 be bound to my variable _bEnable. The variable will change depending on one field users enter, if the value in the field exists in the database, then other controls will be enabled for user to update otherwise they will be disabled.
I have found a very similar question here
but the data is bound to the text field. How do I get rid of the EnableControls method and bind the value of _bEnabled to the "Enabled" property in each control?
Go look into the MVVM (Model - View - ViewModel) pattern, specifically its implementation within Windows Forms. Its much easier to apply it to a WPF/Silverlight application, but you can still use it with Windows Forms without too much trouble.
To solve your problem directly, you will need to do 2 things:
Create some class that will hold your internal state (i.e. whether or not the buttons are enabled). This class must implement INotifyPropertyChanged. This will be your View Model in the MVVM pattern.
Bind an instance of the class from 1.) above to your Form. Your form is the View in the MVVM pattern.
After you have done 1 and 2 above, you can then change the state of your class (i.e. change a property representing whether a button is enabled from true to false) and the Form will be updated automatically to show this change.
The code below should be enough to get the concept working. You will need to extend it obviously, but it should be enough to get you started.
View Model
public class ViewModel : INotifyPropertyChanged
{
private bool _isDoStuffButtonEnabled;
public bool IsDoStuffButtonEnabled
{
get
{
return _isDoStuffButtonEnabled;
}
set
{
if (_isDoStuffButtonEnabled == value) return;
_isDoStuffButtonEnabled = value;
RaisePropertyChanged("IsDoStuffButtonEnabled");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
View
public class View : Form
{
public Button DoStuffButton { get; set; }
public void Bind(ViewModel vm)
{
DoStuffButton.DataBindings.Add("Enabled", vm, "IsDoStuffButtonEnabled");
}
}
Usage
public class Startup
{
public ViewModel ViewModel { get; set; }
public View View { get; set; }
public void Startup()
{
ViewModel = new ViewModel();
View = new View();
View.Bind(ViewModel);
View.Show();
ViewModel.IsDoStuffButtonEnabled = true;
// Button becomes enabled on form.
// ... other stuff here.
}
}
Maybe you can try this approach: in your isEnabled property's setter method, add an if statement:
if(_bEnable) EnableControls();
else DisableControls();
And if your control names are ctl1,ctl2... etc. you can try this:
EnableControls()
{
for(int i=1; i<6;i++)
{
string controlName = "ctl" + i;
this.Controls[controlName].Enabled = true;
}
}
And apply the same logic in DisableControls
If you have more controls in future this could be more elegant.

Invoke or BeginInvoke cannot be called on a control until the window handle has been created error occurs in c# winform

I have a custom control inherits from System.Windows.Forms.Button.
And I have a property called Enabled and DelegateProperty.
public class Button : System.Windows.Forms.Button
{
public bool DelegateProperty { get; set; }
public new bool Enabled
{
get { return base.Enabled; }
set
{
if (DelegateProperty)
{
MethodInvoker action = delegate
{
base.Enabled = value;
};
this.BeginInvoke(action);
}
else
base.Enabled = value;
}
}
}
And when I set DelegateProperty as true in that control, it gives me this error in design time.
"Invoke or BeginInvoke cannot be called on a control until the window handle has been created"
I have tried to avoid MethodInvoker when it's design time using
bool isInDesignMode = LicenseManager.UsageMode == LicenseUsageMode.Designtime || Debugger.IsAttached == true;
But, still I get this error in design time.
How can I avoid running BeginInvode method in design time?

Hide property from inherited silverlight control

I am trying to hide a property from Intellisense for the Text property of the TextBox control.
I tried the following, but I get a compile error complaining that the Text property is not set as virtual in the base class. I am not trying to remove the property, just hide it from Intellisense. Any ideas?
public class MyTextBox:TextBox
{
[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
}
}
}
YOu can use new keyword to hide it if its not virtual.
Like this:
public class MyTextBox:TextBox
{
[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
public new string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
}
}
}

Categories