Display multiple records in c# - c#

GloryDays.Add(new Songs("Shout Out to My Ex", 200));
GloryDays.Add(new Songs("Touch", 161));
GloryDays.Add(new Songs("Power", 177));
GloryDays.Add(new Songs("Your Love", 210));
GloryDays.Add(new Songs("Nobody Like You", 180));
var result = GloryDays.Sum(S => S.TrackLength);
trackLengthtextBox.Text = result.ToString();
List<Songs> GloryDays = new List<Songs>();
There is more than one in class called songs because this is the class where name of the track and its length will get stored.
I can view the info in the textbox for once record only and I would like to find a method which allows me to cycle through each songs list.
public void DisplayAlbum(int thisAlbum, int thisSong )
{
if (Albums[thisAlbum] != null)
{
albumIDtextBox.Text = Albums[thisAlbum].AlbumID.ToString();
albumNametextBox.Text = Albums[thisAlbum].AlbumName.ToString();
releaseDatetextBox.Text = Albums[thisAlbum].ReleaseDate;
albumLabeltextBox.Text = Albums[thisAlbum].Label.ToString();
trackListbox.DataSource = Albums[thisAlbum].Songs.ToList();
trackLengthtextBox.Text = GloryDays.Sum(S => S.Tracklength).ToString();
}

You cannot display on the same textbox all the song items, inorder to display you need to have different text boxes, anyway you can use for loop and display in a format you want,
sample,
foreach (var song in GloryDays) {
MessageBox.Show("song is " + song.TrackName + "length is" + song.TrackLength);
}

Related

Create new model array in List<T> containing values in every four indexes

I need to add a new array containing model values to a list that uses values present in groupings of four indexes.
I am using the code below to retrieve the values from the corresponding database table:
public List<Log> ViewItFilterUseCount()
{
var ndtms2Utils = new NDTMS2UtilsEntities();
var valueQuery = (from log in ndtms2Utils.Logs
where log.Message.Contains("ViewIt - View Data")
select log);
List<Log> logList = new List<Log>();
foreach (var value in valueQuery)
{
Log model = new Log();
model.Id = value.Id;
model.Date = value.Date;
model.Thread = value.Thread;
model.Level = value.Level;
model.Logger = value.Logger;
model.Message = value.Message;
model.Exception = value.Exception;
logList.Add(model);
}
return logList;
}
I need to extract values from the Message variable that appear after a : symbol and use them to create a new value for the Message field in the following format: ViewIt - View Data - the user has selected: messageValue1, messageValue2, messageValue3, messageValue4.
The value for the remaining variables in the model can be filled using those present in the the last index of the group of 4.
The data when in table format looks like this:
The Message added using the first four rows as an example would read:
ViewIt - View Data - the user has selected: Clients in treatment, Opiate, East of England, Essex.
as i understood you try to bind parsed string into model object.
this example you can run in Linqpad (i hope it will help)
void Main()
{
List<string> l = new List<string>()
{
"ViewIt - View Data - selected Key is: client1",
"ViewIt - View Data - selected Substance is: vodka",
"ViewIt - View Data - selected Region is: Russia",
"ViewIt - View Data - selected Area is: Moscow",
"ViewIt - View Data - selected Key is: client2",
"ViewIt - View Data - selected Substance is: Essex",
"ViewIt - View Data - selected Region is: England",
"ViewIt - View Data - selected Area is: Essex",
"ViewIt - View Data - selected Key is: client3",
"ViewIt - View Data - selected Substance is: IceTea",
"ViewIt - View Data - selected Region is: US",
"ViewIt - View Data - selected Area is: New York"
};
List<DATA> datalist = new List<UserQuery.DATA>();
l.Where(w=> w.Contains("View Data")).Select((v, i) => new { Index = i, Value = v })
.GroupBy(x => x.Index / 4)
.ToList().ForEach(r => {
datalist.Add(parseStrings(r.Select(v=>v.Value).ToList()));
});
Console.Write(datalist);
}
public DATA parseStrings(List<string> list){
DATA d = new DATA();
list.ForEach(f => {
var row = f.Substring(f.IndexOf("selected") + 9)
.Split(':');
switch (row[0].TrimEnd(" is".ToCharArray()).ToLower())
{
case "key":
d.Key = row[1].ToString().TrimStart(' ');
break;
case "substance":
d.Substance = row[1].ToString().TrimStart(' ');
break;
case "region":
d.Region = row[1].ToString().TrimStart(' ');
break;
case "area":
d.Area = row[1].ToString().TrimStart(' ');
break;
default:
break;
}
});
return d;
}
public class DATA{
public string Key {get;set;}
public string Substance {get;set;}
public string Region {get;set;}
public string Area {get;set;}
public DATA(){}
}
Managed to get it working by converting the output from the database to an Array and then using Rhaokiels Array code to perform the processing as shown below:
public List<Log> ViewItFilterUseCount()
{
var ndtms2Utils = new NDTMS2UtilsEntities();
var logQuery = (from logs in ndtms2Utils.Logs
where logs.Message.Contains("ViewIt - View Data")
select logs).ToArray();
int index = 0;
return (from log in logQuery
where log.Message.StartsWith("ViewIt - View Data")
group log by (index++ / 4) into grp
let log = grp.Last()
select new Log
{
Id = log.Id,
Date = log.Date,
Thread = log.Thread,
Level = log.Level,
Logger = log.Logger,
Message = "ViewIt - View Data - the user has selected: " + string.Join(", ", grp.Select((l) => l.Message.Substring(l.Message.IndexOf(": ") + 2))),
Exception = log.Exception
}).ToList();
}
This will group the log entries purely 4 at a time and give a combined message as output:
public List<Log> ViewItFilterUseCount()
{
var ndtms2Utils = new NDTMS2UtilsEntities();
// Query LINQ-to-Entities database for all matching rows
var valueQuery = ndtms2Utils.Logs.Where((o) => o.Message.StartsWith("ViewIt - View Data")).ToList();
// Then process client-side
int index = 0;
return (from log in valueQuery
group log by (index++ / 4) into grp
let log = grp.Last()
select new Log {
Id = log.Id,
Date = log.Date,
Thread = log.Thread,
Level = log.Level,
Logger = log.Logger,
Message = "ViewIt - View Data - the user has selected: " + string.Join(", ", grp.Select((l) => l.Message.Substring(l.Message.IndexOf(": ") + 2))),
Exception = log.Exception
}).ToList();
}
This can fail if the order of incoming log entries gets changed slightly, or an entry is missing will cause remaining entries to shift.

c# creating multiple lists within for statement

Is there a way I can create multiple lists under a "for" statement, with an incrimental naming system (eg monster1, monster2, monster3). I've flagged it up under this is where I want an incrimental name within the code.
The number of lists needed to be generated is defined earlier on and I'm having no issues with that, but I'm getting "error CS0128: A local variable named `...' is already defined in this scope" if I attempt to assign the list name based on a variable with an inbuilt counter to incriment the list names (monsterList in this case).
Is there another way I can do this, so that no matter how many lists I need to be generated, it will create them and name them following this set pattern?
The below code is what I'm looking to have iterate a nuber of times (I'm new, so it's probably horribly inefficient, I'm just trying to get it doing what I want for now!):
for (int monstCounter = 2; monstCounter < totalTimes; monstCounter++)
{
Console.WriteLine();
string monsterLists = "Monster " + monstCounter;
string monsterList = "monsters"+monstCounter;
Console.WriteLine(monsterLists);
p = 0;
foreach (Monster aMonster in monsters)
{
if (monsters[p].MonsterName == monsterLists)
y = p;
p++;
}
y = monsters[y].MonsterPopu;
//Create a list of individuals.
List<MonsterStatistics> **This is where I want an incrimental name** = new List<MonsterStatistics>();
totalTimes1 = y;
counter1 = 1;
for (int b=0; b < totalTimes1; b++)
{
// Add monsters to the list.
monsterList.Add(new MonsterStatistics() {oldAge = rndNum.Next(1,100), name = "Name"+counter1, coupled = false, genderGen = rndNum.Next(0,2)});
counter1++;
}
foreach (MonsterStatistics aMonster in monsterList){
if(aMonster.genderGen == 0)
aMonster.gender = "Male";
else if (aMonster.genderGen == 1)
aMonster.gender = "Female";
else
aMonster.gender = "Genderless";
aMonster.age = rndNum.Next(0,aMonster.oldAge);
Console.WriteLine(aMonster.name + " Age: " + aMonster.age + "/" + aMonster.oldAge + " " + aMonster.gender);
}
}
You can't create variables from a string, its not how variables work in C#.
What you cand o is use a Dictionary and assign for each monsters list a unique key (string), something like:
Dictionary<string, List<MonsterStatistics>> monstersStatistics = new Dictionary<string, List<MonsterStatistics>>();
// Add a monster (here you can name monster with an incrementing variable)
monstersStatistics.Add("monster1", new List<MonsterStatistics>());
// Then fill the monster's statistics
monstersStatistics["monster1"].Add(new MonsterStatistics() { oldAge = rndNum.Next(1, 100), name = "Name" + counter1, coupled = false, genderGen = rndNum.Next(0, 2) });

