How do I display exact number of Questions only - c#

In Question set i am getting all questions with particular (topicID,Marks). I am displaying Question randomly for totqsn i.e. total number of questions to display say 10 questions ,I am storing Count for number of questions of particular marks(1,2,3,4) in this int variables mark1Qsn,mark2Qsn,mark3Qsn,mark4Qsn respectively ,
using below code i am able to display Qustions from QuestionSet(say contains 34 qustions with (TopicID,marks)) for totqsn(say display 10 questions randomly from QuestionSet).My problem is
How can i display total 10 Question in which 3 questions of 1 mark,3 questions of 2mark,1 question of 3marks,3 questions of 4 marks i.e.
totqsn(10 questions= 3 qsn_of_mark1 + 3 qsn_of_mark2 + 1 qsn_of_mark3 + 3 qsn_of_mark3)
public partial class GroupExmStart : Form
{
DBHandling db = new DBHandling();
string GrpID = "";
string TopiID = "";
int totQsn = 0;
int mark1qsn = 0;
int mark2Qsn = 0;
int mark3Qsn = 0;
int mark4Qsn = 0;
int tik = 0;
string QuestionSet = "";
static Random _r = new Random();
string[] randomQsn = null;
string[] QAndA = null;
public GroupExmStart(string GroupName, string DurationID)
{
InitializeComponent();
totQsn = Convert.ToInt16(conf[0]);
mark1qsn = Convert.ToInt16(conf[3]);//this variable contains number of question to be display of mark 1
mark2Qsn = Convert.ToInt16(conf[4]);
mark3Qsn = Convert.ToInt16(conf[5]);
mark4Qsn = Convert.ToInt16(conf[6]);
QuestionSet = db.GetQuestions(TopiID, "1");
QuestionSet = QuestionSet + db.GetQuestions(TopiID, "2");
QuestionSet = QuestionSet + db.GetQuestions(TopiID, "3");
QuestionSet = QuestionSet + db.GetQuestions(TopiID, "4");
int z = Quiz(QuestionSet);
foreach (string qa in QAndA.OrderBy(i => _random.Next()))
{
if (qa != null)
if (qa.IndexOf('~') != -1)
{
randomQsn[count] = qa;
count++;
if (count == totQsn)
break;
}
}
int Quiz(string data)
{
string[] words = data.Split('$');
randomQsn = new string[totQsn + 1];
QAndA = new string[words.Length + 1];
for (int i = 0; i < words.Length; i++)
{
QAndA[i] = words[i];
}
return 0;
}
}
}
GetQuestions method accessing from DBHandling class
public string GetQuestions(string TopicID, string Marks)
{
string data = "";
try
{
string sql = "select QID,Question,Opt1,Opt2,Opt3,Opt4,AnsOp,Marks from Questions where TopicID IN(" + TopicID + ") and Marks=" + Marks;
cmd = new OleDbCommand(sql, acccon);
rs = cmd.ExecuteReader();
while (rs.Read())
{
data = data + rs[0].ToString() + "~" + rs[1].ToString() + "~" + rs[2].ToString() + "~" + rs[3].ToString() + "~" + rs[4].ToString() + "~" + rs[5].ToString() + "~" + rs[6].ToString() + "~" + rs[7].ToString() + "$";
}
}
catch (Exception err)
{
MessageBox.Show(err.Message.ToString());
}
return data;
}
Thanks in advance for any help

Completely untested and very messy but...
public class Question
{
public string Id { get; set; }
public string Text { get; set; }
public string Option1 { get; set; }
public string Option2 { get; set; }
public string Option3 { get; set; }
public string Option4 { get; set; }
public string AnswerOption { get; set; }
public int Marks { get; set; }
}
public IEnumerable<Question> GetQuestions(string topicId, int marks)
{
string sql = "select QID,Question,Opt1,Opt2,Opt3,Opt4,AnsOp,Marks from Questions where TopicID IN(" +
topicId + ") and Marks=" + marks.ToString();
var cmd = new OleDbCommand(sql, new OleDbConnection(""));
var rs = cmd.ExecuteReader();
if (rs != null)
{
while (rs.Read())
{
yield return
new Question
{
Id = rs[0].ToString(),
Text = rs[1].ToString(),
Option1 = rs[2].ToString(),
Option2 = rs[3].ToString(),
Option3 = rs[4].ToString(),
Option4 = rs[5].ToString(),
AnswerOption = rs[6].ToString(),
Marks = marks
};
}
}
}
public void Foo()
{
var totQsn = Convert.ToInt16(conf[0]); // isn't this just the sum of everything else?
var mark1qsn = Convert.ToInt16(conf[3]); //this variable contains number of question to be display of mark 1
var mark2qsn = Convert.ToInt16(conf[4]);
var mark3Qsn = Convert.ToInt16(conf[5]);
var mark4Qsn = Convert.ToInt16(conf[6]);
var mark1questionSet = GetQuestions(topicId, 1).ToList();
var mark2questionSet = GetQuestions(topicId, 2).ToList();
// etc
var finalQuestions = new List<Question>();
for (int i = 0; i < mark1qsn; i++)
{
var setIndex = _random.Next(mark1questionSet.Count);
finalQuestions.Add(mark1questionSet[setIndex]);
mark1questionSet.RemoveAt(setIndex);
}
for (int i = 0; i < mark2qsn; i++)
{
var setIndex = _random.Next(mark2questionSet.Count);
finalQuestions.Add(mark2questionSet[setIndex]);
mark2questionSet.RemoveAt(setIndex);
}
// etc - put this into a method or something
}

