New Button for each line of a text file? - c#

I am trying to dynamically create a new button for each line of a text file.
My problem is that no matter how many lines the text file has, it only ever generates a single button.
The code:
System.IO.StreamReader file = new System.IO.StreamReader
(#"D:\SupportDash\Settings\Settings.txt");
string[] lines = System.IO.File.ReadAllLines(#"D:\SupportDash\Settings\Settings.txt");
foreach(String row in lines)
{
Button Buttona = new System.Windows.Forms.Button();
Buttona.Text = "Test";
Buttona.UseVisualStyleBackColor = true;
Buttona.Location = new System.Drawing.Point(85,28);
Buttona.Click += (s, e) =>
{
Form DynamicForm = new Form();
DynamicForm.Show();
};
groupBox2.Controls.Add(Button);
counter++;
}
file.Close();
}
I've also tried using a while and a do-while loop. -The same thing happens.
My text file is separated by a carriage return. (Its generated in-program using File.ApendAllText();)
Is it a problem being caused by my program only thinking there is one huge line?

You are putting all buttons at the same Location, so it may appear there is only one button, when in fact there is one button per line, they are just all on top of each other.
Try incrementing the Location's Top every time through the loop or use a panel control that supports wrapping.

you will need to position each new button at a new position for example
where your setting
Buttona.Location = new System.Drawing.Point(85,28);
call something like
var buttonHeight = 10;
Buttona.Location = new System.Drawing.Point(85,28 + (count * buttonHeight ));
you are actually creating multiple buttons but they are all on top of each other.

Related

Programmatically added LinkLabel not visible

I am encountering a strange phenomenon: I have a WinForms application with four GroupBoxes, all four initially empty. I use this to track new followers/unfollowers on Twitter, planning on expanding its use once this functions properly.
It does work properly for new followers. For these I have a GroupBox called grpFollow, to which I add LinkLabels with the ScreenNames of my new followers like this:
var folTop = new Point(grpFollow.Left + 5, grpFollow.Top + 5);
lblFollowers.Text = Properties.Settings.Default.FollowersNow.Count.ToString();
lblFriends.Text = Properties.Settings.Default.FriendsNow.Count.ToString();
var ctr = 1;
foreach (var fol in newFollowers)
{
var kvp = LookupUser(fol);
if (string.IsNullOrEmpty(kvp.Key)) continue;
var linklabel = new LinkLabel()
{
Text = kvp.Value,
Width = 200,
Height = 15,
Location = folTop,
Visible = true,
Name = $"follbl{ctr}"
};
ctr++;
linklabel.Links.Add(0, linklabel.Width-1, $"https://twitter.com/{kvp.Key}");
linklabel.Click += Linklabel_Click;
grpFollow.Controls.Add(linklabel);
folTop.Y += 25;
}
LookupUser is just a function that passes the user id to the Twitter API and returns the name & screen_name of that user. Works fine, no problem. LinkLabels added nicely, no problem there either.
The trouble is with the other group boxes, e.g. the one for new friends:
folTop = new Point(grpFriends.Left + 15, grpFriends.Top + 15);
ctr = 1;
foreach (var fol in newFriends)
{
var kvp = LookupUser(fol);
if (string.IsNullOrEmpty(kvp.Key)) continue;
var llabel = new LinkLabel()
{
Text = kvp.Value,
Width = 200,
Height = 15,
Location = folTop,
Visible = true,
Name = $"frdlbl{ctr}"
};
ctr++;
llabel.Links.Add(0, llabel.Width - 1, $"https://twitter.com/{kvp.Key}");
llabel.Click += Linklabel_Click;
grpFriends.Controls.Add(llabel);
folTop.Y += 25;
}
As you can see, the logic is identical (because I want to extract this part to a separate method to avoid repetition). The location is set relative to the grpFriends group box, everything else is the same. Yet, the LinkLabel does not show, i.e. the second group box remains (visually) empty!
I have set a breakpoint to check what might go wrong. I single stepped through: the correct screen name is being retrieved, the location is correct, the control is added - but nothing ever shows up.
P.S: This code is in the RunWorkerCompleted method of a background worker, no further code is executed after this point.
Any idea why the Label isn't displayed?
Edit: I'll be damned!
I just changed the location of the grpFriends LinkLabel to 10,10: it appears, juuust clipping the lower border of my friends' group.
Now here is where this gets weird for me:
As you can see, the group has a Y value of 351. Point (10,10) should not even be in the box. So, it seems that the location is the culprit and the original code created the label outside the form.
Replacing grpFriends.Top as Y value with grpFriends.Top - grpFriends.Height got me closer. The LinkLabel is farther down from the top than I'd like but that's not so bad.
Very strange.
Okay, thanks to #raBinn I figured it out. The mistake here was me assuming, the LinkLabels needed a location relative to the Form. However, when adding them to the Controls collection of a GroupBox, they automatically assume a location relative to the GroupBox, not the Form.
So, my code is now basically the same for all four group boxes and looks like this:
PopulateGroup(newFollowers, grpFollow);
PopulateGroup(unFollow, grpLost);
PopulateGroup(newFriends, grpFriends);
PopulateGroup(unFriend, grpDitched);
And:
private void PopulateGroup(List<string> collPeople, GroupBox groupBox)
{
var folTop = new Point(12, 25);
foreach (var fol in collPeople)
{
var kvp = LookupUser(fol);
if (string.IsNullOrEmpty(kvp.Key)) continue;
var linklabel = new LinkLabel()
{
Text = kvp.Value,
Width = 200,
Height = 15,
Location = folTop
};
ctr++;
linklabel.Links.Add(0, linklabel.Width - 1, $"https://twitter.com/{kvp.Key}");
linklabel.Click += Linklabel_Click;
groupBox.Controls.Add(linklabel);
folTop.Y += 25;
}
}
So it doesn't really matter whether the group box is on the left or right, top or bottom of the form...

How can I handle or remove the trailing space of a LinkLabel?

I'm trying to insert links into my RichTextBox. I do not mean setting DetectUrls to true, I want alternate text. What I have so far seems to be working mostly fine.. I'm using much of the code from this solution. But my issue is that there is some trailing whitespace in the LinkLabel that end up cutting off some of the text that follows it.
Here is what I have so far:
private void Form1_Load(object sender, EventArgs e)
{
//My text with a placeholder for the link: %link1%
//NOTE: I can see the leading '>' fine, but the '<' gets hidden by the link label, and it looks like a space between the link text and "Near..."
richTextBox1.Text = "This has a link here:>%link1%<Near the middle.";
LinkLabel link1 = new LinkLabel();
//link1.Margin = new Padding(0); //Doesn't help
//link1.Padding = new Padding(0); //Default is already 0
//What I want to see in my hyperlink
link1.Text = "My_Link_Text";
link1.Font = richTextBox1.Font;
link1.LinkColor = Color.DodgerBlue;
link1.LinkClicked += Link_LinkClicked;
LinkLabel.Link data = new LinkLabel.Link();
//For now, just test with google.com...
data.LinkData = #"http://google.com";
link1.Links.Add(data);
link1.AutoSize = true;
link1.Location = this.richTextBox1.GetPositionFromCharIndex(richTextBox1.Text.IndexOf("%link1%"));
richTextBox1.Controls.Add(link1);
//Replace the placeholder with the text I want to see so that the link gets placed over this text
richTextBox1.Text = richTextBox1.Text.Replace("%link1%", link1.Text);
//Attempt to manually shrink the link by a few pixels (doesn't work)
//NOTE: Turns out this cuts back on the link test, but leave the trailing space :(
//Size s = new Size(link1.Width, link1.Height); //Remember the autosized size (it did the "hard" work)
//link1.AutoSize = false; //Turn off autosize
//link1.Width = s.Width - 5;
//link1.Height = s.Height;
}
The LinkClicked event, just for the curious. Nothing special.
private void Link_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
System.Diagnostics.Process.Start(e.Link.LinkData.ToString());
}
Here is what I see, for reference (notice the missing '<'):
The reason for using a RichTextBox is that I also plan on adding formatting when I am finished (ability for text to be bold, colored, etc.). I'm basically 2 hours away from scrapping the RichTextBox and drawing everything manually onto a panel and handling click position...

