asp.net databound menu multilevel - c#

I am currently using an asp.net menu control to load from a table parent/child items. The problem I am having is that if the child has another child. My code is kindof static in that sense and I can't seem to find a better or "the" way to do it. I have seen sitemap as datasources but i don't need a sitemap and feel that would just be overkill for what I need to achieve.
foreach (ClassName option in list)
{
MenuItem module = new MenuItem(option.Description.ToLower(), "", "", option.Url + "?option=" + option.Optionid);
module.Selectable = true;
navigation.Items.Add(module);
//this is my second level
foreach (ClassName child in listfromparent(option.Optionid))
{
MenuItem childmenu = new MenuItem(child.Description.ToLower(), "", "", child.Url + "?option=" + child.Optionid);
module.ChildItems.Add(childmenu);
}
}
as you can see this works but for 2 levels :(
and of course i could put another childlevel inside child to create the 3rd level but what if there is a 4th, 5th? So that's why I need it to do it itself. I noticed treeview has onpopulate but apparently Menu doesn't. Thanks in advance.

Here's one way you could do it.
Represent parent/child relationship in your table with an adjacency list
Map that adjacency list into a tree structure
Convert that tree structure into your structure of menu items
Maybe you could skip that middle step and map the adjacency list straight to a tree of MenuItems, maybe with some extension methods on MenuItem.
But anyway...
Default.aspx
<%# Page Language="C#" Inherits="MenuTreeDemo.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head runat="server">
<title>Default</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Menu ID="MyMenu" runat="server" StaticDisplayLevels="3" />
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Collections.Generic;
namespace MenuTreeDemo
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
MenuNode root = ConvertTableToTree(GetTreeTable());
foreach (MenuNode topLevelNode in root.Children)
{
MyMenu.Items.Add(topLevelNode.ToMenuItem()); // Visits all nodes in the tree.
}
}
}
// The menu tree as an adjacency list in a table.
static DataTable GetTreeTable()
{
DataTable table = new DataTable();
table.Columns.Add("Id", typeof(int));
table.Columns.Add("Description", typeof(string));
table.Columns.Add("Url", typeof(string));
table.Columns.Add("ParentId", typeof(int));
table.Rows.Add(1, "TopMenu1", "/foo.html", 0);
table.Rows.Add(2, "SubMenu1.1", "/baz.html", 1);
table.Rows.Add(3, "SubMenu1.2", "/barry.html", 1);
table.Rows.Add(4, "SubMenu1.2.1", "/skeet.html", 3);
table.Rows.Add(5, "TopMenu2", "/bar.html", 0);
table.Rows.Add(6, "TopMenu3", "/bar.html", 0);
table.Rows.Add(7, "SubMenu3.1", "/ack.html", 6);
return table;
}
// See e.g. http://stackoverflow.com/questions/2654627/most-efficient-way-of-creating-tree-from-adjacency-list
// Assuming table is ordered.
static MenuNode ConvertTableToTree(DataTable table)
{
var map = new Dictionary<int, MenuNode>();
map[0] = new MenuNode() { Id = 0 }; // root node
foreach (DataRow row in table.Rows)
{
int nodeId = int.Parse(row["Id"].ToString());
int parentId = int.Parse(row["ParentId"].ToString());
MenuNode newNode = MenuNodeFromDataRow(row);
map[parentId].Children.Add(newNode);
map[nodeId] = newNode;
}
return map[0]; // root node
}
static MenuNode MenuNodeFromDataRow(DataRow row)
{
int nodeId = int.Parse(row["Id"].ToString());
int parentId = int.Parse(row["ParentId"].ToString());
string description = row["Description"].ToString();
string url = row["Url"].ToString();
return new MenuNode() { Id=nodeId, ParentId=parentId, Description=description, Url=url };
}
}
}
MenuNode.cs
using System;
using System.Collections.Generic;
using System.Web.UI.WebControls;
namespace MenuTreeDemo
{
public class MenuNode
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Description { get; set; }
public string Url { get; set; }
public List<MenuNode> Children { get; set; }
public MenuNode ()
{
Children = new List<MenuNode>();
}
// Will visit all descendants and turn them into menu items.
public MenuItem ToMenuItem()
{
MenuItem item = new MenuItem(Description) { NavigateUrl=Url };
foreach (MenuNode child in Children)
{
item.ChildItems.Add(child.ToMenuItem());
}
return item;
}
}
}