Related

Parsing list of string containing a delimiter to tree structure

So I have a list of strings like so:
var drinks = new List(){"Drinks", " * ", "Rum", "Captain Morgan", "Kraken", " * ", "Whiskey",
"Laphroaig"}
It needs to return the following:
*Drinks
*Drinks * Rum
*Drinks * Rum * Captain Morgan
*Drinks * Rum * Kraken
*Drinks * Whiskey
*Drinks * Whiskey * Laphroaig
So as seen, anytime a * is encountered, the next string would be treated as a child under the root. So here, Rum would fall under Drinks and Captain Morgan and Kraken would fall under Rum. Whiskey would fall under Drinks and Laphroaig would fall under whiskey.
I know it has to be some sort of tree structure and the only thing I have right now is this:
private static Drink GroupDrinks(List<string> drinkNames)
{
var drink = new Drink() { Children = new List<Drink>() };
foreach (var drinkName in drinkNames)
{
if (drinkName != "*")
{
drink.Name = drinkName;
drinkNames.RemoveAt(0);
}
else
{
drinkNames.RemoveAt(0);
drink.Children.Add(GroupDrinks(drinkNames));
}
}
return drink;
}
I figured I'd need to do some kind of recursion and maybe remove the character so it doesn't affect the next iteration but this clearly isn't working. Any tips would be great.
I am not sure if this code work for you but it is tested as your expected output:
Declaration:
List<Drink> lstdrink = new List<Drink>();
public List<FinalDrink> lstFinalDrink = new List<FinalDrink>();
Class:
public class FinalDrink
{
public string name { get; set; }
}
public class Drink
{
public string name { get; set; }
public int Tag { get; set; }
}
Set Up the Value:
public List<Drink> SetUpTheValue()
{
var drinks = new List<string> { "Drinks", " * ", "Rum", "Captain Morgan", "Kraken", " * ", "Whiskey", "Laphroaig" };
var repl = drinks.Select(s => s.Replace('*', ' ')).ToList();
string tag = string.Empty;
Drink drk = new Drink();
lstdrink = new List<Drink>();
for (int i = 0; i < repl.Count; i++)
{
if (i == 0)
{
drk = new Drink();
drk.name = repl[i];
drk.Tag = 1;
lstdrink.Add(drk);
tag = repl[i];
continue;
}
if (tag.Trim().Length == 0)
{
drk = new Drink();
drk.name = repl[i];
drk.Tag = 2;
lstdrink.Add(drk);
tag = repl[i];
continue;
}
if (repl[i].ToString().Trim().Length > 0)
{
drk = new Drink();
drk.name = repl[i];
drk.Tag = 0;
lstdrink.Add(drk);
tag = repl[i];
}
tag = repl[i];
}
return lstdrink;
}
Group Drinks:
public List<FinalDrink> GroupDrinks(List<Drink> drinkNames)
{
lstFinalDrink = new List<FinalDrink>();
FinalDrink fDrink = new FinalDrink();
var GetFirst = drinkNames.Where(x => x.Tag == 1).ToList();
fDrink.name = GetFirst[0].name.ToString();
lstFinalDrink.Add(fDrink);
var Content = drinkNames.Where(x => x.Tag != 1).ToList();
string itrVal = string.Empty;
int prev = 0;
string hcur = string.Empty;
for (int i = 0; i < Content.Count(); i++)
{
if (Content[i].Tag == 2)
{
hcur = GetFirst[0].name + " * " + Content[i].name;
fDrink = new FinalDrink();
itrVal = GetFirst[0].name + " * " + Content[i].name;
fDrink.name = itrVal;
lstFinalDrink.Add(fDrink);
prev = Content[i].Tag;
itrVal = string.Empty;
}
else
{
fDrink = new FinalDrink();
itrVal = hcur + " * " + Content[i].name;
fDrink.name = itrVal;
lstFinalDrink.Add(fDrink);
prev = Content[i].Tag;
itrVal = string.Empty;
}
}
return lstFinalDrink;
}
Execution:
private void button1_Click(object sender, EventArgs e)
{
if (SetUpTheValue().Count() > 0)
{
GroupDrinks(lstdrink);
}
}
The GroupDrinks return List<FinalDrink> this is the final result.
It is depend on you to modify the result
This Code will return the expected output as you added from above.

EP Plus - Error Table range collides with table

