Span Two Columns When Dynamically Adding Controls - c#

I have an ASP.NET web application. This application renders out glossary type items, similar to the following:
This goes through all the letters in the alphabet for items. I am rendering this out and appending it directly to a Controls collection in a Server Control using the following:
List<char> alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray().ToList();
foreach (char c in alpha)
{
Label lblAlphaCharacter = new Label();
lblAlphaCharacter.Font.Size = 24;
lblAlphaCharacter.Font.Bold = true;
lblAlphaCharacter.Text = c.ToString(CultureInfo.InvariantCulture);
Controls.Add(lblAlphaCharacter);
Controls.Add(new LiteralControl("<p>"));
FilterOnAlphaCharacter(this, Page, c);
Controls.Add(new LiteralControl("<p>"));
}
private static void FilterOnAlphaCharacter(Control control, Page page, char character)
{
foreach (List<Things> item in items)
{
string title = item.Title;
string description = item.Definition;
HyperLink link = new HyperLink();
link.Text = title;
control.Controls.Add(link);
Label lblDescription = new Label();
lblDescription.Text = string.Format(" - {0}", description);
control.Controls.Add(lblDescription);
}
}
}
I am trying to, depending on the content, equally split this, so that it looks like this:
This can have different amounts of items. So in reality, there could be 25 entries under "A", and perhaps 1 under "Z". The above is just an example, it goes through all letters A-Z. The expected result would be based on the amount of content, it would equally split between two columns. I have to do this server-side (I was thinking using Table or HtmlTable and related objects).
Howe would you implement a solution for splitting the content equally in a Table or the likes (sort of indifferent on approach).

try this:
//it shows the number of line that inserting during the process
private int _inserteditemCount;
//its number of items in each column
private int _itemsCount;
//line height use for determine paragraph line height
private const string Lineheight = "30px";
protected void Page_Load(object sender, EventArgs e)
{
_inserteditemCount = 0;
var alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
//you can do this query in data access layer
var listCountcount = new Thingsclass().GetThings().Count;
//Count of rows on dictionary + number of leters
_itemsCount = (listCountcount + alpha.Count()) / 2;
var leftdiv = new HtmlGenericControl("div");
var rightdiv = new HtmlGenericControl("div");
//you can change this styles
leftdiv.Style.Add("display", "inline-block");
leftdiv.Style.Add("width", "50%");
leftdiv.Style.Add("float", "Left");
rightdiv.Style.Add("display", "inline-block");
rightdiv.Style.Add("float", "right");
rightdiv.Style.Add("width", "50%");
foreach (var c in alpha)
{
var lblAlphaCharacter = new Label();
lblAlphaCharacter.Font.Size = 24;
lblAlphaCharacter.Font.Bold = true;
lblAlphaCharacter.Text = c.ToString(CultureInfo.InvariantCulture);
var control = _inserteditemCount <= _itemsCount ? leftdiv : rightdiv;
var paragraph = new HtmlGenericControl("p");
paragraph.Style.Add("line-height", Lineheight);
paragraph.Controls.Add(lblAlphaCharacter);
control.Controls.Add(paragraph);
FilterOnAlphaCharacter(leftdiv, rightdiv, c.ToString());
_inserteditemCount++;
}
Panel1.Controls.Add(leftdiv);
Panel1.Controls.Add(rightdiv);
}
private void FilterOnAlphaCharacter(Control leftctr, Control rightctr, string character)
{
//you can do this query in data access layer
var items = new Thingsclass().GetThings().Where(c => c.chara.ToLower().Equals(character.ToLower()));
foreach (var item in items)
{
var paragraph = new HtmlGenericControl("p");
paragraph.Style.Add("line-height", Lineheight);
var control = _inserteditemCount <= _itemsCount ? leftctr : rightctr;
var title = item.Title;
var description = item.Description;
var link = new HyperLink { Text = title };
paragraph.Controls.Add(link);
var lblDescription = new Label { Text = string.Format(" - {0}", description) };
paragraph.Controls.Add(lblDescription);
_inserteditemCount++;
control.Controls.Add(paragraph);
}
}