Related

Using listbox, how to find that exact object?

I think this is a somewhat easy answer but Im not able to understand how to do it.
I have an object (lets call it A) with a list of other objects (for example places)
So Im creating a Webapp and in that page I have a listbox of places (Im using the name of the places (string) as a unique id). The question is when I select an item from that list, how do I find that item in the list of places?
for example:
page.aspx:
<p style="margin-left: 40px">
Select place:</p>
<p style="margin-left: 40px">
<asp:ListBox ID="listplace" runat="server"></asp:ListBox>
</p>
page.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
listplace.DataSource = A.listOfPlaces;
listplace.DataBind();
}
}
Hopefully this can help you:
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
namespace ListBox_42581647
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Doit();
}
private void Doit()
{
ListBox lb = new ListBox();//create a listbox
lb.Items.Add(new aPlace { placename = "TheBar", placeCoolFactor = "booze" });//add something to the listbox
lb.Items.Add(new aPlace { placename = "TheHouse", placeCoolFactor = "bowl"});//add something to the listbox
lb.Items.Add(new aPlace { placename = "ThePark", placeCoolFactor = "dogs" });//add something to the listbox
lb.SelectedItem = lb.Items[1];//lets fake a selection
var theSelectedPlace = lb.SelectedItem;//the actual item selected
var theSelectedPlaceName = ((aPlace)lb.SelectedItem).placename;//the selected item place name
var theSelectedPlaceCoolFactor = ((aPlace)lb.SelectedItem).placeCoolFactor;//the selected item place cool factor
//now I'll create your (lets call it A)
List<aPlace> parallelList = new List<aPlace>();//lets call it A
parallelList.Add((aPlace)lb.Items[0]);//This list contains the same items your ListBox contains
parallelList.Add((aPlace)lb.Items[1]);//This list contains the same items your ListBox contains
parallelList.Add((aPlace)lb.Items[2]);//This list contains the same items your ListBox contains
//find the selected by matching the selected Placename
aPlace theChosenPlace = parallelList.Where(p => p.placename == theSelectedPlaceName).FirstOrDefault();
//find the selected by matching the actual item
aPlace theChosenPlace2 = parallelList.Where(p => p == theSelectedPlace).FirstOrDefault();
}
}
public class aPlace
{
public string placename { get; set; }
public string placeCoolFactor { get; set; }
}
}
You can try:
string currPlace = listplace.SelectedItem.ToString();
string place = A.listOfPlaces.Where
(x => x.Contains(currPlace)).FirstOrDefault();

Is there any way to access fields of 'super' class (not inherited)

