How can I go about accessing the result of an if statement in a user control?
UserControl code:
public bool SendBack(bool huh)
{
if(huh)
huh = true;
else huh = false;
return huh;
}
And in a separate project i am trying to access it like this:
private void button1_Click(object sender, EventArgs e)
{
MyControl.TextControl t = (MyControl.TextCOntrol)sender;
if(t.SendBack(true))
{
// Do something.
}
}
In this case I thing the sender will be the button1, so it will not be castable to your usercontrol...
You will need a reference form the container (form/panel/...) that contains your usercontrol.
Also, I know this might be for simplicity but you can change
public bool SendBack(bool huh)
{
if(huh)
huh = true;
else huh = false;
return huh;
}
to
public bool SendBack(bool huh)
{
return huh;
}
You might also want to take a look at Control.ControlCollection.Find Method
Searches for controls by their Name
property and builds an array of all
the controls that match.
Related
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;
}
}
}
}
New C# problem...
I'm supposed to write 6 separate methods to clear 6 groups of checkboxes (all at once) when I click the clear button. I know how to code it with individual checkboxes, but the problem asks for me to create a method and then call all 6 of them upon clicking the clear button. Help?
I have nothing associated with the clearButton_Click event yet.
private void ClearOilLube
{
set {oilChangeCheckBox.Checked = false;
lubeJobCheckBox.Checked = false;}
}
private void ClearFlushes
{
set {radiatorFlushCheckBox.Checked = false;
transFlushCheckBox.Checked = false;}
}
private void ClearMisc
{
set {inspectionCheckBox.Checked = false;
replaceMufflerCheckBox.Checked = false;
tireRotationCheckBox.Checked = false;}
}
private void ClearOther
{
set {partsCostInputTextBox.Text = null;
laborInputTextBox.Text = null;}
}
private void ClearFees
{
set {servicesLaborDispLabel.Text = null;
partsDispLabel.Text = null;
partsTaxDispLabel.Text = null;
totalFeesDispLabel.Text = null;}
}
When the clear button is clicked just call the methods you created above to clear the data.
public void clearButton_Click(Object sender, EventArgs e)
{
ClearOilLube();
ClearFlushes();
ClearMisc();
ClearOther();
ClearFees();
// May be required to be called to ensure the UI is up to date.
Update();
}
Edit
The syntax on your question is a little strange. They are written kind of like properties when they should be methods. No 'set' or 'get' is needed. Just make them regular helper methods.
This is just typed in no testing on a compiler or IDE but what I can see is fixed.
private void ClearOilLube()
{
oilChangeCheckBox.Checked = false;
lubeJobCheckBox.Checked = false;
}
private void ClearFlushes()
{
radiatorFlushCheckBox.Checked = false;
transFlushCheckBox.Checked = false;
}
private void ClearMisc()
{
inspectionCheckBox.Checked = false;
replaceMufflerCheckBox.Checked = false;
tireRotationCheckBox.Checked = false;
}
private void ClearOther()
{
partsCostInputTextBox.Text = "";
laborInputTextBox.Text = "";
}
private void ClearFees()
{
servicesLaborDispLabel.Text = "";
partsDispLabel.Text = "";
partsTaxDispLabel.Text = "";
totalFeesDispLabel.Text = "";
}
Your methods (or is that properties?) are written quite badly. I will just assume that you want to write methods not properties.
Method headers take the following form: (simplified)
[access modifier] {return value type} {method name} ([parameter list])
So your methods should look like this:
private void ClearOilLube ()
{
oilChangeCheckBox.Checked = false;
lubeJobCheckBox.Checked = false;
}
private void ClearFlushes ()
{
radiatorFlushCheckBox.Checked = false;
transFlushCheckBox.Checked = false;
}
private void ClearMisc ()
{
inspectionCheckBox.Checked = false;
replaceMufflerCheckBox.Checked = false;
tireRotationCheckBox.Checked = false;
}
private void ClearOther ()
{
partsCostInputTextBox.Text = null;
laborInputTextBox.Text = null;
}
private void ClearFees ()
{
servicesLaborDispLabel.Text = null;
partsDispLabel.Text = null;
partsTaxDispLabel.Text = null;
totalFeesDispLabel.Text = null;
}
And then, you can call these methods one by one in the onClick method.
However, a better approach is to loop through (or iterate) through the Controls of the form.
private void ClearButtonClick (object sender, EventArgs e) {
foreach (Control control in this.Controls) {
if (control is CheckBox) {
((CheckBox)control).Checked = false;
}
}
}
If you still don't understand, tell me in the comments!
To give you an alternative, though it is more complex:
private void GetAllControlsOfType<TControl>(TControl collection, List<TControl> container) where TControl : Control
{
foreach(Control control in collection)
{
if(control is TControl)
container.Add(control);
if(control.HasControls())
GetAllControlsOfType<TControl>(control.Controls, container);
}
}
Then to utilize, you would simply do:
var checkboxes = new List<Checkbox>();
GetAllControlsOfType<Checkbox>(Page.Controls, checkboxes);
After that is executed it will contain a List of all the checkbox controls. Then you could simply map them to the state of the object or you can simply do the following:
foreach(var checkbox in checkboxes)
checkbox.Checked = false;
That would uncheck all, keep in mind this hasn't been tested so it may need some fine tuning.
I have a program with several different forms, most of these forms have some repetition in them especially when it comes to form manipulation controls. How do I create a common class so I don't have the same code on each form, but am still able to manipulate individual forms. For instance the code below is a ToolStripMenuControl for making the form Always on top. I have this code repeated 4 times in other forms, but I cant seem to wrap my head around how to go about creating a shared control for this. What am I missing here?
public bool onTop = false;
public bool ToggleTop()
{
if (onTop)
{
onTop = false;
this.TopMost = false;
keepOnTopToolStripMenuItem.Checked = false;
return onTop;
}
if (!onTop)
{
onTop = true;
this.TopMost = true;
keepOnTopToolStripMenuItem.Checked = true;
return onTop;
}
else return onTop;
}
private void keepOnTopToolStripMenuItem_Click(object sender, EventArgs e)
{
ToggleTop();
}
You don't need to store a separate bool onTop. Form.TopMost already tracks the exact same value.
For this simple task, your code is too long. You can rewrite it simply as:
public class Form5 : Form {
CheckBox cbTopMost = new CheckBox { Text = "Top Most" };
public Form5() {
Controls.Add(cbTopMost);
cbTopMost.CheckedChanged += delegate {
this.TopMost = cbTopMost.Checked;
};
}
}
If you really want, have all your Forms extend a base form, such as the example.
In your case I would use some base form with common implementation. It means you will move this code to some separate base class and all your forms with this ToolStripMenuControl will derive from it.
protected class FormWithToolStripControl : Form
{
//Initialization of ToolStripControl will be somewhere here
//And here your common code for all forms derived from this class
public bool onTop = false;
public bool ToggleTop()
{
if (onTop)
{
onTop = false;
this.TopMost = false;
keepOnTopToolStripMenuItem.Checked = false;
return onTop;
}
if (!onTop)
{
onTop = true;
this.TopMost = true;
keepOnTopToolStripMenuItem.Checked = true;
return onTop;
}
else return onTop;
}
private void keepOnTopToolStripMenuItem_Click(object sender, EventArgs e)
{
ToggleTop();
}
}
In a page, I have an event handler that sets 'Visible' to false on one control and true on another. Stepping through debug, I see that these values get set properly, and the control marked visible goes through OnPreRender while the control I have set to invisible does not. So all of that seems to be working as expected. However, when the request completes, the visibility has not changed at all on the page. I've tried setting the directly parent UpdatePanel to 'always' and have tried manually calling 'Update()' on it with no effect. Any clue as to what is going on here?
UPDATE:
I have found that it is only setting a private property on my user control that causes this whole thing to not work. I have included an example of that control and all of the places it references the private field.
Example:
protected override void OnLoad(EventArgs e)
{
if (this.IsPostback)
{
return;
}
this.Control1.Visible = true;
this.Control2.Visible = false;
}
protected void OnButtonClicked (object sender, EventArgs e)
{
this.Control1.Visible = false;
this.Control2.Visible = true;
// this has desired results when it fires
}
protected void OnUserControlEventThatFiresAfterRowCommand (object sender, EventArgs e)
{
this.Control2.SomeProp = this.GetSomeObject();
this.Control1.Visible = false;
this.Control2.Visible = true;
// this does not have desired results, even though it does fire
}
And then in Control2:
private SomeClass privatefield;
public SomeClass SomeProp
{
get
{
return this.privatefield;
}
set
{
this.PopulateFields(value);
this.privatefield = value;
// If I comment out this line it works!
}
}
protected override void LoadViewState(object savedState)
{
object[] state = savedState as object[];
base.LoadViewState(state[0]);
this.Enabled = state[1] as bool? ?? true;
this.SomeProp = state[2] as SomeClass;
this.Visible = state[3] as bool? ?? true;
}
protected override object SaveViewState()
{
return new object[]
{
base.SaveViewState(),
this.Enabled,
this.SomeProp,
this.Visible
};
}
I finally found out why by looking at the actual response body.
156|error|500|Error serializing value 'withheld class name' of type 'withheld class name'|
Why this error was not being thrown in debug is beyond me, but for anyone else reading this question looking for answers, look at your response bodies! It is because I was trying to put my instance of a class into Viewstate but that class was not marked with the Serializable attribute.
Is there any way I can reference a GridView object as a variable within my code behind page so I can refer to it once rather than multiple times?
I'm trying to make my code easier for me to update, and easier to transport. The less references I have to use the better!
This is an example of how my code sort of looks at the moment, there must be a better way of declaring the var GridView_ variable outside of the scope of each void?
public class GlobalVars
{
// Button Toggle
public static bool boolToggleView = false;
// Column Indexes
public static int Column1Index = new int();
}
protected void GetColumnIndexes()
{
// GridView Variable
var GridView_ = GridViewName;
// Column Indexes
GlobalVars.Column1Index = Utility.GetColumnIndexByName(GridView_, "Column1");
}
protected void Button1_Click(object sender, EventArgs e)
{
// GridView Variable
var GridView_ = GridViewName;
if (GlobalVars.boolToggleView)
{
GlobalVars.boolToggleView = false;
}
else
{
GlobalVars.boolToggleView = true;
}
// Bind GridView
GridView_.DataBind();
}