C# Search Textfile after multiple Datas and fill them into a Datagrid View

I get the datas from an textfile. The File itself is already inserted by ReadAllLines and converted into a string - this works fine for me and I checked the content with a MessageBox.
The Textfile looks like this (This is just 1 line from about thousand):
3016XY1234567891111111ABCDEFGHIJKabcdef+0000001029916XY1111111123456789ABCDEFGHIJKabcdef+00000003801
Now these are 2 records and I need 2 datas from every record.
The "XY Number" - these are the first 16 digits AFTER "16XY" (16XY is always the same value)
Value from the example: XY1234567891111111
The "Price" - that is the 11 digits value after the plus. The last 2 digits specify the amount of Cent.
Value from the example: 102,99$
I Need both of this datas to be in the same row in my Datagrid View and also for all other Datas in this textfile.
All I can imagine is to write a code, which searchs the string after "16XY" and counts the next 16 digits - the same with the Price which searchs for a "plus" and counts the next 11 digits. Just in this case I would need to ignore the first line of the file because there are about 10x"+".
I tried several possibilities to search and count for that values but without any success right now. Im also not sure how to get the datas into the specific Datagrid View.
This is all I have to show at the moment:
List<List<string>> groups = new List<List<string>>();
List<string> current = null;
foreach (var line in File.ReadAllLines(path))
{
if (line.Contains("") && current == null)
current = new List<string>();
else if (line.Contains("") && current != null)
{
groups.Add(current);
current = null;
}
if (current != null)
current.Add(line);
}
//array
string output = string.Join(Environment.NewLine, current.ToArray());
//string
string final = string.Join("", output.ToCharArray());
MessageBox.Show(output);
Thanks in advance!
Create a class or struct to hold data
public class Data
{
String XYValue { set; get; }
Decimal Price { set; get; }
}
Then the reading logic (You might need to add some more checks):
string decimalSeperator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
List<Data> results = new List<Data>();
foreach(string line in File.ReadAllLines(path).Skip(1))
{
if (line == null)
continue;
int indexOfNextXY = 0;
while (true)
{
int indexOfXY = line.IndexOf("16XY", indexOfNextXY) + "16XY".Length;
int indexOfPlus = line.IndexOf("+", indexOfXY + 16) + "+".Length;
indexOfNextXY = line.IndexOf("16XY", indexOfPlus);
string xyValue = line.Substring(indexOfXY - 2, 18); // -2 to get the XY part
string price = indexOfNextXY < 0 ? line.Substring(indexOfPlus) : line.Substring(indexOfPlus, indexOfNextXY - indexOfPlus);
string intPart = price.Substring(0, price.Length - 2);
string decimalPart = price.Substring(price.Length - 2);
price = intPart + decimalSeperator + decimalPart;
results.Add(new Data (){ XYValue = xyValue, Price = Convert.ToDecimal(price) });
if (indexOfNextXY < 0)
break;
}
}
var regex = new Regex(#"\+(\d+)(\d{2})16(XY\d{16})");
var q =
from e in File.ReadLines("123.txt")
let find = regex.Match(e)
where find.Success
select new
{
price = double.Parse(find.Groups[1].Value) + (double.Parse(find.Groups[2].Value) / 100),
value = find.Groups[3]
};
dataGridView1.DataSource = q.ToList();
If you need the whole text file as string, you can manipulate it with .Split method.
The action will look something like this:
var values = final.Split(new string[] { "16XY" }, StringSplitOptions.RemoveEmptyEntries).ToList();
List <YourModel> models = new List<YourModel>();
foreach (var item in values)
{
if (item.IndexOf('+') > 0)
{
var itemSplit = item.Split('+');
if (itemSplit[0].Length > 15 &&
itemSplit[1].Length > 10)
{
models.Add(new YourModel(itemSplit[0].Substring(0, 16), itemSplit[1].Substring(0, 11)));
}
}
}
And you will need some model
public class YourModel
{
public YourModel(string xy, string price)
{
float forTest = 0;
XYNUMBER = xy;
string addForParse = string.Format("{0}.{1}", price.Substring(0, price.Length - 2), price.Substring(price.Length - 2, 2));
if (float.TryParse(addForParse, out forTest))
{
Price = forTest;
}
}
public string XYNUMBER { get; set; }
public float Price { get; set; }
}
After that you can bind it to your gridview.
Given that the "data pairs" are variable each line (and can get truncated to the next line), it is best to use File.ReadAllText() instead. This will give you a single string to work on, eliminating the truncation issue.
var data = File.ReadAllText(path);
Define a model to contain your data:
public class Item {
public string XYNumber { get; set; }
public double Price { get; set; }
}
You can then use regular expressions to find matches and store them in a list:
var list = List<Item>();
var regex = new Regex(#"(XY\d{16})\w+\+(\d{11})");
var match = regex.Match(data);
while (match.Success) {
var ps = match.Group[1].Captures[0].Value.Insert(9, ".");
list.Add(new Item {
XYNumber = match.Group[0].Captures[0].Value,
Price = Convert.ToDouble(ps)
});
match = match.NextMatch();
}
The list can also be used as a data source to a grid view:
gridView.DataSource = list;
Consider employing the Split method. From the example data, I notice there is "16XY" between each value. So something like this:
var data = "3016XY1234567891111111ABCDEFGHIJKabcdef+0000001029916XY1111111123456789ABCDEFGHIJKabcdef+00000003801";
var records = data.Split(new string[] { "16XY" }, StringSplitOptions.RemoveEmptyEntries);
Given the example data this will return the following array:
[0]: "30"
[1]: "1234567891111111ABCDEFGHIJKabcdef+00000010299"
[2]: "1111111123456789ABCDEFGHIJKabcdef+00000003801"
Now it will be easier to count characters in each string and give them meaning in your code.
So we know valuable data is separated by +. Lets split it further and fill a Dictionary<string, double>.
var parsed = new Dictionary<string, double>(records.Length - 1);
foreach (var pairX in records.Skip(1))
{
var fields = pairX.Split('+');
var cents = double.Parse(fields[1]);
parsed.Add(fields[0], cents / 100);
}
// Now you bind to the GridView
gv.DataSource = parsed;
And your 'GridView` declaration should look like this:
<asp:GridView ID="gv" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="Key" HeaderText="ID" />
<asp:BoundField DataField="Value" HeaderText="Price" />
</Columns>
</asp:GridView>

Enumerable.Zip more than 2 collections?

var productNameTags = document.DocumentNode.SelectNodes(textBox3.Text);
var priceTags = document.DocumentNode.SelectNodes(textBox2.Text);
var codeNameAndPrice = productNameTags.Zip(priceTags, (n, w) => new { productNameTags = n, priceTags = w });
int counter = 1;
if (codeNameAndPrice != null)
{
foreach (var nw in codeNameAndPrice)
{
label1.Visible = true;
label1.Text += counter + ". " + nw.productNameTags.InnerHtml + " - " + nw.priceTags.InnerHtml + "\n";
}
}
I have this code which looks at html tags and prints out a product name and a price from a website and prints out like this using .Zip:
Baseball - £5.00
Football - £10.00
Toy Car - £15.00
Is there a simple way of adding three or more variables to zip together using a different method?
e.g.
Baseball - £5.00 - 1123
Football - £10.00 - 1124
Toy Car - £15.00 - 1125
Thanks in advance!
I don't think you can do it easily with .Zip (bar multiple levels of zip?), but you could do it dynamically:
var names = new[] { "Baseball", "Football", "Toy Car" };
var prices = new[] { 5.0M, 10.0M, 15.0M };
var ids = new[] { 1123, 1124, 1125 };
var products = names
.Select((name, index) => new { Name = name, Price = prices[index], Id = ids[index] });
No.
You can chain Zip calls, or you can write (or find) extension/helper method that would walk multiple sources in parallel similar to Zip to provide functionality you are looking for.
In your particular case consider iterating over some parent nodes and selecting individual child nodes relative to parent (assuming all nodes for particular item are children of single "parent" node).

Fill PDFP Table Cell with Dots

I have a PDFP Table and I want to have it laid out like so:
Item1 ............ $10.00
Item1123123 ...... $50.00
Item3 ............ $75.00
This is what I have so far:
var tableFont = FontFactory.GetFont(FontFactory.HELVETICA, 7);
var items = from p in ctx.quote_server_totals
where p.item_id == id
&& p.name != "total"
&& p.type != "totals"
select p;
foreach (var innerItem in items)
{
detailsTable.AddCell(new Phrase(innerItem.type == "discount" ? "ADJUSTMENT -" + innerItem.name : innerItem.name, tableFont));
detailsTable.AddCell(new Phrase(".......................................................", tableFont));
detailsTable.AddCell(new Phrase(Convert.ToDecimal(innerItem.value).ToString("c"), tableFont));
}
document.Add(detailsTable);
As can see, the only way I've been able to get the dots to extend is by manually entering them; however, this obviously won't work because the the first column's width will be different every time I run this code. Is there a way I can accomplish this? Thanks.
Please download chapter 2 of my book and search for DottedLineSeparator. This separator class will draw a dotted line between two parts of a Paragraph (as shown in the figures in the book). You can find the C# version of the Java book samples here.
If you can use a fixed-width font such as FontFactory.COURIER your task will be a lot easier.
//Our main font
var tableFont = FontFactory.GetFont(FontFactory.COURIER, 20);
//Will hold the shortname from the database
string itemShortName;
//Will hold the long name which includes the periods
string itemNameFull;
//Maximum number of characters that will fit into the cell
int maxLineLength = 23;
//Our table
var t = new PdfPTable(new float[] { 75, 25 });
for (var i = 1; i < 10000; i+=100) {
//Get our item name from "the database"
itemShortName = "Item " + i.ToString();
//Add dots based on the length
itemNameFull = itemShortName + ' ' + new String('.', maxLineLength - itemShortName.Length + 1);
//Add the two cells
t.AddCell(new PdfPCell(new Phrase(itemNameFull, tableFont)) { Border = PdfPCell.NO_BORDER });
t.AddCell(new PdfPCell(new Phrase(25.ToString("c"), tableFont)) { Border = PdfPCell.NO_BORDER });
}

Categories