Title may be misleading as I had some trouble searching and even creating a proper question, so let me give a real problem I'm struggling with:
I have a Graph class. Since graphs need nodes and edges I created two additional classes Node (vertex) and Edge. My structure looks like this:
class Graph
{
List<Node> nodes;
List<Edge> edges;
public Graph( ... ) { /* populate lists */ }
}
class Node { ... }
class Edge { ... }
I wrote some methods for Node class, one is particularly problematic for me. Signature:
public List<Node> GetNeighbours(List<Edge> edges) { ... }
Pretty standard. Given a graph I ask a node: how many neighbours do you have? I need list of edges to resolve it.
How can I refactor this code so that I can use Graph properties/fields inside instead of passing a list of edges every time? Is something like this possible:
public List<Node> GetNeighbours()
{
// ...
foreach(edge in *BASE*.edges) { ... }
}
I know that I can't use the base keyword because I don't want any inheritance here (why would a node have to inherit from graph?!) and nested classes seem not to help me as well (no access to "parent's" fields).
This code is working right now, but I feel it's not elegant and I'd like to experience a proper solution.
Pass a reference to the parent class in the Graph constructor.
Something like:
class Graph
{
private ParentType parent;
public void Graph(ref ParentType parent)
{
this.parent = parent;
}
}
Then, in the GetNeighbours method (assuming the ParentType has an Edges collection property):
public List<Node> GetNeighbours()
{
// ...
foreach(var edge in parent.Edges) { ... }
}
From this description of what you're trying to do:
Given a graph I ask a node: how many neighbours do you have?
Are you sure that this should be a method of a Node? Since Graph contains the Nodes and Edges perhaps this method is better off in Graph.
public List<Node> GetNeighbours(Node node)
{
if(!nodes.Contains(node)
{
return new List<Node>(); //No neighbors. Return an empty list.
}
// Find and return the neighbors. This method is in Graph so it
// has access to all of Graph's internals.
}
My reasoning is that since in a sense Graph is a parent and it contains Nodes, Node does not need to know about Graph. Its purpose (Single Responsibility) is complete without any references to Graph.
I would have a method like Graph.AddNodes() or Graph.AddEdges() on Graph so that this is a central place to make sure that all Nodes (and/or Edges) have the reference that it needs. I'm thinking something like this, depending on the model of Node and Edge for you.
class Graph
{
List<Node> nodes;
List<Edge> edges;
public Graph( ... ) { /* populate lists */ }
public void AddEdges(params Edge[] edges) {
foreach (var edge in edges) {
edge.Node1.Parent = this;
edge.Node2.Parent = this;
}
}
}
class Node {
public Graph Parent { get; set; }
public List<Node> GetNeighbours()
{
var neighbors = new List<Node>();
foreach(var edge in parent.Edges) {
if (edge.Node1 == this && !neighbors.Contains(edge.Node2)) {
neighbors.Add(edge.Node2);
}
else if (edge.Node2 == this && !neighbors.Contains(edge.Node1)) {
neighbors.Add(edge.Node1);
}
}
}
}
class Edge {
public Node Node1 { get; set; }
public Node Node2 { get; set; }
}
Here is an alternative approach. Instead of passing the parent reference, you could make each edge aware of the nodes on each end. And make each node aware of the edges connected to them.
A massive advantage of this is that you do not need enumerate possibly massive amounts of nodes/edges to find what you need. You already have what you need so it is much faster.
Here is quick sample of the approach I described along with some tests:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GraphModelTest
{
class Program
{
static void Main(string[] args)
{
TestA();
TestB();
TestC();
}
private static void TestC()
{
//A <-> B
//| |
//D <-> C
Node a = new Node("a");
Node b = new Node("b");
Node c = new Node("c");
Node d = new Node("d");
Edge ab = a.ConnectTo(b);
Edge bc = b.ConnectTo(c);
Edge cd = c.ConnectTo(d);
Edge da = d.ConnectTo(a);
Graph g = new Graph();
g.Nodes.Add(a);
g.Nodes.Add(b);
g.Nodes.Add(c);
g.Nodes.Add(d);
g.Edges.Add(ab);
g.Edges.Add(bc);
g.Edges.Add(cd);
g.Edges.Add(da);
Console.WriteLine(g.ToString());
Console.WriteLine("Neighbours of B");
foreach (Node n in b.GetNeighbours())
{
Console.WriteLine(n.ToString());
}
Console.WriteLine("Neighbours of D");
foreach (Node n in d.GetNeighbours())
{
Console.WriteLine(n.ToString());
}
}
private static void TestB()
{
//A <-> B <-> C
Node a = new Node("a");
Node b = new Node("b");
Edge ab = a.ConnectTo(b);
Node c = new Node("c");
Edge bc = b.ConnectTo(c);
Graph g = new Graph();
g.Nodes.Add(a);
g.Nodes.Add(b);
g.Nodes.Add(c);
g.Edges.Add(ab);
g.Edges.Add(bc);
Console.WriteLine(g.ToString());
Console.WriteLine("Neighbours of B");
foreach (Node n in b.GetNeighbours())
{
Console.WriteLine(n.ToString());
}
}
private static void TestA()
{
//A <-> B
Node a = new Node("a");
Node b = new Node("b");
Edge ab = a.ConnectTo(b);
Graph g = new Graph();
g.Nodes.Add(a);
g.Nodes.Add(b);
g.Edges.Add(ab);
Console.WriteLine(g.ToString());
}
}
class Edge
{
public Edge(string name, Node a, Node b)
{
Name = name;
A = a;
B = b;
}
public Node A { get; private set; }
public Node B { get; private set; }
public string Name { get; private set; }
public override string ToString() => $"{Name}";
}
class Node
{
public Node(string name)
{
Name = name;
connectedEdges = new List<Edge>();
}
public string Name { get; private set; }
private ICollection<Edge> connectedEdges;
public IEnumerable<Edge> ConnectedEdges
{
get
{
return connectedEdges.AsEnumerable();
}
}
public void AddConnectedEdge(Edge e)
{
connectedEdges.Add(e);
}
public Edge ConnectTo(Node n)
{
//Create the edge with references to nodes
Edge e = new Edge($"{Name} <-> {n.Name}", this, n);
//Add edge reference to this node
AddConnectedEdge(e);
//Add edge reference to the other node
n.AddConnectedEdge(e);
return e;
}
public IEnumerable<Node> GetNeighbours()
{
foreach (Edge e in ConnectedEdges)
{
//Have to figure which one is not this node
Node node = e.A != this ? e.A : e.B;
yield return node;
}
}
public override string ToString() => $"{Name}";
}
class Graph
{
public Graph()
{
Nodes = new List<Node>();
Edges = new List<Edge>();
}
public ICollection<Node> Nodes { get; set; }
public ICollection<Edge> Edges { get; set; }
public override string ToString()
{
StringBuilder str = new StringBuilder();
str.AppendLine("Graph:");
str.AppendLine("Nodes:");
foreach (Node n in Nodes)
{
str.AppendLine(n.ToString());
}
str.AppendLine("Edges:");
foreach (Edge e in Edges)
{
str.AppendLine(e.ToString());
}
return str.ToString();
}
}
}

Get specific dataTable cell values in View (ASP.NET MVC)

I am trying to find a way to access specific cells in a DataTable in View. The DataTable was created in controller.
Code in conroller:
[ChildActionOnly]
public ActionResult _ls()
{
var getXMLlivescore = new HtmlDocument();
getXMLlivescore.Load("D://lscopy.xml");
DataTable matchTable = new DataTable();
matchTable.Columns.Add("put2forEventOr1", typeof(int));
matchTable.Columns.Add("country", typeof(string));
...
matchTable.Columns.Add("min", typeof(string));
matchTable.Columns.Add("extramin", typeof(string));
foreach (HtmlNode match in category.SelectNodes(".//match")){
//code to get xml tags
matchTable.Rows.Add(put2forEventOr1, country, ....., min, extramin);
}
return PartialView(matchTable);
}
and the partialView code:
<table>
#foreach (DataRow row in Model.Rows)
{
//get cell in row[0]
#if (row[0] == 3){
do some work
}
}
</table>
How can I iterate through DataTable cells in view and get specific cells?
I really don't understand why do you need to use a DataTable. You can always create a class with structure you need. It will be much easier to us simple POCO's in your views.
You haven't provided your XML so I made some examples for very simple version:
<Elements>
<Element>
<Country>Peru</Country>
<Min>20</Min>
</Element>
<Element>
<Country>Armenia</Country>
<Min>9</Min>
</Element>
</Elements>
For such XML you can create a class that will represent an Element:
public class Element
{
public string Country { get; set; }
public int Min { get; set; }
public string NotXmlProperty { get; set; }
}
And then you can use your method of reading XML or for example this one:
var xDoc = XDocument.Load(xmlFilePath);
IEnumerable<Element> elements = xDoc
.Descendants("Element")
.Select(x => new Element
{
Country = x.Element("Country").Value,
Min = Convert.ToInt32(x.Element("Min").Value),
NotXmlProperty = "Value"
});
After that accessing your data in the view should be very simple:
#model IEnumerable<Element>
<table>
#foreach(var element in Model)
{
<tr>
<td>#element.Country</td>
<td>#element.Min</td>
<td>#element.NotXmlProperty</td>
</tr>
}
<table>