Related

TextBox is not creating newline when reading text file C#

I have this program that supposed to reads multiple text files on the same folder, in that folder there's 2 text files which are supposed to be read, ok now I have to generate a new TextBox based on the total numbers of text files in that folder.
Main Goal
Load the contents of those files in each textbox
File1.txt contents will be loaded into TextBox1.
File2.txt contents will be loaded into TextBox2.
Content of File1.txt:
Title 1
ABCDEFG
Content of File2.txt:
Title 2
1234567890
The problem
Loading the contents of those files into each TextBoxes works fine, but the problem is that the newline isn't created on the TextBoxes.
Instead I got this on each textboxes:
TextBox 1:
Title 1ABCDEFG
TextBox 2:
Title 21234567890
Do the necessary stuff as soon the program loads:
private void Form1_Load(object sender, EventArgs e) {
flowLayoutPanel1.AutoScroll = true;
var dirs_notes = #"C:\MAIN_LOC\DATA_LOC\";
var count_notes = Directory.GetFiles(dirs_notes,"*.*",SearchOption.AllDirectories).Count();
string setup_path = #"C:\MAIN_LOC\DATA_LOC\";
if(Directory.Exists(setup_path)) {
string[] get_notes = Directory.GetFiles(dirs_notes, "*.txt", SearchOption.AllDirectories);
string[] get_texts = get_notes.Select(x => File.ReadAllText(x)).ToArray();
for(int i=0; i<count_notes; i++) {
int top = 25;
int h_p = 170;
var load_note = new Guna2TextBox() {
Text = "\n" + get_texts[i],
Name = "Note" + i,
Multiline = true,
AcceptsTab = true,
AcceptsReturn = true,
WordWrap = false,
Width = 230,
Height = 145,
BorderRadius = 8,
Font = new Font("Bahnschrift", 13),
ForeColor = Color.White,
FillColor = ColorTranslator.FromHtml("#1E1E1E"),
BorderColor = ColorTranslator.FromHtml("#2C2C2C"),
Location = new Point(450, top)
};
top += h_p;
flowLayoutPanel1.Controls.Add(load_note);
}
} else {
MessageBox.Show("There's problem with loading notes..", "Flow Notes System");
}
}
A fix could be using the Lines property instead of the Text property.
var dirs_notes = #"C:\MAIN_LOC\DATA_LOC\";
// Be sure to count only txt files here...
var count_notes = Directory.GetFiles(dirs_notes,"*.txt",SearchOption.AllDirectories).Count();
string setup_path = #"C:\MAIN_LOC\DATA_LOC\";
if(Directory.Exists(setup_path)) {
string[] get_notes = Directory.GetFiles(dirs_notes, "*.txt", SearchOption.AllDirectories);
var get_texts = get_notes.Select(x => File.ReadLines(x));
for(int i=0; i<count_notes; i++) {
....
var load_note = new Guna2TextBox() {
Lines = "\n" + get_texts[i].ToArray(),
But a better approach is to use this instead:
// No counting here (counting means load all
// files names in a memory array and the get its length
var files = Directory.EnumerateFiles(dirs_notes,"*.txt",SearchOption.AllDirectories)
int i = 1;
// Enumerate files one by one without loading all names in memory
foreach(string file in files) {
int top = 25;
int h_p = 170;
var load_note = new Guna2TextBox() {
// Set the textbox with the current file lines content
// again one by one without loading all texts in memory
Lines = File.ReadLines(file).ToArray(),
Name = "Note" + i,
...
}
i++;
.....
}

Replacing labels c# wpf

created a sports table that shows different statistics sorted by one property. When sorting for a different property I created completely new labels that just sit on top of the old ones instead of replacing them.
This is ran when a button is pressed:
private void Points_Order(object sender, RoutedEventArgs e)
{
List<Team> leagueTeams = new List<Team>();
using (StreamReader sr = new StreamReader("TXT1.txt"))
{
using (JsonReader jr = new JsonTextReader(sr))
{
JsonSerializer js = new JsonSerializer();
leagueTeams = js.Deserialize<List<Team>>(jr);
}
}
List<Team> sortedList = leagueTeams.OrderByDescending(o => o.points).ToList(); //orders the keagueTeams list by points and stores in a new list using linq
List<Label> TeamLabels = new List<Label>(); //makes list of labels that show the teams
List<string> Names = new List<string>(); //Creates a list for the names
List<Label> gamesPlayedLabels = new List<Label>();
List<int> GamesPlayed = new List<int>();
foreach (var properties in sortedList)
{
Names.Add(properties.name);//adds the name of each object into the Names list
GamesPlayed.Add(properties.gamesPlayed);
}
for (int i = 0; i < 20; i++)
{
string nameLab = Names[i];
TeamLabels.Add(new Label { Height = 100, Width = 100, Content = nameLab }); //sets position of the name labels
Canvas.SetLeft(TeamLabels[i], 0);
Canvas.SetTop(TeamLabels[i], (i * 19) + 19);
canvas1.Children.Add(TeamLabels[i]);
string played = Convert.ToString(GamesPlayed[i]);
gamesPlayedLabels.Add(new Label { Height = 100, Width = 100, Content = played });
Canvas.SetLeft(gamesPlayedLabels[i], 112);
Canvas.SetTop(gamesPlayedLabels[i], (i * 19) + 19);
canvas1.Children.Add(gamesPlayedLabels[i]);
}
}
When a second button is pressed the exact same code is ran but apart from
List<Team> sortedList = leagueTeams.OrderByDescending(o => o.points).ToList()
it is
List<Team> sortedList = leagueTeams.OrderBy(o => o.name).ToList();
so the question is can you replace existing labels so the table can be sorted?

using Aspose Words to replace page numbers with barcodes

this may be a silly question but I cannot work out an answer to it and after a day I am turning to the community at large for help...
I am using Aspose for Word (C# or .Net) and I am trying to replace the generated page numbering for barcode images of my own creation. I can use fonts to do it currently but I have found they are less reliable with my barcode reader and thus need to be able to read the value from the page numbering and replace it with an image of my own creation.
So really I need to find the numbering container, read the value in it and replace it. Once I have that creating the barcode and inserting it is easy.
Can anyone help?
The current method (sorry its messy but i keep trying new things):
internal static void SetFooters(ref Document doc)
{
doc.FirstSection.HeadersFooters.LinkToPrevious(false);
var builder = new DocumentBuilder(doc);
builder.MoveToDocumentStart();
Section currentSection = builder.CurrentSection;
PageSetup pageSetup = currentSection.PageSetup;
int totalPages = doc.PageCount;
int j = 1;
foreach (Section sect in doc.Sections)
{
//Loop through all headers/footers
foreach (HeaderFooter hf in sect.HeadersFooters)
{
if (
hf.HeaderFooterType == HeaderFooterType.FooterPrimary || hf.HeaderFooterType == HeaderFooterType.FooterEven || hf.HeaderFooterType == HeaderFooterType.FooterFirst)
{
builder.MoveToHeaderFooter(hf.HeaderFooterType);
Field page = builder.InsertField("PAGE");
builder.Document.UpdatePageLayout();
try
{
page.Update();
}
catch { }
int pageNumber = j;
if (int.TryParse(page.Result, out pageNumber))
{ j++; }
// Remove PAGE field.
page.Remove();
builder.Write(string.Format("{0}/{1}", pageNumber, totalPages));
}
}
}
}
HeaderFooter is a section-level node and can only be a child of Section. The page field inside the header/footer returns the latest updated value and it will be same value for all pages of a section.
In your case, I suggest you to insert text-box at the top/bottom of each page and inset the desired contents in it. Following code example inserts the text-box on each page of document and insert page field and some text in it. Hope this helps you.
public static void InsertTextBoxAtEachPage()
{
string filePathIn = MyDir + #"input.docx";
string filePathOut = MyDir + #"output.docx";
Document doc = new Document(filePathIn);
DocumentBuilder builder = new DocumentBuilder(doc);
LayoutCollector collector = new LayoutCollector(doc);
int pageIndex = 1;
foreach (Section section in doc.Sections)
{
NodeCollection paragraphs = section.Body.GetChildNodes(NodeType.Paragraph, true);
foreach (Paragraph para in paragraphs)
{
if (collector.GetStartPageIndex(para) == pageIndex)
{
builder.MoveToParagraph(paragraphs.IndexOf(para), 0);
builder.StartBookmark("BM_Page" + pageIndex);
builder.EndBookmark("BM_Page" + pageIndex);
pageIndex++;
}
}
}
collector = new LayoutCollector(doc);
LayoutEnumerator layoutEnumerator = new LayoutEnumerator(doc);
const int PageRelativeY = 0;
const int PageRelativeX = 0;
foreach (Bookmark bookmark in doc.Range.Bookmarks)
{
if (bookmark.Name.StartsWith("BM_"))
{
Paragraph para = (Paragraph)bookmark.BookmarkStart.ParentNode;
Shape textbox = new Shape(doc, Aspose.Words.Drawing.ShapeType.TextBox);
textbox.Top = PageRelativeY;
textbox.Left = PageRelativeX;
int currentPageNumber = collector.GetStartPageIndex(para);
string barcodeString = string.Format("page {0} of {1}", currentPageNumber, doc.PageCount);
string barcodeEncodedString = "some barcode string";
Paragraph paragraph = new Paragraph(doc);
ParagraphFormat paragraphFormat = paragraph.ParagraphFormat;
paragraphFormat.Alignment = ParagraphAlignment.Center;
Aspose.Words.Style paragraphStyle = paragraphFormat.Style;
Aspose.Words.Font font = paragraphStyle.Font;
font.Name = "Tahoma";
font.Size = 12;
paragraph.AppendChild(new Run(doc, barcodeEncodedString));
textbox.AppendChild(paragraph);
paragraph = new Paragraph(doc);
paragraphFormat = paragraph.ParagraphFormat;
paragraphFormat.Alignment = ParagraphAlignment.Center;
paragraphStyle = paragraphFormat.Style;
font = paragraphStyle.Font;
font.Name = "Arial";
font.Size = 10;
paragraph.AppendChild(new Run(doc, barcodeString));
textbox.AppendChild(paragraph);
//Set the width height according to your requirements
textbox.Width = doc.FirstSection.PageSetup.PageWidth;
textbox.Height = 50;
textbox.BehindText = false;
para.AppendChild(textbox);
textbox.RelativeHorizontalPosition = Aspose.Words.Drawing.RelativeHorizontalPosition.Page;
textbox.RelativeVerticalPosition = Aspose.Words.Drawing.RelativeVerticalPosition.Page;
bool isInCell = bookmark.BookmarkStart.GetAncestor(NodeType.Cell) != null;
if (isInCell)
{
var renderObject = collector.GetEntity(bookmark.BookmarkStart);
layoutEnumerator.Current = renderObject;
layoutEnumerator.MoveParent(LayoutEntityType.Cell);
RectangleF location = layoutEnumerator.Rectangle;
textbox.Top = PageRelativeY - location.Y;
textbox.Left = PageRelativeX - location.X;
}
}
}
doc.Save(filePathOut, SaveFormat.Docx);
}
I work with Aspose as Developer evangelist.

Systematically remove first line

I am trying to remove the first line of a paragraph when the total lines exceed a predetermined number of entries. This is for a kind of chat window and I do not want too many lines displayed at one time.
private Paragraph paragraph = new Paragraph();
public void WriteMessage(string output)
{
string outputFormat = string.Format("{0}", output);
string[] parts = output.Split(new char[]{':'}, 2);
string user = parts[0];
string[] username = parts[0].Split('!');
paragraph.Inlines.Add(new Run(username[0].Trim() + ": "){Foreground = UserColor});
paragraph.Inlines.Add(new Run(parts[1]) { Foreground = MessageColor});
paragraph.Inlines.Add(new LineBreak());
if (paragraph.Inlines.Count >= 50) {
//???
//The count does not actually count lines the way I would expect.
}
}
Not sure of the easiest way to do this, everything I have tried thus far has not worked.
Suggest you use List verus array. It gives you some functionality you need.
public List<string> TrimParagraph(List<string> paragraph)
{
int count = paragraph.Count;
if (count > 50)
paragraph = paragraph.Skip(count - 50).ToList();
return paragraph;
}
Edit... Use something like this when constructing your paragraph object.
Solved it by creating a FlowDocument and adding the paragraph to the block. Then each entry is it's own block and it retains the original formatting.
private Paragraph paragraph = new Paragraph();
_rtbDocument = new FlowDocument(paragraph);
public void WriteMessage(string output)
{
string outputFormat = string.Format("{0}", output);
string[] parts = output.Split(new char[]{':'}, 2);
string user = parts[0];
string[] username = parts[0].Split('!');
Paragraph newline = new Paragraph();
newline.LineHeight = 2;
newline.Inlines.Add(new Run(username[0].Trim() + ": ") { Foreground = UserColor });
newline.Inlines.Add(new Run(parts[1]) { Foreground = MessageColor });
_rtbDocument.Blocks.Add(newline);
if (_rtbDocument.Blocks.Count > 10)
{
_rtbDocument.Blocks.Remove(_rtbDocument.Blocks.FirstBlock);
}
}

How to assign dynamically created objects to a string?

I have a form with this code assigned to a button:
TextBox[] tbxCantServ = new TextBox[1];
int i;
for (i = 0; i < tbxCantServ.Length; i++)
{
tbxCantServ[i] = new TextBox();
}
foreach (TextBox tbxActualCant in tbxCantServ)
{
tbxActualCant.Location = new Point(iHorizontal, iVertical);
tbxActualCant.Visible = true;
tbxActualCant.Width = 44;
tbxActualCant.MaxLength = 4;
this.Controls.Add(tbxActualCant);
iVertical = iVertical + 35;
}
And this code creates textboxes dynamically, one for every "button click", so I can have an "add" button to call it and the user can write a list of things that is not limited.
The question is: How can I assign these "textboxes.Text" to a string? They haven't got a name :S
something like:
string sAllBoxes = tbx1.Text + tbx2.Text + "..." + tbxN.Text;
Thanks!!
If your tbxCantServ is defined as local to a method, then you have to assign a Name to your TextBoxes like:
int counter = 0;
foreach (TextBox tbxActualCant in tbxCantServ)
{
tbxActualCant.Location = new Point(iHorizontal, iVertical);
tbxActualCant.Name = "tbx" + counter++;
tbxActualCant.Visible = true;
tbxActualCant.Width = 44;
tbxActualCant.MaxLength = 4;
this.Controls.Add(tbxActualCant);
iVertical = iVertical + 35;
}
And later in some other method if you want to get the joined text then you can do:
string sAllBoxes = string.Join(",", this.Controls.OfType<TextBox>()
.Where(r => r.Name.StartsWith("tbx"))
.Select(r => r.Text));
But if you have tbxCantServ defined at class level then you can do:
string sAllBoxes = string.Join(",", tbxCantServ
.Where(r=> r != null)
.Select(r => r.Text));
In string.Join, you can replace , with an empty string or any string depending on your requirement.
You can do it in the same way you created them.
Try this:
string sAllBoxes="";
foreach (TextBox tbxActualCant in tbxCantServ)
{
sAllBoxes+=tbxActualCant.Text;
}
OR
Using a StringBuilder:
StringBuilder textBuilder = new StringBuilder();
foreach (TextBox tbxActualCant in tbxCantServ)
{
textBuilder.Append(tbxActualCant.Text);
}
string allText = textBuilder.ToString();
If you have access to your textbox array, you can easily do this:
string sAllBoxes = string.Join(" ", tbxCantServ.Select(x => x.Text));
If you don't then use Control collection of your Form, and give name to your textboxes so you can access them using this.Controls[txtBoxName].
If you just want to concatanate your texts without a separator, you can also use string.Concat method:
string sAllBoxes = string.Concat(tbxCantServ.Select(x => x.Text));

Categories