add controls (Picturebox) in loop

What i have: Big PictureBox (lets call it Pic_Map) on the form. A class Ore.cs, A List<Ore> ores; and a database that pulls the data and places it into the ores list.
Functionality: So, The functionality of this is i have a TextBox/Combobox and a Button. When i press the Button, it will loop through the ores list and Dynamically add PictureBoxes ontop of the Pic_Map based on TexBox/ComboBox being equal to the data (in this case Ore_Name).
Problem: This all works fine, but the problem is that when i add the PictureBoxes Dynamically, it only seems to add the last value on the ores list (Red circles on Pic_Map). so, it ends up showing only 1 PictureBox instead of lets say 3, since i have 3 value Names that match with the TextBox/ComboBox.
Question: How to get it to work like when i write/choose "Flame Stone" it looks on all the data that has "Flame Stone" in its name and add it (Instead of it adding only the last value from the list).
Code:
private void PopulateComboBoxByName()
{
PictureBox ore_Area = new PictureBox();
db.GetOre(); //Getting data and putting it into "ores" list
foreach (Ore ore in db.ores)
{
if (CBOX_Filter.SelectedItem.ToString() == ore.Ore_Name)
{
int area_Width = Convert.ToInt32(ore.Area_Width);
int area_Height = Convert.ToInt32(ore.Area_Height);
int ore_Width = Convert.ToInt32(ore.Ore_Width);
int ore_Height = Convert.ToInt32(ore.Ore_Height) - area_Height / 2;
ore_Area.Name = "ore_Area";
ore_Area.ImageLocation = #"Data\Images\Circle.png";
ore_Area.SizeMode = PictureBoxSizeMode.StretchImage;
ore_Area.Size = new Size(Convert.ToInt32(area_Width), Convert.ToInt32(area_Height));
ore_Area.Location = new Point(Convert.ToInt32(ore_Width), Convert.ToInt32(ore_Height));
ore_Area.BackColor = Color.Transparent;
this.Controls.Add(ore_Area);
}
}
ore_Area.Parent = PIC_Map;
}
Images:
Data:
Map:
Thanks to LarsTech, it has been fixed.
Making the picturebox is moved inside the loop, this.controls.add is changed to PIC_Map.controls.add and Ore_Area.Parent = PIC_Map; is deleted.