Problem with threads(and redirect) while searching list with queryString

EDIT: Have updated the code, The remaining problem is that i need to wait for the "The thread '' has exited with code 0" to fire before I can make a new search. If i dont the button events fire, but not the page_Load. Is there a way to handle it?
I am creating a aspx webpage (localhost) to study for a certification. The page contains a grindview that presents data, a search box and a button to summit searches. I use Linq to get the result from the database, querystring to store the search while post-back and the Cache to store the non searched result. The page loads slow the first time and load fast after a refresh (so the caching probably works). The Linq query also gives the expected result and the url on the site is in accord with what the user type in the textbox.
Public void Button_Search(object sender, EventArgs e)
protected void Button1_Click(object sender, EventArgs e)
{
Debug.WriteLine("Button Pressed");
String s = ("~/Matches.aspx");
if (TextBox1.Text != null && TextBox1.Text != "")
{
s = (s + "?Search=" +TextBox1.Text);
}
Debug.WriteLine("Redirction adress:" +s);
Response.Redirect(s, false);
Context.ApplicationInstance.CompleteRequest();
}
then my page_Load function
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Debug.WriteLine("---------------");
Debug.WriteLine("PageLoad");
if (Request.QueryString["Search"] != null)
{
Debug.WriteLine("SerchValueFound");
search = Request.QueryString["Search"];
}
if (Cache["MatchesCache"] == null)
{
Debug.WriteLine("Cache Loading");
using (ConnectionToDBDataContext context = new ConnectionToDBDataContext())
{
try
{
var lista = (from game in context.Games
join home in context.Teams on game.HomeTeamID equals home.TeamID
join away in context.Teams on game.AwayTeamID equals away.TeamID
join arenaName in context.Arenas on game.ArenaID equals arenaName.ArenaID
select new Match
{
MatchID = (int)game.MatchID,
Date = (int)game.Date,
TimeStart = game.TimeStart,
HomeTeam = home.TeamName,
AwayTeam = away.TeamName,
HomeGoals = (int)game.HomeTeamGoals,
AwayGoals = (int)game.AwayTeamGoals,
Arena = arenaName.ArenaName,
Line = "-"
});
list = lista.ToList();
Cache.Insert("MatchesCache", list, null, DateTime.Now.AddDays(1), System.Web.Caching.Cache.NoSlidingExpiration);
}
catch { Debug.WriteLine("Failed to update cache"); }
}
}
list = (List<Match>)Cache["MatchesCache"];
Debug.WriteLine("List loaded from Cache");
if (search != null && search != "")
{
Debug.WriteLine("Search is beeing done");
List<Match> newList = new List<Match>();
foreach (Match m in list)
{
if (m.AwayTeam.Contains(search) || m.HomeTeam.Contains(search))
{
newList.Add(m);
}
}
list = newList;
}
GridView1.DataSource = list;
GridView1.DataBind();
search = "";
Debug.WriteLine("---------------");
}
Have you tried putting some debug code in there to check whether the list of Match objects are being retrieved from the Cache vs the DB, without using breakpoints?
---- Update ----
I've taken your code (except for the database bit) and put it into an ASP.NET 4.0 web application, and it all seems to be working fine...
Here is the aspx page:
<%# Page Title="Home Page" Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
Inherits="WebApplication1._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head id="Head1" runat="server">
<title></title>
</head>
<body>
<form id="Form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>
</div>
</form>
</body>
</html>
And here is the code-behind for it:
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace WebApplication1
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
List<Match> list;
string search = null;
Debug.WriteLine("---------------");
Debug.WriteLine("PageLoad");
if (Request.QueryString["Search"] != null)
{
Debug.WriteLine("SerchValueFound");
search = Request.QueryString["Search"];
}
if (Cache["MatchesCache"] == null)
{
Debug.WriteLine("Cache Loading");
try
{
list = new List<Match>
{
new Match{MatchId = 1, Date = 1, TimeStart = 1, AwayTeam = "the flying fijians", HomeTeam = "wallabies"},
new Match{MatchId = 2, Date = 1, TimeStart = 1, AwayTeam = "wallabies", HomeTeam = "all blacks"},
new Match{MatchId = 3, Date = 1, TimeStart = 1, AwayTeam = "springboks", HomeTeam = "all blacks"},
};
Cache.Insert("MatchesCache", list, null, DateTime.Now.AddDays(1), System.Web.Caching.Cache.NoSlidingExpiration);
}
catch
{
Debug.WriteLine("Failed to update cache");
}
}
list = (List<Match>)Cache["MatchesCache"];
Debug.WriteLine("List loaded from Cache");
if (!string.IsNullOrEmpty(search))
{
Debug.WriteLine("Search is beeing done");
var newList = new List<Match>();
foreach (var m in list)
{
if (m.AwayTeam.Contains(search) || m.HomeTeam.Contains(search))
{
newList.Add(m);
}
}
list = newList;
}
GridView1.DataSource = list;
GridView1.DataBind();
Debug.WriteLine("---------------");
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Debug.WriteLine("Button Pressed");
var s = ("~/Default.aspx");
if (!string.IsNullOrEmpty(TextBox1.Text))
{
s = (s + "?Search=" + TextBox1.Text);
}
Debug.WriteLine("Redirction adress:" + s);
Response.Redirect(s, false);
}
}
public class Match
{
public int MatchId { get; set; }
public int Date { get; set; }
public int TimeStart { get; set; }
public string HomeTeam { get; set; }
public string AwayTeam { get; set; }
}
}
Perhaps it is a problem with your ConnectionToDBDataContext?

