I built a winform project. This project open a mhtml file, then, he display the datagrid and remove the empty column.
i used much time "invoke" in my code. I would like to know how can i put this data into a DataTable or List and then binded the grid to it.
Here is the code :
{
public partial class Form1 : Form
{
private readonly string ConvertedFileName = "page.html";
private readonly List<string> ColumnsToSeparate = new List<string>() { "life limit", "interval" }; // Delete these columns
private readonly List<string> ExtraColumnsToAdd = new List<string>() { "Calendar", "Flight Hours", "Landing" }; // Add these columns
public Form1()
{
InitializeComponent();
this.Text = $"MhtmlTablesHunter v{Application.ProductVersion}";
}
//browse for specific file type , in this case its .mhtml
private void btnBrowse_Click(object sender, EventArgs e)
{
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Title = "Please choose the MHTML file";
openFileDialog.Filter = "MHTML files (*.mhtml)|*.mhtml;"; //the file type specified here
openFileDialog.RestoreDirectory = false;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
textBoxSourceFile.Text = openFileDialog.FileName;
checkAndExtractTable();
}
}
}
private void checkAndExtractTable()
{
string sourcePath = textBoxSourceFile.Text;
if (!string.IsNullOrEmpty(sourcePath)) //check if the input file path is not empty
{
if (File.Exists(sourcePath)) //check if the input file path is exists
{
Task.Run(async () => await ExtractTable(sourcePath)); //run the extraction process in a thread for the UI to be more responsive
}
else
{
MessageBox.Show("Source file doesn't exist.");
}
}
else
{
MessageBox.Show("Please select the source file.");
}
}
//This part concern the headers, rows and columns
public async Task<string> ExtractTable(string sourcePath)
{
try
{
var doc = new HtmlAgilityPack.HtmlDocument();
var converter = new MimeConverter(); //converter used to convert mhtml file to html
if (File.Exists(ConvertedFileName)) //check if previously converted file is exist
{
File.Delete(ConvertedFileName); //delete the file
}
using (FileStream sourceStream = File.OpenRead(sourcePath))
{
using (FileStream destinationStream = File.Open("page.html", FileMode.Create))
{
await converter.Convert(sourceStream, destinationStream); //convert the file to html, it will be stored in the application folder
}
}
doc.Load(ConvertedFileName); //load the html
var tables = doc.DocumentNode.SelectNodes("//table"); //get all the tables
HtmlAgilityPack.HtmlNode table = null;
if (tables.Count > 0)
{
table = tables[tables.Count - 1]; //take the last table
}
if (table != null) //if the table exists
{
dataGridView1.Invoke((Action)delegate //we use delegate because we accessing the datagridview from a different thread
{
this.dataGridView1.Rows.Clear();
this.dataGridView1.Columns.Clear();
});
var rows = table.SelectNodes(".//tr"); //get all the rows
var nodes = rows[0].SelectNodes("th|td"); //get the header row values, first item will be the header row always
string LifeLimitColumnName = ColumnsToSeparate.Where(c => nodes.Any(n => n.InnerText.ToLower().Contains(c))).FirstOrDefault();
if (string.IsNullOrWhiteSpace(LifeLimitColumnName))
{
LifeLimitColumnName = "Someunknowncolumn";
}
List<string> headers = new List<string>();
for (int i = 0; i < nodes.Count; i++) // LOOP
{
headers.Add(nodes[i].InnerText);
if (!nodes[i].InnerText.ToLower().Contains(LifeLimitColumnName))
{
dataGridView1.Invoke((Action)delegate
{
dataGridView1.Columns.Add("", nodes[i].InnerText);
});
}
}
int indexOfLifeLimitColumn = headers.FindIndex(h => h.ToLower().Contains(LifeLimitColumnName));
if (indexOfLifeLimitColumn > -1)
{
foreach (var eh in ExtraColumnsToAdd)
{
dataGridView1.Invoke((Action)delegate
{
dataGridView1.Columns.Add("", eh); //add extra header to the datagridview
});
}
}
for (int i = 1; i < rows.Count; i++) ///loop through rest of the rows
{
var row = rows[i];
var nodes2 = row.SelectNodes("th|td"); //get all columns in the current row
List<string> values = new List<string>(); //list to store row values
for (int x = 0; x < nodes2.Count; x++)
{
//rowes.Cells[x].Value = nodes2[x].InnerText;
string cellText = nodes2[x].InnerText.Replace(" ", " ");
values.Add(cellText); //add the cell value in the list
}
// Factory for -> Calendar, Flight Hours, Landings
if (indexOfLifeLimitColumn > -1)
{
values.RemoveAt(indexOfLifeLimitColumn);
string lifeLimitValue = nodes2[indexOfLifeLimitColumn].InnerText.Replace(" ", " ");
string[] splittedValues = lifeLimitValue.Split(' ');
for (int y = 0; y < ExtraColumnsToAdd.Count; y++)
{
if (ExtraColumnsToAdd[y] == "Calendar")
{
string valueToAdd = string.Empty;
string[] times = new string[] { "Years", "Year", "Months", "Month", "Day", "Days" };
if (splittedValues.Any(s => times.Any(t => t == s)))
{
var timeFound = times.Where(t => splittedValues.Any(s => s == t)).FirstOrDefault();
int index = splittedValues.ToList().FindIndex(s => s.Equals(timeFound));
valueToAdd = $"{splittedValues[index - 1]} {timeFound}";
}
values.Add(valueToAdd);
}
else if (ExtraColumnsToAdd[y] == "Flight Hours")
{
string valueToAdd = string.Empty;
if (splittedValues.Any(s => s == "FH"))
{
int index = splittedValues.ToList().FindIndex(s => s.Equals("FH"));
valueToAdd = $"{splittedValues[index - 1]} FH";
}
values.Add(valueToAdd);
}
else
{
string valueToAdd = string.Empty;
if (splittedValues.Any(s => s == "LDG"))
{
int index = splittedValues.ToList().FindIndex(s => s.Equals("LDG"));
valueToAdd = $"{splittedValues[index - 1]} LDG";
}
values.Add(valueToAdd);
}
}
}
dataGridView1.Invoke((Action)delegate
{
this.dataGridView1.Rows.Add(values.ToArray()); //add the list as a row
});
}
//This code remove the empty row
dataGridView1.Invoke((Action)delegate
{
int[] rowDataCount = new int[dataGridView1.Columns.Count];
Array.Clear(rowDataCount, 0, rowDataCount.Length);
for (int row_i = 0; row_i < this.dataGridView1.RowCount; row_i++)
{
for (int col_i = 0; col_i < this.dataGridView1.ColumnCount; col_i++)
{
var cell = this.dataGridView1.Rows[row_i].Cells[col_i];
string cellText = cell.Value.ToString();
if (!String.IsNullOrWhiteSpace(cellText))
{
rowDataCount[col_i] += 1;
}
}
}
int removedCount = 0;
for (int index = 0; index < rowDataCount.Length; index++)
{
if (rowDataCount[index] == 0)
{
this.dataGridView1.Columns.RemoveAt(index - removedCount);
removedCount++;
}
}
});
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return string.Empty;
}
private void textBoxSourceFile_TextChanged(object sender, EventArgs e)
{
}
}
}
Somebody can help me please? thanks a lot !
I have a gridview with multiple groups and I use the CustomDrawGroupRow Event to display the row count for each group:
private void gridView_CustomDrawGroupRow(object sender, DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs e)
{
var view = (GridView)sender;
var info = (GridGroupRowInfo)e.Info;
var caption = info.Column.Caption;
if (info.Column.Caption == string.Empty)
{
caption = info.Column.ToString();
}
info.GroupText = $"{caption} : {info.GroupValueText} ({view.GetChildRowCount(e.RowHandle)})";
}
Now I would like to display the row count recursively, so that the first level shows a count of 2171 (1913 + 135 + 123).
This is what I have tried, but it throws a StackOverflowException and I cannot see the problem here:
private void gridView_CustomDrawGroupRow(object sender, DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs e)
{
var view = (GridView)sender;
var info = (GridGroupRowInfo)e.Info;
var caption = info.Column.Caption;
if (info.Column.Caption == string.Empty)
{
caption = info.Column.ToString();
}
info.GroupText = $"{caption} : {info.GroupValueText} ({GetRowCountRecursive(view, e.RowHandle)})";
}
private int GetRowCountRecursive(GridView view, int rowHandle)
{
int totalCount = 0;
int childrenCount = view.GetChildRowCount(rowHandle);
for (int i = 0; i < childrenCount; i++)
{
var childRowHandle = view.GetChildRowHandle(rowHandle, i);
totalCount += GetRowCountRecursive(view, childRowHandle);
}
return totalCount;
}
I was missing to check if childRowHandle is a group row with IsGroupRow(). If not, the recursion have to stop and totalCount need to be increased by 1.
private int GetRowCountRecursive(GridView view, int rowHandle)
{
int totalCount = 0;
int childrenCount = view.GetChildRowCount(rowHandle);
for (int i = 0; i < childrenCount; i++)
{
var childRowHandle = view.GetChildRowHandle(rowHandle, i);
if (view.IsGroupRow(childRowHandle))
{
totalCount += GetRowCountRecursive(view, childRowHandle);
}
else
{
totalCount++;
}
}
return totalCount;
}
You can use GroupRowInfo.ChildControllerRowCount property to get the row count. The instance of GroupRowInfo class you can get from GridGroupRowInfo.RowKey property.
Here is example:
private void gridView1_CustomDrawGroupRow(object sender, RowObjectCustomDrawEventArgs e)
{
var view = (GridView)sender;
var info = (GridGroupRowInfo)e.Info;
var caption = info.Column.Caption;
if (info.Column.Caption == string.Empty)
{
caption = info.Column.ToString();
}
var groupInfo = info.RowKey as GroupRowInfo;
info.GroupText = $"{caption} : {info.GroupValueText} ({groupInfo?.ChildControllerRowCount})";
}
Here is the screenshot:
When I select a particular item in ListView item, I am able to display that particular item, and when the form loads I am getting the last item displayed by default (say the 10th item). However, what I want is to display the first item by default. How can I do this? I tried to do something like
listView1.Items[1].Selected = true;
but it's not working:
public partial class GroupExmStart : Form
{
string[] totDisplayQsn = null;
string[] QAndA = null;
string[] words = null;
private List<Question> questions;
ListViewItem lvi;
public GroupExmStart(string GroupName, string DurationID)
{
InitializeComponent();
this.GrpID=GroupName;
TopiID=db.GetTopicIDForGroup(GrpID);
string[] conf = db.GetConfiguration(Convert.ToInt16(DurationID)).Split('|');
Question qsn = new Question();
questions = qsn.Foo(TopiID, conf);
int z = Quiz(questions);
totQsn = Convert.ToInt16(conf[0]);
for (int kk = 1; kk <= totQsn; kk++)//using this I am adding items to listview
{
lvi = new ListViewItem();
lvi.Text = kk.ToString();
listView1.Items.Add(lvi);
}
totDisplayQsn = new string[totQsn + 1];
}
int Quiz(List<Question> questions)//using this I a passing set of questions to be displayed
{
foreach (Question question in questions)
{
DisplayQuestion(question);
}
return 0;
}
private void DisplayQuestion(Question question)//using this i am displaying questions
{
string Q = question.Text;
label5.Text = Q;
string OP1 = question.Option1;
string OP2 = question.Option2;
string OP3 = question.Option3;
string OP4 = question.Option4;
radioButton12.Text = OP4;
radioButton11.Text = OP4;
radioButton10.Text = OP4;
radioButton9.Text = OP4;
}
}
private void listView1_MouseClick(object sender, MouseEventArgs e)//using this i am selection particular item and displaying it
{
if (totDisplayQsn.GetLength(0) >= 0)
{
if (listView1.SelectedItems.Count > 0)
{
var q = Convert.ToInt16(listView1.SelectedItems[0].Text);
var selectedQuestion = questions[q-1];
DisplayQuestion(selectedQuestion);
}
}
}
Thanks in advance for any help.
Try this
listView1.SelectedItems[0].Focused = true;
To select the first item, access it by its zero based index. Place the code just after your items initialization code.
for (int kk = 1; kk <= totQsn; kk++)//using this I am adding items to listview
{
lvi = new ListViewItem();
lvi.Selected = false;
lvi.Text = kk.ToString();
listView1.Items.Add(lvi);
}
listView1.Items[0].Selected = true;
DisplayQuestion(questions[0]);
Remove the following code:
int Quiz(List<Question> questions)//using this I a passing set of questions to be displayed
{
foreach (Question question in questions)
{
DisplayQuestion(question);
}
return 0;
}
Ok try the below code:
ListViewItem foundItem = listView1.FindItemWithText("Select4", false, 0, true);
if (foundItem != null)
{
listView1.Items[foundItem.Index].Selected = true;
}
That's All.
I'm trying to get a list of strings from the database.
For each string in the list i want to add a label & textbox to the page.
On button submit I want to collect the textbox value as well as the corresponding label value then save it to the database.
I need help retrieving the values from the textboxes.
What I have so far:
Panel1 is on the aspx page
protected List<string> items = MyClass.GetItems();
protected void Page_Load(object sender, EventArgs e)
{
GenerateItemsTable();
}
private void GenerateItemsTable()
{
Table table = new Table();
table.ID = "Table1";
//PlaceHolder1.Controls.Add(table);
Panel1.Controls.Add(table);
foreach (var x in items)
{
TableRow row = new TableRow();
for (int y = 0; y < 1; y++)
{
TableCell labelCell = new TableCell();
labelCell.Controls.Add(CreateLabel(x));
labelCell.CssClass = "tdLabel";
row.Cells.Add(labelCell);
TableCell txbCell = new TableCell();
txbCell.Controls.Add(CreateRadNumericTextBox(x));
txbCell.Width = 30;
row.Cells.Add(txbCell);
TableCell dataTypeCell = new TableCell();
dataTypeCell.Text = "<span style='font-size: 10px; color: #777'>(student count)</span>";
dataTypeCell.Width = 100;
row.Cells.Add(dataTypeCell);
TableCell fourthCell = new TableCell();
if (x == items[items.Count - 1])
{
RadButton rb = new RadButton();
rb.ID = "submit";
rb.Text = "Submit Guidance";
rb.Skin = "Forest";
rb.Click += new EventHandler(submit_Click);
rb.AutoPostBack = true;
fourthCell.Controls.Add(rb);
row.Cells.Add(fourthCell);
}
else
{
row.Cells.Add(fourthCell);
}
}
table.Rows.Add(row);
}
}
private RadNumericTextBox CreateRadNumericTextBox(string x)
{
RadNumericTextBox rntb = new RadNumericTextBox();
rntb.ID = x;
rntb.Width = 40;
return rntb;
}
private Label CreateLabel(string x)
{
Label l = new Label();
l.ID = "label_" + x;
l.Text = "<label>" + x + "</label>";
return l;
}
protected void submit_Click(object sender, EventArgs e)
{
foreach (Control x in FindControl("Panel1").FindControl("Table1").Controls)
{
if (x is RadNumericTextBox)
{
//how to get the data??????/
}
}
}
(thanks to those that actually read the whole post)
-----------------updated solution--------------------------------------------
I decided to change it and store the list from the db at page_load. With the list stored i loop through the list and use FindControl() to access the textboxes. Something like this..
//a couple containers
protected class ItemVal
{
public int Value { get; set; }
public string Name { get; set; }
}
protected List<ItemVal> items = new List<ItemVal>();
//get the list from that database
protected void GetItems()
{
foreach (var x in MyClass.GetItems())
{
ItemVal i = new ItemVal();
i.Name = x;
items.Add(i);
}
}
//submit
protected void submit_Click(object sender, EventArgs e)
{
foreach (var x in items)
{
RadNumericTextBox rntb = FindControl(x.Name) as RadNumericTextBox;
x.Value = (int)rntb.Value;
}
}
You need to cast x to a RadNumericTextBox and then pull out the property values you want, like this:
RadNumericTextBox theRadNumericTextBox = x as RadNumericTextBox;
string val = theRadNumericTextBox.Text;
Then for the other controls you want, you will need to put if conditions for their types, like this:
if (x is Label)
{
Label theLabel = x as Label;
string valLabel = theLabel.Text;
}
Here is the full code for the method:
protected void submit_Click(object sender, EventArgs e)
{
foreach (Control x in FindControl("Panel1").FindControl("Table1").Controls)
{
Label theLabel;
RadNumericTextBox theRadNumericTextBox;
if (x is RadNumericTextBox)
{
RadNumericTextBox theRadNumericTextBox = x as RadNumericTextBox;
string val = theRadNumericTextBox.Text;
}
if (x is Label)
{
Label theLabel = x as Label;
string valLabel = theLabel.Text;
}
// Either store up in a list or save to the database on each loop; it is recommended to store a list and send all the changes at once for a database save, but that is your choice
}
}
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.