Xml node foreach loop

I'm currently trying to read a xml file and add a control for every "Mods" entry.
<Modlist>
<Mods>
<Mod>Test1</Mod>
<Version>1.0</Version>
</Mods>
<Mods>
<Mod>Test2</Mod>
<Version>2.0</Version>
</Mods>
<Mods>
<Mod>Test3</Mod>
<Version>3.0</Version>
</Mods>
</Modlist>
Basically i want to add a control to a panel for every listed mod in the xml.
XDocument Mods = XDocument.Load(#"C:\dataset.xml");
foreach (var mod in Mods.Descendants("Mods"))
{
Button modbutton = new Button();
modbutton.Text = mod.Element("Mod").Value;
panel1.Controls.Add(modbutton);
}
Its working, but its only creating one button and seems to stop.
In my example it should create 3 buttons.
What do i have to change? Whats wrong with my code?
Your code to read xml is correct but you are putting each button one over the other. Set .Location property for every Button.
ur code working perfectly, but the problem is buttons are placed in same place. u need change the position.
Try this
XDocument Mods = XDocument.Load(#"C:\dataset.xml");
int I = 10;
foreach (var mod in Mods.Descendants("Mods"))
{
Button modbutton = new Button() { Top = 10 + I, Left = 10 };
modbutton.Text = mod.Element("Mod").Value;
panel1.Controls.Add(modbutton);
I += 50;
}

Adding buttons programmatically to a TabControl (TabPage)

I read this topic (Adding buttons to a TabControl Tab in C#) but I don't figure out why my code below add one button only to the tabpage.
I've obviously debugged that the foreach works properly.
foreach (string line in File.ReadAllLines(#"C:\quicklauncher.ini"))
{
TabPage page = new TabPage(foldername);
DirectoryInfo d = new DirectoryInfo(line);
foreach (FileInfo file in d.GetFiles("*.*"))
{
Button button = new Button();
button.Text = file.Name;
button.Click += new EventHandler(button_Click);
page.Controls.Add(button);
}
tabControl.TabPages.Add(page); //add our tab page to the tab control
}
Thanks,
Steve
You thought it added only 1 button for you but in fact it did not, it added all the buttons for you but those buttons had the same Location (which is (0,0) by default). That's why you did think there was only 1 button (because you saw only 1 last button on top of others).
You added buttons automatically to your tabpage, so you should have some rule to locate them, I'm not sure what that rule is but I suppose you want to line them up vertically (just an example), I'm going to correct your code to achieve such a thing, at least you will see it work, and in fact all the buttons are added normally:
//you need some variable to save the next Top for each new button:
//let's call it nextTop:
int nextTop = 0;
foreach (FileInfo file in d.GetFiles("*.*"))
{
Button button = new Button { Top = nextTop,
Text = file.Name };
button.Click += new EventHandler(button_Click);
page.Controls.Add(button);
nextTop += button.Height + 5; //it's up to you on the
//Height and vertical spacing
}
//...
You can also try using some layout control like FlowLayoutPanel and TableLayoutPanel to contain all the buttons, they can help arrange your buttons in some way you may want, just try it.

Categories

Resources