Access Unordered list control id's in codebehind

I have ul elements in usercontrol like below
<u><ul>
<li id="liMiddle" class="off">
<a href="#">One
</a>
<ul id="One" runat="server">
</ul>
</li>
<li id="liMiddle" class="off">
<a href="#">Two
</a>
<ul id="Two" runat="server">
</ul>
</li>
<li id="liMiddle" class="off">
<a href="#">Three
</a>
<ul id="Three" runat="server">
</ul>
foreach (SPWeb supersubsite in subsites)
{
int i = 0;
HtmlGenericControl li = new HtmlGenericControl("li");
CurrentTab.Controls.Add(li);
HtmlGenericControl anchor = new HtmlGenericControl("a");
anchor.Attributes.Add("href", supersubsite.Url);
anchor.InnerText = supersubsite.Title;
li.Controls.Add(anchor);
} </u>
Here in each loop Current tab should be changed to corresponding next ul id. How to access it?
I have to generate 'li' elements dynamically under above ul's. So I need to access all the 'ul' id's one by one in the codebehind.
Can anybody tell me the solution?
I would implement a collection in codebehind where you can add listitems by presenter/controller or in page_load/click_events/..
And then simple looping in an ASP.NET MVC style..
// YourPage.aspx.cs:
private readonly ICollection<string> items = new Collection<string> { "one", "two" };
// YourPage.aspx
<ul>
<% foreach (var stringItem in this.items) { %>
<li><%= stringItem %></li>
<% } %>
</ul>
You could make your own ListBuilder class with an Add method that takes a custom UserListItem class/struct. Inside of these classes you could use TagBuilder to create the LI and UL tags using the custom class/struct you built for the UserListItem. You could store a static dictionary of current Lists you're building in that custom ListBuilder class, using an user defined key.
That way if you needed to get at your List, or ListItems dynamically from the code behind, you could just use your ListBuilder and reference them by ID.
Code below is a bit rough, but here's the general idea:
using System.Collections.Generic;
using System.Web.Mvc;
using System;
public class UserList
{
public List<UserListItem> UserListItems = new List<UserListItem>();
public void Add(UserListItem item)
{
UserListItems.Add(item);
}
}
public class UserListItem
{
public string Name { get; set; }
}
public class ListBuilder
{
static Dictionary<string, UserList> userLists = new Dictionary<string, UserList>();
public ListBuilder(string listId)
{
UserList newList = new UserList();
newList.Add(new UserListItem() { Name = "Item1" });
newList.Add(new UserListItem() { Name = "Item2" });
userLists.Add(listId, newList);
}
public static UserList GetList(string listId)
{
return userLists[listId];
}
public static string BuildList(string listId)
{
UserList list = userLists[listId];
TagBuilder listTagBuilder = new TagBuilder("ul");
list.UserListItems.ForEach(listItem =>
{
TagBuilder listItemTagBuilder = new TagBuilder("li") { InnerHtml = listItem.Name };
listTagBuilder.InnerHtml += listItemTagBuilder.ToString(TagRenderMode.Normal);
});
return listTagBuilder.ToString(TagRenderMode.Normal);
}
}

Categories