I am building an export to excel functionality using EP plus and c# application. I am currently getting the error.
'Table range collides with table tblAllocations29'
In my code logic below, I am looping through a data structure that contains key and collection as a value.
I looping across each key and once again loop through each collection belonging to that key.
I basically need to print tabular information for each collection along with its totals.
In the current scenario, I am getting the error when it is trying to print
three arrays
The first array has 17 records
The second array has 29 records
The third array has 6 records
I have taken a note of the ranges it is creating while debugging
The ranges are
A1 G18
A20 G50
A51 G58
controller
[HttpGet]
[SkipTokenAuthorization]
public HttpResponseMessage DownloadFundAllocationDetails(int id, DateTime date)
{
var ms = GetStrategy(id);
DateTime d = new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1);
if (ms.FIRM_ID != null)
{
var firm = GetService<FIRM>().Get(ms.FIRM_ID.Value);
IEnumerable<FIRMWIDE_MANAGER_ALLOCATION> allocationsGroup = null;
var allocationsGrouped = GetAllocationsGrouped(EntityType.Firm, firm.ID, d);
string fileName = string.Format("{0} as of {1}.xlsx", "test", date.ToString("MMM, yyyy"));
byte[] fileContents;
var newFile = new FileInfo(fileName);
using (var package = new OfficeOpenXml.ExcelPackage(newFile))
{
FundAllocationsPrinter.Print(package, allocationsGrouped);
fileContents = package.GetAsByteArray();
}
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(fileContents)
};
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
return result;
}
return null;
#endregion
}
I have written the following utility that will try and export. It works sometimes when there are two array collections and it failed when processing three. Could somebody tell me what the problems are
FundsAllocationsPrinter.cs
public class FundAllocationsPrinter
{
public static void Print(ExcelPackage package, ILookup<string, FIRMWIDE_MANAGER_ALLOCATION> allocation)
{
ExcelWorksheet wsSheet1 = package.Workbook.Worksheets.Add("Sheet1");
wsSheet1.Protection.IsProtected = false;
int count = 0;
int previouscount = 0;
var position = 2;
int startposition = 1;
IEnumerable<FIRMWIDE_MANAGER_ALLOCATION> allocationGroup = null;
foreach (var ag in allocation)
{
allocationGroup = ag.Select(a => a);
var allocationList = allocationGroup.ToList();
count = allocationList.Count();
using (ExcelRange Rng = wsSheet1.Cells["A" + startposition + ":G" + (count + previouscount + 1)])
{
ExcelTableCollection tblcollection = wsSheet1.Tables;
ExcelTable table = tblcollection.Add(Rng, "tblAllocations" + count);
//Set Columns position & name
table.Columns[0].Name = "Manager Strategy";
table.Columns[1].Name = "Fund";
table.Columns[2].Name = "Portfolio";
table.Columns[3].Name = "As Of";
table.Columns[4].Name = "EMV (USD)";
table.Columns[5].Name = "Percent";
table.Columns[6].Name = "Allocations";
wsSheet1.Column(1).Width = 45;
wsSheet1.Column(2).Width = 45;
wsSheet1.Column(3).Width = 55;
wsSheet1.Column(4).Width = 15;
wsSheet1.Column(5).Width = 25;
wsSheet1.Column(6).Width = 20;
wsSheet1.Column(7).Width = 20;
// table.ShowHeader = true;
table.ShowFilter = true;
table.ShowTotal = true;
//Add TotalsRowFormula into Excel table Columns
table.Columns[0].TotalsRowLabel = "Total Rows";
table.Columns[4].TotalsRowFormula = "SUBTOTAL(109,[EMV (USD)])";
table.Columns[5].TotalsRowFormula = "SUBTOTAL(109,[Percent])";
table.Columns[6].TotalsRowFormula = "SUBTOTAL(109,Allocations])";
table.TableStyle = TableStyles.Dark10;
}
foreach (var ac in allocationGroup)
{
wsSheet1.Cells["A" + position].Value = ac.MANAGER_STRATEGY_NAME;
wsSheet1.Cells["B" + position].Value = ac.MANAGER_FUND_NAME;
wsSheet1.Cells["C" + position].Value = ac.PRODUCT_NAME;
wsSheet1.Cells["D" + position].Value = ac.EVAL_DATE.ToString("dd MMM, yyyy");
wsSheet1.Cells["E" + position].Value = ac.UsdEmv;
wsSheet1.Cells["F" + position].Value = Math.Round(ac.GroupPercent,2);
wsSheet1.Cells["G" + position].Value = Math.Round(ac.WEIGHT_WITH_EQ,2);
position++;
}
position++;
previouscount = position;
// position = position + 1;
startposition = position;
position++;
}
}
}
This is how the data looks when it is displayed successfully
Your issue is entirely in your Print method. You've been bitten by creating a slightly over-complicated row tracking mechanism and combining that with magic numbers. This causes you to position each table after the first one row higher than it should be. The header and subtotals are not part of the table, so you have a couple rows of leeway for the error. Tables can't overlap as you've seen, so EPPlus starts barking at you after you've exhausted your leeway.
All you need to do is keep track of the current row that you are writing to, and account for the space taken by your table header and footer (the subtotals) if you use them.
You declare these:
int count = 0;
int previouscount = 0;
var position = 2;
int startposition = 1;
But to write to the correct row, all you need is this:
var rowNumber = 1;
This will properly start writing your data in row one of the Excel sheet. As you write your table rows, you'll track and increment only the rowNumber. But what about the header and footer of each table? If you start writing at the first row of your table you'll overwrite the header, and if you don't account for both the header and footer you'll start having collisions like you've seen. So lets do this:
var showFilter = true;
var showHeader = true;
var showTotals = true;
var rowAdderForHeader = Convert.ToInt32(showHeader);
var rowAdderForFooter = Convert.ToInt32(showTotals);
These are pretty self explanatory, you'll use the rowAdders to hop the header or footer when needed. rowNumber will always be your current row to create your table and write your data. You use the count when defining your table, but we've made it irrelevant for anything else, so we move it:
var allocationList = allocationGroup.ToList();
//Moved here
var count = allocationList.Count();
Your using statement becomes:
using (ExcelRange Rng = wsSheet1.Cells["A" + rowNumber + ":G" + (count + rowNumber)])
Next, it isn't mentioned in your post, but you are going to run into a problem with the following:
ExcelTableCollection tblcollection = wsSheet1.Tables;
ExcelTable table = tblcollection.Add(Rng, "tblAllocations" + count);
Your table names have to be unique, but you could very well wind up with multiple allocations having the same count, which will cause EPPlus to throw an exception at you for duplicating a table name. So you'll want to also track the index of your current table:
var rowNumber = 1;
var tableIndex = 0;
//...
foreach (var ag in allocation)
{
tableIndex += 1;
//...
}
And use it to ensure unique table names:
ExcelTableCollection tblcollection = wsSheet1.Tables;
ExcelTable table = tblcollection.Add(Rng, "tblAllocations" + tableIndex);
We use our format control variables:
// table.ShowHeader = true;
table.ShowFilter = true;
table.ShowTotal = true;
//Changes to
table.ShowHeader = showHeader;
table.ShowFilter = showFilter;
table.ShowTotal = showTotals;
You have a small typo here:
table.Columns[6].TotalsRowFormula = "SUBTOTAL(109,Allocations])";
//Should be:
table.Columns[6].TotalsRowFormula = "SUBTOTAL(109,[Allocations])";
After you are done defining your table, you begin writing your data with a foreach loop. In order to prevent overwriting the table header if it exists, we'll have to advance one row. We also have to advance one row for each FIRMWIDE_MANAGER_ALLOCATION. If you are using the subtotals, we have to advance one row after the loop completes in order to properly position the next table:
rowNumber += rowAdderForHeader;
foreach (var ac in allocationGroup)
{
//...
rowNumber += 1;
}
rowNumber += rowAdderForFooter;
And that's it. We now properly track our position using just one variable, and we modify the position as necessary if there is a header or footer on your table.
The following is a complete working example that can be run in LinqPad as long as you add the EPPlus package through Nuget. It creates a random number of allocation groups each with a random number of allocations, and then exports them. Change the output file path to something that works for you:
void Main()
{
var dataGenerator = new DataGenerator();
var allocations = dataGenerator.Generate();
var xlFile = new FileInfo(#"d:\so-test.xlsx");
if (xlFile.Exists)
{
xlFile.Delete();
}
using(var xl = new ExcelPackage(xlFile))
{
FundAllocationsPrinter.Print(xl, allocations);
xl.Save();
}
}
// Define other methods and classes here
public static class FundAllocationsPrinter
{
public static void Print(ExcelPackage package, ILookup<string, FIRMWIDE_MANAGER_ALLOCATION> allocation)
{
ExcelWorksheet wsSheet1 = package.Workbook.Worksheets.Add("Sheet1");
wsSheet1.Protection.IsProtected = false;
IEnumerable<FIRMWIDE_MANAGER_ALLOCATION> allocationGroup = null;
var rowNumber = 1;
int tableIndex = 0;
var showFilter = true;
var showHeader = true;
var showTotals = true;
var rowAdderForHeader = Convert.ToInt32(showHeader);
var rowAdderForFooter = Convert.ToInt32(showTotals);
foreach (var ag in allocation)
{
tableIndex += 1;
Console.WriteLine(tableIndex);
allocationGroup = ag.Select(a => a);
var allocationList = allocationGroup.ToList();
var count = allocationList.Count();
using (ExcelRange Rng = wsSheet1.Cells["A" + rowNumber + ":G" + (count + rowNumber)])
{
ExcelTableCollection tblcollection = wsSheet1.Tables;
ExcelTable table = tblcollection.Add(Rng, "tblAllocations" + tableIndex);
//Set Columns position & name
table.Columns[0].Name = "Manager Strategy";
table.Columns[1].Name = "Fund";
table.Columns[2].Name = "Portfolio";
table.Columns[3].Name = "As Of";
table.Columns[4].Name = "EMV (USD)";
table.Columns[5].Name = "Percent";
table.Columns[6].Name = "Allocations";
wsSheet1.Column(1).Width = 45;
wsSheet1.Column(2).Width = 45;
wsSheet1.Column(3).Width = 55;
wsSheet1.Column(4).Width = 15;
wsSheet1.Column(5).Width = 25;
wsSheet1.Column(6).Width = 20;
wsSheet1.Column(7).Width = 20;
table.ShowHeader = showHeader;
table.ShowFilter = showFilter;
table.ShowTotal = showTotals;
//Add TotalsRowFormula into Excel table Columns
table.Columns[0].TotalsRowLabel = "Total Rows";
table.Columns[4].TotalsRowFormula = "SUBTOTAL(109,[EMV (USD)])";
table.Columns[5].TotalsRowFormula = "SUBTOTAL(109,[Percent])";
table.Columns[6].TotalsRowFormula = "SUBTOTAL(109, [Allocations])";
table.TableStyle = TableStyles.Dark10;
}
//Account for the table header
rowNumber += rowAdderForHeader;
foreach (var ac in allocationGroup)
{
wsSheet1.Cells["A" + rowNumber].Value = ac.MANAGER_STRATEGY_NAME;
wsSheet1.Cells["B" + rowNumber].Value = ac.MANAGER_FUND_NAME;
wsSheet1.Cells["C" + rowNumber].Value = ac.PRODUCT_NAME;
wsSheet1.Cells["D" + rowNumber].Value = ac.EVAL_DATE.ToString("dd MMM, yyyy");
wsSheet1.Cells["E" + rowNumber].Value = ac.UsdEmv;
wsSheet1.Cells["F" + rowNumber].Value = Math.Round(ac.GroupPercent, 2);
wsSheet1.Cells["G" + rowNumber].Value = Math.Round(ac.WEIGHT_WITH_EQ, 2);
rowNumber++;
}
//Account for the table footer
rowNumber += rowAdderForFooter;
}
}
}
public class FIRMWIDE_MANAGER_ALLOCATION
{
public FIRMWIDE_MANAGER_ALLOCATION(string name, Random rnd)
{
Name = name;
MANAGER_STRATEGY_NAME = "strategy name";
MANAGER_FUND_NAME = "fund name";
PRODUCT_NAME = "product name";
EVAL_DATE = DateTime.Now;
UsdEmv = (decimal)rnd.NextDouble() * 100000000;
GroupPercent = (decimal)rnd.NextDouble() * 100;
WEIGHT_WITH_EQ = 0;
}
public string Name { get; set; }
public string MANAGER_STRATEGY_NAME { get; set; }
public string MANAGER_FUND_NAME { get; set; }
public string PRODUCT_NAME { get; set; }
public DateTime EVAL_DATE { get; set; }
public decimal UsdEmv { get; set; }
public decimal GroupPercent { get; set; }
public decimal WEIGHT_WITH_EQ { get; set; }
}
public class DataGenerator
{
public static Random rnd = new Random();
public ILookup<string, FIRMWIDE_MANAGER_ALLOCATION> Generate()
{
var data = new List<FIRMWIDE_MANAGER_ALLOCATION>();
var itemCount = rnd.Next(1, 100);
for (var itemIndex = 0; itemIndex < itemCount; itemIndex++)
{
var name = Path.GetRandomFileName();
data.AddRange(GenerateItems(name));
}
return data.ToLookup(d => d.Name, d => d);
}
private IEnumerable<FIRMWIDE_MANAGER_ALLOCATION> GenerateItems(string name)
{
var itemCount = rnd.Next(1,100);
var items = new List<FIRMWIDE_MANAGER_ALLOCATION>();
for (var itemIndex = 0; itemIndex < itemCount; itemIndex++)
{
items.Add(new FIRMWIDE_MANAGER_ALLOCATION(name, rnd));
}
return items;
}
}

C# Loop over all possible values, when not found increase value and continue

I need to send a request for every supplier code to a webservice (i know that sounds crazy but the owner designed it this way).
The supplier code format is:
30X1X1XXXXX1
You can check what i did so far (github link: https://github.com/rareba/SiapWebServices_Library/blob/master/SiapWebServices_Library/SiapWebServicesFornitore.cs)
public static List<StructAnaFornitoreOut> Get_All_Suppliers(WebServicesFornitoreClient client, StructLogin loginCredentials, string showSuspended = "N", string searchType = "R")
{
var supplier_list = new List<StructAnaFornitoreOut>();
var supplier_retrived = new StructAnaFornitoreOut
{
esito = new StructEsito
{
stato = "OK",
}
};
int KO_Count = 0;
int conto = 1;
int sottoconto = 1;
int codice = 0;
string codFornitore = Generate_Supplier_Code_String(codice, sottoconto, conto);
var search = new StructAnaFornitoreIn
{
IAnaFornitore = new StructAnaFornitore
{
codice = codFornitore
},
IAzione = "C",
//vModRicerca = new string[] { "COD_FIS","PAR_IVA","ALT_SIS" }
};
while (KO_Count < 10)
{
while (KO_Count < 10)
{
while (KO_Count < 10)
{
supplier_retrived = client.gestioneAnagraficaFornitore(loginCredentials, search);
if (supplier_retrived.esito.stato == "KO")
{
KO_Count++;
}
else
{
supplier_list.Add(supplier_retrived);
codFornitore = Generate_Supplier_Code_String(codice, sottoconto, conto);
Console.WriteLine(codFornitore);
codice++;
search.IAnaFornitore.codice = codFornitore;
}
}
KO_Count = 0;
sottoconto++;
}
KO_Count = 0;
conto++;
}
return supplier_list;
}
// Returns a supplier code string increased by 1
public static string Generate_Supplier_Code_String(int codice = 0, int sottoconto = 1, int conto = 1, string mastro = "30")
{
codice++;
string string_conto = " ";
string string_sottoconto = " ";
string string_codice = " ";
if (conto > 9)
{
string_conto = "";
}
if (sottoconto > 9)
{
string_sottoconto = "";
}
if (codice > 9)
{
string_codice = " ";
}
else if (codice > 99)
{
string_codice = " ";
}
else if (codice > 999)
{
string_codice = " ";
}
else if (codice > 9999)
{
string_codice = " ";
}
else if (codice > 99999)
{
string_codice = " ";
}
else if (codice >= 999999)
{
string_codice = "";
}
string customercode = mastro + string_conto + conto + string_sottoconto + sottoconto + string_codice + codice;
return customercode;
}
However this doesn't work at all: it stops at supplier 30 1 1 100 and starts increasing sottoconto like there is no tomorrow.
The idea should be to do something like:
- Get the supplier data
- Increase codice by 1
- If for 10 times you get nothing (esito.status = "KO") then increase sottoconto and start again from codice = 1
- If after incresing sottoconto you still get nothing for 10 times then increase conto and start again from codice = 0

Align in RichtextBox

Using this:
richTextBox1.AppendText("EMPID: " + "\t\t" + "4001");
richTextBox1.AppendText(System.Environment.NewLine);
richTextBox1.AppendText(System.Environment.NewLine);
richTextBox1.AppendText("EmployeeName: " + "\t\t" + "Taborjakol");
I got this:
How I will perfectly Align it to this:
What you can do is change the tab positions of the RichTextBoxControl.
richTextBox1.SelectionTabs = new int[] { 90, 180, 270, 360 };
richTextBox1.AppendText("EMPID: " + "\t\t" + "4001");
richTextBox1.AppendText(System.Environment.NewLine);
richTextBox1.AppendText(System.Environment.NewLine);
richTextBox1.AppendText("EmployeeName: " + "\t\t" + "Taborjakol");
The SelectionsTab property re-defines the spaces that are used for each tab in the RichTextBox control. You need to experiment with the tab settings to get the best result for your text.
Replace your last line of code with
richTextBox1.AppendText("EmployeeName: " + "\t" + "Taborjakol");
If you dont have to use a richtextbox, you should definetly have a look at the gridview or if you use third party tools like Telerik, DevCraft, ComponentOne and others most of them will have a control called Property Grid that has a layout you might be interested in.
If there is no other way around in using a richtextbox, you have to do the following:
Get a fixed-width font or called monospaced font http://en.wikipedia.org/wiki/Monospaced_font
Evalute the amout of characters which share the same width as a tab (I dont know the number of character have to figure it out yourself with testing)
Get the max length of your text at the left side (your "columnnames" I guess - like "EmployeeName")
Do some math - max length + one tab = x characters
now fill the remaining text at your left side with the neccessary tabs (can be anything from 1 to x) to get the same amout of characters as calculated in 4.
But again a richtextbox isnt the ideal control for this kind of scenario.
Edit:
Here some Code:
public partial class Form1 : Form
{
private const int FetchTestData = 50;
private const int TabCharLength = 5;
public Form1()
{
InitializeComponent();
//With this Fontsettings - 5 chars = 1 Tab - this changes with different fonts
this.richTextBox1.Font = new System.Drawing.Font("Courier New", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
var type = typeof(TestData);
var list = GetTestData();
var maxProperty = GetMaxProperty(type);
maxProperty = FillToNext(maxProperty);
var properties = GetProperties(type);
for (var i = 0; i < FetchTestData; i++)
{
var data = list[i];
foreach (var propertyInfo in properties)
{
richTextBox1.AppendText(propertyInfo.Name);
var tabs = GetNumberOfTabs(maxProperty, propertyInfo.Name.Length);
for (var j = 0; j < tabs; j++)
richTextBox1.AppendText("\t");
richTextBox1.AppendText(Convert.ToString(propertyInfo.GetValue(data)));
richTextBox1.AppendText(Environment.NewLine);
}
if (i >= FetchTestData - 1)
continue;
richTextBox1.AppendText(Environment.NewLine);
richTextBox1.AppendText("---------- NEXT DATA ----------");
richTextBox1.AppendText(Environment.NewLine);
}
}
private int GetNumberOfTabs(int maxLength, int textLength)
{
if ((maxLength % TabCharLength) != 0)
maxLength = FillToNext(maxLength);
var difLength = maxLength - textLength;
return (int)(Math.Floor(Convert.ToDouble(difLength / TabCharLength)) + 1);
}
private int FillToNext(int maxLength)
{
return maxLength + (5 - (maxLength % TabCharLength));
}
private PropertyInfo[] GetProperties(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
}
private int GetMaxProperty(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return (from x in GetProperties(type)
select x.Name.Length).Max();
}
private List<TestData> GetTestData()
{
var returnValue = new List<TestData>();
for (int i = 0; i < FetchTestData; i++)
{
returnValue.Add(new TestData()
{
ID = i,
Name = "NameValue " + i,
Description = "DescriptionValue " + i,
PropertyA = "PropertyAValue " + i,
PropertyB = "PropertyBValue " + i,
SomeReallyLongPropertyName = "RandomStuff... " + i
});
}
return returnValue;
}
}
public class TestData
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string SomeReallyLongPropertyName { get; set; }
}
As stated you firstly would want to set the font to a mono-space font, this means that each letter will be the same size.
So you will see something like this:
EEEEEEEEEEE
Rather than
EeEeeiiiiiiiiiiiiiiiiii
Secondly, you could align the text which may improve it slightly:
richTextBox1.SelectAll();
richTextBox1.SelectionAlignment = HorizontalAlignment.Center;
However unless you have to, I would suggest using a different control:
Gridview
Listbox
These are both easy to format, gridview has tabs, and the listbox you can use string.Format when entering the values.

What C# template engine that has clean separation between HTML and control code?

What C# template engine
that uses 'pure' HTML having only text and markers
sans any control flow like if, while, loop or expressions,
separating html from control code ?
Below is the example phone book list code,
expressing how this should be done:
string html=#"
<html><head><title>#title</title></head>
<body>
<table>
<tr>
<td> id</td> <td> name</td> <td> sex</td> <td>phones</td>
</tr><!--#contacts:-->
<tr>
<td>#id</td> <td>#name</td> <td>#sex</td>
<td>
<!--#phones:-->#phone <br/>
<!--:#phones-->
</td>
</tr><!--:#contacts-->
</table>
</body>
</html>";
var contacts = from c in db.contacts select c;
Marker m = new Marker(html);
Filler t = m.Mark("title");
t.Set("Phone book");
Filler c = m.Mark("contacts", "id,name,sex");
// **foreach** expressed in code, not in html
foreach(var contact in contacts) {
int id = contact.id;
c.Add(id, contact.name, contact.sex);
Filler p = c.Mark("phones", "phone");
var phones = from ph in db.phones
where ph.id == id
select new {ph.phone};
if (phones.Any()) {
foreach(var ph in phones) {
p.Add(ph);
}
} else {
fp.Clear();
}
}
Console.Out.WriteLine(m.Get());
Use this code:
Templet.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace templaten.com.Templaten
{
public class tRange
{
public int head, toe;
public tRange(int _head, int _toe)
{
head = _head;
toe = _toe;
}
}
public enum AType
{
VALUE = 0,
NAME = 1,
OPEN = 2,
CLOSE = 3,
GROUP = 4
}
public class Atom
{
private AType kin;
private string tag;
private object data;
private List<Atom> bag;
public Atom(string _tag = "",
AType _kin = AType.VALUE,
object _data = null)
{
tag = _tag;
if (String.IsNullOrEmpty(_tag))
_kin = AType.GROUP;
kin = _kin;
if (_kin == AType.GROUP)
bag = new List<Atom>();
else
bag = null;
data = _data;
}
public AType Kin
{
get { return kin; }
}
public string Tag
{
get { return tag; }
set { tag = value; }
}
public List<Atom> Bag
{
get { return bag; }
}
public object Data
{
get { return data; }
set { data = value; }
}
public int Add(string _tag = "",
AType _kin = AType.VALUE,
object _data = null)
{
if (bag != null)
{
bag.Add(new Atom(_tag, _kin, _data));
return bag.Count - 1;
}
else
{
return -1;
}
}
}
public class Templet
{
private string content;
string namepat = "\\w+";
string justName = "(\\w+)";
string namePre = "#";
string namePost = "";
string comment0 = "\\<!--\\s*";
string comment1 = "\\s*--\\>";
private Atom tokens; // parsed contents
private Dictionary<string, int> iNames; // name index
private Dictionary<string, tRange> iGroups; // groups index
private Atom buffer; // output buffer
private Dictionary<string, int> _iname; // output name index
private Dictionary<string, tRange> _igroup; // output index
public Templet(string Content = null)
{
Init(Content);
}
private int[] mark(string[] names, string group)
{
if (names == null || names.Length < 1) return null;
tRange t = new tRange(0, buffer.Bag.Count - 1);
if (group != null)
{
if (!_igroup.ContainsKey(group)) return null;
t = _igroup[group];
}
int[] marks = new int[names.Length];
for (int i = 0; i < marks.Length; i++)
marks[i] = -1;
for (int i = t.head; i <= t.toe; i++)
{
if (buffer.Bag[i].Kin == AType.NAME)
{
for (int j = 0; j < names.Length; j++)
{
if (String.Compare(
names[j],
buffer.Bag[i].Tag,
true) == 0)
{
marks[j] = i;
break;
}
}
}
}
return marks;
}
public Filler Mark(string group, string names)
{
Filler f = new Filler(this, names);
f.di = mark(f.names, group);
f.Group = group;
tRange t = null;
if (_igroup.ContainsKey(group)) t = _igroup[group];
f.Range = t;
return f;
}
public Filler Mark(string names)
{
Filler f = new Filler(this, names);
f.di = mark(f.names, null);
f.Group = "";
f.Range = null;
return f;
}
public void Set(int[] locations, object[] x)
{
int j = Math.Min(x.Length, locations.Length);
for (int i = 0; i < j; i++)
{
int l = locations[i];
if ((l >= 0) && (buffer.Bag[l] != null))
buffer.Bag[l].Data = x[i];
}
}
public void New(string group, int seq = 0)
{
// place new group copied from old group just below it
if (!( iGroups.ContainsKey(group)
&& _igroup.ContainsKey(group)
&& seq > 0)) return;
tRange newT = null;
tRange t = iGroups[group];
int beginRange = _igroup[group].toe + 1;
for (int i = t.head; i <= t.toe; i++)
{
buffer.Bag.Insert(beginRange,
new Atom(tokens.Bag[i].Tag,
tokens.Bag[i].Kin,
tokens.Bag[i].Data));
beginRange++;
}
newT = new tRange(t.toe + 1, t.toe + (t.toe - t.head + 1));
// rename past group
string pastGroup = group + "_" + seq;
t = _igroup[group];
buffer.Bag[t.head].Tag = pastGroup;
buffer.Bag[t.toe].Tag = pastGroup;
_igroup[pastGroup] = t;
// change group indexes
_igroup[group] = newT;
}
public void ReMark(Filler f, string group)
{
if (!_igroup.ContainsKey(group)) return;
Map(buffer, _iname, _igroup);
f.di = mark(f.names, group);
f.Range = _igroup[group];
}
private static void Indexing(string aname,
AType kin,
int i,
Dictionary<string, int> dd,
Dictionary<string, tRange> gg)
{
switch (kin)
{
case AType.NAME: // index all names
dd[aname] = i;
break;
case AType.OPEN: // index all groups
if (!gg.ContainsKey(aname))
gg[aname] = new tRange(i, -1);
else
gg[aname].head = i;
break;
case AType.CLOSE:
if (!gg.ContainsKey(aname))
gg[aname] = new tRange(-1, i);
else
gg[aname].toe = i;
break;
default:
break;
}
}
private static void Map(Atom oo,
Dictionary<string, int> dd,
Dictionary<string, tRange> gg)
{
for (int i = 0; i < oo.Bag.Count; i++)
{
string aname = oo.Bag[i].Tag;
Indexing(oo.Bag[i].Tag, oo.Bag[i].Kin, i, dd, gg);
}
}
public void Init(string Content = null)
{
content = Content;
tokens = new Atom("", AType.GROUP);
iNames = new Dictionary<string, int>();
iGroups = new Dictionary<string, tRange>();
// parse content into tokens
string namePattern = namePre + namepat + namePost;
string patterns =
"(?<var>" + namePattern + ")|" +
"(?<head>" + comment0 + namePattern + ":" + comment1 + ")|" +
"(?<toe>" + comment0 + ":" + namePattern + comment1 + ")";
Regex jn = new Regex(justName, RegexOptions.Compiled);
Regex r = new Regex(patterns, RegexOptions.Compiled);
MatchCollection ms = r.Matches(content);
int pre = 0;
foreach (Match m in ms)
{
tokens.Add(content.Substring(pre, m.Index - pre));
int idx = -1;
if (m.Groups.Count >= 3)
{
string aname = "";
MatchCollection x = jn.Matches(m.Value);
if (x.Count > 0 && x[0].Groups.Count > 1)
aname = x[0].Groups[1].ToString();
AType t = AType.VALUE;
if (m.Groups[1].Length > 0) t = AType.NAME;
if (m.Groups[2].Length > 0) t = AType.OPEN;
if (m.Groups[3].Length > 0) t = AType.CLOSE;
if (aname.Length > 0)
{
tokens.Add(aname, t);
idx = tokens.Bag.Count - 1;
}
Indexing(aname, t, idx, iNames, iGroups);
}
pre = m.Index + m.Length;
}
if (pre < content.Length)
tokens.Add(content.Substring(pre, content.Length - pre));
// copy tokens into buffer
buffer = new Atom("", AType.GROUP);
for (int i = 0; i < tokens.Bag.Count; i++)
buffer.Add(tokens.Bag[i].Tag, tokens.Bag[i].Kin);
// initialize index of output names
_iname = new Dictionary<string, int>();
foreach (string k in iNames.Keys)
_iname[k] = iNames[k];
// initialize index of output groups
_igroup = new Dictionary<string, tRange>();
foreach (string k in iGroups.Keys)
{
tRange t = iGroups[k];
_igroup[k] = new tRange(t.head, t.toe);
}
}
public string Get()
{
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < buffer.Bag.Count; i++)
{
switch (buffer.Bag[i].Kin)
{
case AType.VALUE:
sb.Append(buffer.Bag[i].Tag);
break;
case AType.NAME:
sb.Append(buffer.Bag[i].Data);
break;
case AType.OPEN:
case AType.CLOSE:
break;
default: break;
}
}
return sb.ToString();
}
}
public class Filler
{
private Templet t = null;
public int[] di;
public string[] names;
public string Group { get; set; }
public tRange Range { get; set; }
private int seq = 0;
public Filler(Templet tl, string markers = null)
{
t = tl;
if (markers != null)
names = markers.Split(new char[] { ',' },
StringSplitOptions.RemoveEmptyEntries);
else
names = null;
}
public void init(int length)
{
di = new int[length];
for (int i = 0; i < length; i++)
di[i] = -1;
seq = 0;
Group = "";
Range = null;
}
// clear contents inside marked object or group
public void Clear()
{
object[] x = new object[di.Length];
for (int i = 0; i < di.Length; i++)
x[i] = null;
t.Set(di, x);
}
// set value for marked object,
// or add row to group and set value to columns
public void Set(params object[] x)
{
t.Set(di, x);
}
public void Add(params object[] x)
{
if (Group.Length > 0)
{
t.New(Group, seq);
++seq;
t.ReMark(this, Group);
}
t.Set(di, x);
}
}
}
Testing program
Program.cs
Templet m = new Templet(html);
Filler f= m.Mark("title");
f.Set("Phone book");
Filler fcontacts = m.Mark("contacts", "id,name,sex,phone");
fcontacts.Add(1, "Akhmad", "M", "123456");
fcontacts.Add(2, "Barry", "M", "234567");
fcontacts.Add(1, "Charles", "M", "345678");
Console.Out.WriteLine(m.Get());
Still can't do nested loop- yet.
Just use ASP.NET. Whether you use webforms or MVC, it's super easy to have C# in your .cs files, and HTML in your .aspx files.
As with anything in programming, it's 99% up to you to do things right. Flexible UI engines aren't going to enforce that you follow good coding practices.
In principle most any template engine you choose can separate HTML from control logic with the proper architecture. using an MVC (Or MVVM) pattern, if you construct your model in such a way that the controller contains the if/then logic instead of the view you can eliminate it from the view.
That said, the syntax you use is very close to Razor syntax which is easily available for ASP.NET MVC through NuGet packages.
I totally hear you. I built SharpFusion, which has some other stuff in it but if you look for the template.cs file you will see the handler that parses a HTML file and simply replaces out tokens with values that you've made in c#.
Because no XML parsing is done like ASP.NET the framework loads much faster than even an MVC site.
Another alternative is ServiceStack.

Categories

Resources