I'm trying to a do a program which manages tables in a restaurant.
When the button is clicked its supposed to check all the tables which are in an array if their status is clear,then highlight them by using another png.
ATTEMPTED FAILED CODE:
private void tblf_Click(object sender, EventArgs e)
{
for (; z < 9; )
{
"button" + x +.Image = Image.FromFile("C:\\Users\\cents\\Desktop\\programming stuff\\C#\\TABLES\\sprites and shit\\clearHIGH.png");
x += 1;
y += 1;
z += 1;
}
}
Try using Control.ControlCollection.Find
Button button = this.Controls.Find("button"+x, false).Single();
button.Image = Image.FromFile(
"C:\\Users\\cents\\Desktop\\programming stuff\\C#\\TABLES\\sprites and shit\\clearHIGH.png"
);
Instead of having button1, button2 etc as separate variables, have a single variable buttons of type List or Button[]. That way you can access buttons[x] etc.
Credit
goes to Jon skeet. This was the solution after all!
Ok so I have a variable called info which is of my own class called Kingdom Perk. It holds info about each different upgrade you can add to your kingdom and it gets passed to a script through a setup function, and in that function the public variable "info" gets assigned to whats passed in.
In an update function, if I write:
Debug.Log("Perk Name: " + info.Name);
It tells me "Cannon" or "Walls" e.t.c
But if I try to access it in a function that is run when a button is pressed, it tells me that "info" is null.
The setup function is always run before the button pressed function, and the same global variable works in the update function as it always tells me the correct thing, its only broken in this function.
Any help appreciated, ask if you need more detail
Thanks
EDIT: A different global variable also shows as null in this function only.
EDIT 2:
private KingdomPerk info;
public void Setup(KingdomPerk data)
{
info = data;
perkName.text = data.Name;
perkType.text = "Type: " + data.Type.ToString();
perkHealth.text = "Health: " + data.Health.ToString() + "HP";
perkUpgradeCost.text = "Upgrade Cost: " + data.UpgradeCost.ToString();
perkImage.sprite = data.Sprite;
}
public void UpgradeButtonPressed()
{
float money = FindObjectOfType<MapGenerator>().worldInfo.money;
if (money >= info.UpgradeCost && info.Level != info.MaxUpgradeLevel)
{
Debug.Log("We've got enough!");
money -= info.UpgradeCost;
info.DamagePerShot *= info.DamageMultiplier;
info.Health *= info.HealthMultiplier;
info.Level++;
info.UpgradeCost *= info.CostMultiplier;
info.FireRate *= info.FireRateMultiplier;
RefreshInfo();
}
else if (money < info.UpgradeCost)
Debug.Log("Get more money!");
else if (info.Level == info.MaxUpgradeLevel)
Debug.Log("Already max level!");
}
Setup is called here, in a different script:
void RefreshListItems()
{
ClearListItems();
for (var i = 0; i < perks.Count; i++)
{
if (perks[i].UnlockLevel <= FindObjectOfType<MapGenerator>().worldInfo.playerLevel)
{
GameObject perkObject = Instantiate(itemPrefab);
perkObject.transform.SetParent(scrollViewTransform);
PerkListItem perkItem = perkObject.GetComponent<PerkListItem>();
perkItem.Setup(perks[i]);
upgradeGOList.Add(perkObject);
}
}
}
Fixed - The onclick event was referencing the script on the prefab rather than the instantiated copies of that.
I'm trying to instantie several button using prefab.
But I've got a problem to Delegate variable.
for(int i = 0; i < _partnerList.partner.Count; i++)
{
GameObject _instance_partner_button = Instantiate(_prefab_partner_button);
_instance_partner_button.name = "_button_"+_partnerList.partner[i].partner_name;
_instance_partner_button.transform.SetParent(GameObject.Find("_UI_menu_partner").transform, false);
// Change Value of The Button ----------------------------------------------------------------
Text _instance_partner_button_text = _instance_partner_button.GetComponentInChildren<Text>();
_instance_partner_button_text.text = _partnerList.partner[i].partner_name;
Button _instance_partner_button_button = _instance_partner_button.GetComponent<Button>();
int _tempInt = i;
// Delegate to Another Script ---------------------------------------------------------------
_instance_partner_button_button.onClick.AddListener(() => _scripts_myScripts_ui.AnimationMenuPartner(_tempInt));
// -------------------------------------------------------------------------------------------
}
The function AnimationMenuPartner() just Debug.Log(_tempInt);
No matter which button I press the result is the same.
I'm maybe missing something, as I see in this link it must be working correctly Link
Thanks you for your help.
Edit :
The Another Script with the function AnimationMenuPartner
public void AnimationMenuPartner(int _tempInt)
{
Debug.Log(_tempInt));
}
The log output print : "4"
Which is the length of the list.
Basically I am trying to create an attachment window utilizing keeping everything in lists for easy use later. So, every time the form loads it goes through everything in the list and creates both labels and buttons for them. There is no errors until I click my button. If I click any of the X buttons, I get an argument out of bounds exception on the click += line. What's interesting is why its being called? The click isn't supposed to add another event handler to itself. Its also interesting that on click the indicie is one greater than the total count so how its even executing that line is beside me considering it should never iterate higher that its max count. Any help would be greatly appreciated.
ArrayList attachmentFiles;
ArrayList attachmentNames;
public Attachments(ArrayList attachments, ArrayList attachmentFileNames)
{
InitializeComponent();
attachmentFiles = attachments;
attachmentNames = attachmentFileNames;
}
private void Attachments_Load(object sender, EventArgs e)
{
ScrollBar vScrollBar1 = new VScrollBar();
ScrollBar hScrollBar1 = new HScrollBar();
vScrollBar1.Dock = DockStyle.Right;
hScrollBar1.Dock = DockStyle.Bottom;
vScrollBar1.Scroll += (sender2, e2) => { pnl_Attachments.VerticalScroll.Value = vScrollBar1.Value; };
hScrollBar1.Scroll += (sender3, e4) => { pnl_Attachments.HorizontalScroll.Value = hScrollBar1.Value; };
pnl_Attachments.Controls.Add(hScrollBar1);
pnl_Attachments.Controls.Add(vScrollBar1);
Label fileName;
for (int i = 0; i < attachmentNames.Count; i++)
{
fileName = new Label();
fileName.AutoSize = true;
fileName.Text = attachmentNames[i].ToString();
fileName.Top = (i + 1) * 22;
pnl_Attachments.Controls.Add(fileName);
Button btn_RemoveAttachment = new Button();
btn_RemoveAttachment.Text = "X";
btn_RemoveAttachment.Tag = i;
btn_RemoveAttachment.Click += new System.EventHandler((s, e3) => removeAttachment(s, e3, attachmentFiles[i].ToString(), attachmentNames[i].ToString()));
btn_RemoveAttachment.Top = (i + 1) * 22;
btn_RemoveAttachment.Left = fileName.Right + 22;
pnl_Attachments.Controls.Add(btn_RemoveAttachment);
}
}
private void removeAttachment(object sender, EventArgs e, string file, string fileName)
{
attachmentNames.Remove(fileName);
attachmentFiles.Remove(file);
pnl_Attachments.Controls.Clear();
this.Close();
}
In my test, attachmentFiles had a count of 3 and attachmentNames had a count of 3. On form load, there are no issues. But, on button click I get an exception because somehow its trying to add another click listener to a button with i = 3 (a.k.a a 4th element)
The problem is not with the event subscription, but with the event handler execution.
You are running into this problem because a closure is created for the event handler, but the value i is modified by the for loop. The last value of i will be 1 + attachmentNames.Count and this will be the value used by each invocation of the event handler.
For more detail as to why this happens you can check out the question and answer here: Access to Modified Closure.
To resolve the problem, you can assign i to another variable:
var currentAttachmentIndex = i;
btn_RemoveAttachment.Click += new System.EventHandler((s, e3) => {
removeAttachment(s,
e3,
attachmentFiles[currentAttachmentIndex].ToString(),
attachmentNames[currentAttachmentIndex].ToString())
});
Or you can use the value you already captured in the Tag property of the btn_RemoveAttachment control.
btn_RemoveAttachment.Click += new System.EventHandler((s, e3) => {
var senderButton = (Button)s;
var currentAttachmentIndex = (int)senderButton.Tag;
removeAttachment(s,
e3,
attachmentFiles[currentAttachmentIndex].ToString(),
attachmentNames[currentAttachmentIndex].ToString())
});
Keep in mind, though, if you are removing items from the List, the indexes will not be valid. Understanding how closures work, however, should help you solve that problem if it arises (it looks like you close the form anyway after the first removal).
Presumably, the attachmentFiles[i] is what is causing the out of bounds exception, perhaps attachmentFiles has fewer elements than attachmentNames?
Why not set a breakpoint on that line and check what is causing the out of bounds exception?
I get an argument out of bounds exception on the click += line. What's interesting is why its being called? The click isn't supposed to add another event handler to itself
It looks like the exception is not thrown at the event subscription (+=) but at the lambda function declared in that same line
Its also interesting that on click the indicie is one greater than the total count so how its even executing that line is beside me considering it should never iterate higher that its max count. Any help would be greatly appreciated
The value of i is fixed when you assign the lambda to the event. The indexes at the attachmentFiles change as you remove elements, but the indexes used by the lambda to access it don't. Let's try an example.
let's assume we have an array with 4 attchements (index:attachment))
[0:att0, 1:att1, 2:att2, 3:att3]
And 4 buttons that execute this lambdas
[removeAt(0), removeAt(1), removeAt(2), removeAt(3)]
We click the second button and it correctly removes the second attachment from array, now we have:
[0:att0, 1:att2, 2:att3]
[removeAt(0), removeAt(1), removeAt(2), removeAt(3)]
Now we click the fourth button. It tries to remove the attachment with index 3 and the out of bounds exception is thrown because that index doesn't exist anymore (and even if it existed, it might not point to the right attachment!)
Another approach would be to modify your 'removeAttachment' method, and use that as your event handler for all buttons.
An example of this would be:
for (int i = 0; i < attachmentNames.Count; i++)
{
var lbl_FileName = new Label
{
AutoSize = true,
Name = "Label" + i, // Give this a name so we can find it later
Text = attachmentNames[i],
Top = (i + 1) * 22
};
var btn_RemoveAttachment = new Button
{
Text = "X",
Tag = i,
Top = (i + 1) * 22,
Left = lbl_FileName.Right + 22
};
btn_RemoveAttachment.Click += removeAttachment;
pnl_Attachments.Controls.Add(lbl_FileName);
pnl_Attachments.Controls.Add(btn_RemoveAttachment);
}
Then you can modify your removeAttachment method to be an EventHandler, and to detect the button and associated label using the sender As Button and Button.Tag property:
private void removeAttachment(object sender, EventArgs e)
{
// Get associated Label and Button controls
var thisButton = sender as Button;
var index = Convert.ToInt32(thisButton.Tag);
var thisLabel = (Label) Controls.Find("NameLabel" + index, true).First();
// Remove the files
int itemIndex = attachmentNames.IndexOf(thisLabel.Text);
attachmentNames.RemoveAt(itemIndex);
attachmentFiles.RemoveAt(itemIndex);
// Disable controls and strikethrough the text
thisButton.Enabled = false;
thisLabel.Font = new Font(thisLabel.Font, FontStyle.Strikeout);
thisLabel.Enabled = false;
}
I have a question about the ProcessBar on C#,
How would I add the value of 1 to a label if the method used when passing an item within a list box was successful ?
I have a method like this
private static Form1 f1 = Application.OpenForms["Form1"] as Form1;
public static void GroupList1(processBar bar)
{
f1.listBox1.Items.Add("User1");
bar.Value = 100;
}
public static void GroupList2(processBar bar2)
{
f1.listBox1.Items.Add("User2");
bar.Value = 100;
} // Etc, etc - up to GroupList6
I would also like to have a label that tells me how many user's were successfully added (using the bar), I was thinking of adding a method like this :
if (bar.Value = 100)
{
f1.label1.Text = "" + 1;
}
Inside of my GroupList1/2 method, but the label always appears as the value 1 .
This method within the main form of my code loads a separate label :
for(int i = 0; int i < listBox1.Items.Count; i++)
{
label2.Text = i.ToString();
}
So, I would like label 1 to increase by 1 if the user has been loaded into my list box successfully, how would I do this ?
Obviously this isn't actually the code I'm using within my program, a method is used if the selected index changes (which is why I want to increase by 1, to ensure the user parsed the method successfully), but the question still remains as described, thanks.
I dont quite understand well what are you trying to achieve, but if you only look in increasing the value of such label then you can easily do this by
if (bar.Value = 100)
{
f1.label1.Text = ""+(int.Parse(f1.label1.Text)+1);
}
or even a better way to initialize the string if for some reason the Text of the label is not an integer
if (bar.Value == 100)
{
int value;
if(!int.TryParse(f1.label1.Text,out value))
{
f1.label1.Text = "1";
}
else
{
f1.label1.Text = ""+(value+1);
}
}
but the best way to do this is to keep track of the value in a separate variable and just update the content of the label.
It's a bad idea to store the actual count in the label's Text property, instead, create a variable:
private static int count;
Now, change your code to something like this:
if (bar.Value = 100)
{
// Add 1
count += 1;
// Update the UI
f1.label1.Text = count.ToString();
}