I want to design a table user control and dynamically add the properties of custom objects. I want to populate this table with a collection object with a generic type. How can I do that ? I can not send the properties of the class to PopulateTable with its custom headers.
What I have so far (in a usercontrol) is..
<table class="datatable">
<thead>
<asp:Literal id="ltrlHeaders" runat="server" />
</thead>
<tbody>
<asp:Literal runat="server" ID="ltrlContent" />
</tbody>
</table>
public void PopulateTable(? myCollection)
{
List<string> headers = new List<string>();
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo f in fields)
{
headers.Add(f.Name);
}
// headers
StringBuilder headerString = new StringBuilder();
headerString.Append("<thead>");
headers.ForEach(delegate(string h)
{
headerString.Append(String.Format("<th>{0}</th>", h));
});
headerString.Append("</thead>");
ltrlHeaders.Text = headerString.ToString();
StringBuilder contentString = new StringBuilder();
foreach (var item in list)
{
contentString.Append("<tr>");
foreach (string fieldInfo in headers)
{
contentString.Append(String.Format("<td>{0}</td>", type.GetField(fieldInfo).GetValue(item) as string));
}
contentString.Append("</tr>");
}
ltrlContent.Text = contentString.ToString();
}
public void PopulateTable<T>(T myCollection)
Assuming that T objects can be cast to string. Or you might want:
public void PopulateTable<T>(IEnumerable<T> myCollection)
if you wanted to be able to pass a collection and know something about its interface.
A very simple method to do what you want might look like this. I've updated it with a List of Person as defined in my code. Note that I've also included a class derived from Person so you can see other properties.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Reflection;
public partial class _Default : System.Web.UI.Page
{
public class Person
{
public string Name { get; set; }
public string Title { get; set; }
}
public class WorkingPerson : Person
{
public string Job { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
List<Person> people = new List<Person>();
people.Add(new Person() {Name = "T", Title = "Mr" }) ;
people.Add(new WorkingPerson() {Name="Face", Title="Mr", Job ="Film Star" } );
TextBox textBox = new TextBox();
Controls.Add(CreateTableFromObject<Person>(people));
}
public PlaceHolder CreateTableFromObject<T>(IEnumerable<T> objectList) where T : Person
{
PlaceHolder holder = new PlaceHolder();
foreach (T thing in objectList)
{
Table table = new Table();
PropertyInfo[] properties = thing.GetType().GetProperties();
TableRow propertiesSpan = new TableRow();
propertiesSpan.Cells.Add(new TableCell() { ColumnSpan = properties.Length, Text = String.Format("Properties of {0}", thing.GetType().FullName) });
table.Rows.Add(propertiesSpan);
TableRow tableRow = new TableRow();
foreach (PropertyInfo propertyInfo in properties)
{
TableCell tc = new TableCell();
tc.Text = propertyInfo.Name;
tableRow.Cells.Add(tc);
}
table.Rows.Add(tableRow);
holder.Controls.Add(table);
}
return holder;
}
}
This effectively takes an object, uses reflection to discover its properties, and then writes them out to table cells. You can change the signature to accept your custom collection, and modify the internals to render your table.
Related
I have a solution that i need to call a console app from asp.net and need to pass variables. one variable is a generic list of a certain class.
I have tried passing it but I got error that i cannot convert a generic list to a string which is correct.
I am not sure if there is another way to pass this.
I know webservice can solve this issue. But it there any other options?
Is this possible to do or only string are possible to pass
Here is the generic list sample.
List<person> personList = new List<person>();
person p = new person();
p.name = "test";
p.age = 12;
p.birthdate = 01/01/2014
personList.add(p)
Thanks.
Ok, Console application accepts only strings. This is defined in the Main method as
static void Main(string[] args)
Since you have a complex object list it'll be bit hard to pass this information to the console application (but not impossible). There are several options for you.
Pass your values as comma separated values as a string as long as this string is not too long.
Web Services or a Web API as you suggested.
Serialize your object to an XML file and then deserialize in your console application.
Write and read from a persistent data store
UPDATE
Sample Code for Option 3 (Write to an XML file)
I wrote this sample code out of curiosity. Hope this helps to solve your issue.
ASP.Net Website
I have a button in my web page (Default.aspx) and in it's click event it writes the Person collection/ List to an XML file. Here's the code behind.
using System;
using System.IO;
using System.Xml.Serialization;
namespace WriteToConsole
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnWriteToConsole_Click(object sender, EventArgs e)
{
PersonCollection personList = new PersonCollection();
// Person 1
Person p = new Person();
p.Name = "test 1";
p.Age = 12;
p.BirthDate = DateTime.Parse("01/01/2014");
personList.Add(p);
// Person 2
Person p2 = new Person();
p2.Name = "test 2";
p2.Age = 25;
p2.BirthDate = DateTime.Parse("01/01/2014");
personList.Add(p2);
XmlSerializer serializer = new XmlSerializer(personList.GetType());
StreamWriter file = new StreamWriter(#"D:\temp\PersonCollection.xml");
serializer.Serialize(file, personList);
file.Close();
}
}
}
And, the Person.cs looks like this.
using System;
using System.Collections.Generic;
namespace WriteToConsole
{
[Serializable]
[System.Xml.Serialization.XmlRoot("PersonCollection")]
public class PersonCollection : List<Person> {
}
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime BirthDate { get; set; }
public Person()
{
this.Name = string.Empty;
this.Age = 0;
this.BirthDate = DateTime.MinValue;
}
}
}
Console Application
Then read the XML file in your console application and display the data in personList on the console.
using System;
using System.IO;
using System.Xml.Serialization;
namespace ReadInConsole
{
class Program
{
static void Main(string[] args)
{
XmlSerializer deserializer = new XmlSerializer(typeof(PersonCollection));
TextReader textReader = new StreamReader(#"D:\temp\PersonCollection.xml");
PersonCollection personList = new PersonCollection();
personList = (PersonCollection)deserializer.Deserialize(textReader);
textReader.Close();
if (personList != null && personList.Count > 0)
{
foreach (Person p in personList)
{
Console.WriteLine("Person name: {0}, Age: {1} and DOB: {2}", p.Name, p.Age, p.BirthDate.ToShortDateString());
}
Console.ReadLine();
}
}
}
}
In your console application you should have the same Person class as a modal (This is same as the Person class in your Web Application. Only the namespace is different).
using System;
using System.Collections.Generic;
namespace ReadInConsole
{
[Serializable]
[System.Xml.Serialization.XmlRoot("PersonCollection")]
public class PersonCollection : List<Person>
{
}
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime BirthDate { get; set; }
public Person()
{
this.Name = string.Empty;
this.Age = 0;
this.BirthDate = DateTime.MinValue;
}
}
}
Hope you understand the code.
I am getting this error on my DataBind Command I am trying to populate a gridview from a List using asp and c#.
The Scenario is repeater populates category links on sidebar, based on selection will populate a gridview in the main div. It worked fine when I used a dataset as my datasource but this scenario I am using generics and I don't know where the error is coming from. The List gets populated just cant databind it
public partial class Products : System.Web.UI.Page
{
string ItemNumber;
string ItemDescription;
string PrePrice;
string Size;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
PopCategories();
}
}
private List<Products> GetCategoryDetails(string HiddenField1)
{
DataTable table = new DataTable();
table = new BizLayer().grabdata(HiddenField1);
List<Products> list = new List<Products>();
foreach (DataRow dr in table.Rows)
{
Products products = new Products();
products.ItemNumber = dr["Item #"].ToString();
products.ItemDescription = dr["Item Description"].ToString();
products.PrePrice = dr["Pre Price"].ToString();
products.Size = dr["Size"].ToString();
list.Add(products);
}
return list;
}
private void PopDetails()
{
DetailsGridView.DataSource = GetCategoryDetails(HiddenField1.Value);
Error Here
DetailsGridView.DataBind();
}
protected void Repeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
//Get Command Arguement from repeater OnItemCommand
if (e.CommandName == "cmd")
{
HiddenField1.Value = (e.CommandArgument).ToString();
GetCategoryDetails(HiddenField1.Value);
PopDetails();
}
}
protected void DetailsGridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
DetailsGridView.PageIndex = e.NewPageIndex;
// DataSource
DetailsGridView.DataSource = GetCategoryDetails(HiddenField1.Value);
DetailsGridView.DataBind();
}
<asp:GridView ID="DetailsGridView" AllowPaging="true" PageSize="3" CssClass="dataGrid"
RowStyle- CssClass="chartItemStyle" AlternatingRowStyle-CssClass="chartAlternatingItemStyle"
HeaderStyle- CssClass="chartHeaderStyle" runat="server" OnPageIndexChanging="DetailsGridView_PageIndexChanging"> </asp:GridView>
public partial class Products : System.Web.UI.Page
{
public class Products2
{
public string ItemNumber { get; set; }
public string ItemDescription { get; set; }
public string PrePrice { get; set; }
public string Size { get; set; }
}
//....
Then:
List<Products2> list = new List<Products2>();
foreach (DataRow dr in table.Rows)
{
Products2 products = new Products2();
products.ItemNumber = dr["Item #"].ToString();
products.ItemDescription = dr["Item Description"].ToString();
products.PrePrice = dr["Pre Price"].ToString();
products.Size = dr["Size"].ToString();
list.Add(products);
}
Hai i'm doing one silverlight app that uses MVVM architecture.
The Scenario is this. I have one combobox and datagrid in same page.
I have use ObservableCollection to bind the values in Datagrid and in that collection i have three fields namely Fname,Sname and Dept.
I bind Dept in Combobox but if i select any one of department means that value does not update in DataGrid. ie., i have created the code in ViewModel and i use LINQ query and i have Fetched the value also in,
var semp = from s in Employees where s.Dept.Equals(Names.Dept) select s;
i need to send this semp datasource to Datagrid in View.
Datagrid Syntax is :
<my:DataGrid x:Name="McDataGrid" ItemsSource="{Binding Employees,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Margin="130,151,0,0" Height="137" VerticalAlignment="Top" RowBackground="#AA5D9324" AutoGenerateColumns="True" HorizontalAlignment="Left" Width="196">
</my:DataGrid>
Help me if u Know...
This is the ViewModel Code:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Silverlight_MVVM.Model;
using Silverlight_MVVM.Utils;
using System.Linq;
using System.Collections.Generic;
namespace Silverlight_MVVM.ViewModel
{
public class EmployeeListViewModel:INotifyPropertyChanged
{
public ObservableCollection<Employee> Employees { get; private set; }
public EmployeeListViewModel()
{
Employees = Silverlight_MVVM.DataHelper.EmployeeDataHelper.EmployeeData ();
}
private string _fname;
public string Fname
{
get
{
return _fname;
}
set
{
_fname = value;
RaisePropertyChanged("Fname");
}
}
private string _sname;
public string Sname
{
get
{
return _sname;
}
set
{
_sname = value;
RaisePropertyChanged("Sname");
}
}
private string _dept;
public string Dept
{
get
{
return _dept;
}
set
{
_dept = value;
RaisePropertyChanged("Dept");
}
}
private Employee _SelectedEmployee;
public Employee SelectedEmployee
{
get
{
return _SelectedEmployee;
}
set
{
_SelectedEmployee = value;
RaisePropertyChanged("SelectedEmployee");
}
}
private string _demp;
public string demp
{
get
{
return _demp;
}
set
{
_demp = value;
RaisePropertyChanged("demp");
}
}
private Employee _Names;
public Employee Names
{
get
{
return _Names;
}
set
{
_Names = value;
List<Employee> myList = new List<Employee>();
IEnumerable<Employee> myEnumerable = myList;
// List<Employee> listAgain = myEnumerable.ToList();
// Employees = (ObservableCollection<Employee>)Employees.Where(_ => _.Dept.Equals(Names.Dept));
RaisePropertyChanged("Names");
}
}
public void HandleShowMessage()
{
// MessageBox.Show("Hello " + Names + ",Welcome to EventTrigger for MVVM.");
}
public RelayCommand _AddEmployeeCommand;
/// <summary>
/// Returns a command that show the customer.
/// </summary>
public ICommand AddEmployeeCommand
{
get
{
if (_AddEmployeeCommand == null)
{
_AddEmployeeCommand = new RelayCommand(
param => this.AddEmployee(),
param => this.CanAddEmployee
);
}
return _AddEmployeeCommand;
}
}
public bool CanAddEmployee
{
get
{
return true;
}
}
public void AddEmployee()
{
Employee newEmployee = new Employee();
if (Names == null)
{
newEmployee.Fname = this.Fname;
newEmployee.Sname = this.Sname;
newEmployee.Dept = this.Dept;
Employees.Add(newEmployee);
//SelectedEmployee = newEmployee.ToString();
}
else //This is the event for getting selected item through combobox and the linq query fetching
{
Employees = Silverlight_MVVM.DataHelper.EmployeeDataHelper.EmployeeData();
var semp = from emp in Employees where emp.Dept.Equals(Names.Dept) select emp;
}
}
#region INotifyPropertyChanged
// [field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
I have a self-referencing table and I want to visualize it using:
<ol>
<li>
</li>
</ol>
I want to create a custom server data-bound control with templates, I have read the MSDN article:
http://msdn.microsoft.com/en-us/library/aa479322.aspx
But I think that, I have to use different aproach and inherit the
HierarchicalDataBoundControl
or implement
IHierarchicalDataSource
But I cannot find any examples, or something to read from.
Can someone point me to a book or an article, or explain it to me in steps how it needs to be done.
A summary of what is required is this:
A Control which extends HierarchicalDataSourceControl AND DataSourceControl that implements IHeirarchicalDataSource. Believe me working from the documentation provided took A LOT of trial and error but in the end it is worth it. Mines been on hold but shortly I'll complete a project using this which will be able to bind to any n depth structure + navigate it in code using Node.GetParent().GetChildren().Where .. etc. It's complicted and may be overkill for what you need and you may revert back to repeater. Given the posting length allowed at stackoverflow I can't give you full code listing (some 100k chars)
To give you a flavour of whats in my other code here is the generic IHierachicalDataSourceControl:
#region Generic Hierachical DatasourceControl
/// <summary>
/// Datasource control
/// </summary>
public class GenericHierachicalDataSourceControl<TDataContext, TNode, TEntity> : HierarchicalDataSourceControl, IHierarchicalDataSource
where TDataContext : DataContext, new()
where TNode : class,PNS.GenericLinqNodeHeirachy<TDataContext, TNode, TEntity>.IHeirachicalNode, new()
where TEntity : class,PNS.GenericLinqNodeHeirachy<TDataContext, TNode, TEntity>.IHeirachyNodeEntity, new()
{
NodeDataSourceView view;
protected override HierarchicalDataSourceView GetHierarchicalView(string viewPath)
{
view = new NodeDataSourceView(viewPath);
return view;
}
public class NodeDataSourceView : HierarchicalDataSourceView
{
private string _viewPath;
public NodeDataSourceView(string viewPath)
{
_viewPath = viewPath;
}
public override IHierarchicalEnumerable Select()
{
var hierarchy = new HierarchicalEnumerable();
List<TNode> topNodes;
if (String.IsNullOrEmpty(_viewPath))
{
//get all top level nodes (ones without parents)
topNodes = GenericLinqNodeHeirachy<TDataContext, TNode, TEntity>.NodesDAL.GetTopLevelNodes().ToList();
}
else
{
//get the last node in the path
string[] nodes = _viewPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
topNodes = new List<TNode>();
topNodes.Add(GenericLinqNodeHeirachy<TDataContext, TNode, TEntity>.NodesDAL.GetNode(nodes[nodes.Length - 1]));
}
//for each node in the path
foreach (var node in topNodes)
{
if (node.Entity != null)
{
hierarchy.Add(node.Entity);
}
}
return hierarchy;
}
}
public class HierarchicalEnumerable : List<TEntity>, IHierarchicalEnumerable
{
public HierarchicalEnumerable()
: base()
{
}
public IHierarchyData GetHierarchyData(object enumeratedItem)
{
return enumeratedItem as IHierarchyData;
}
}
}
and another part:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web.UI.HtmlControls;
namespace BootstrapProject.CodeBase
{
public class GenericHierarchicalDataboundControl : HierarchicalDataBoundControl
{
private string _textField;
public string TextField
{
get { return _textField; }
set { _textField = value; }
}
protected override string TagName
{
get
{
return "div";
}
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
protected override void CreateChildControls()
{
if (null != Page && Page.IsPostBack && null != ViewState["_!DataBound"])
{
this.RequiresDataBinding = true;
this.EnsureDataBound();
}
}
protected override void PerformDataBinding()
{
IHierarchicalEnumerable dataSource = GetData(string.Empty).Select();
this.PerformDataBinding(0, this.Controls, dataSource);
this.MarkAsDataBound();
}
protected virtual void PerformDataBinding(int level, ControlCollection controls, IHierarchicalEnumerable dataSource)
{
if (null != dataSource)
{
//controls.Clear();
HtmlGenericControl ul = new HtmlGenericControl("ul");
foreach (object value in dataSource)
{
var itemData = dataSource.GetHierarchyData(value);
Control item = CreateAndBindControl(level, value);
ul.Controls.Add(item);
var data = dataSource.GetHierarchyData(value);
if (data != null && data.HasChildren)
{
IHierarchicalEnumerable childData = data.GetChildren();
PerformDataBinding(1 + level, item.Controls, childData);
}
controls.Add(ul);
}
}
}
protected virtual Control CreateAndBindControl(int level, object dataItem)
{
HtmlGenericControl li = new HtmlGenericControl("li");
string text = String.Empty;
if (!String.IsNullOrEmpty(TextField))
{
text = DataBinder.GetPropertyValue(dataItem, TextField).ToString();
}
else
{
text = dataItem.ToString();
}
li.Attributes.Add("rel", text);
li.Controls.Add(new HyperLink { Text = text });
return li;
}
}
}
And finally:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using BootstrapProject.CodeBase.DAL;
using PNS;
namespace BootstrapProject.CodeBase
{
public class NodeDataSourceControl : HierarchicalDataSourceControl, IHierarchicalDataSource
{
NodeDataSourceView view;
protected override HierarchicalDataSourceView GetHierarchicalView(string viewPath)
{
view = new NodeDataSourceView(viewPath);
return view;
}
}
public class NodeDataSourceView : HierarchicalDataSourceView
{
private string _viewPath;
public NodeDataSourceView(string viewPath)
{
_viewPath = viewPath;
}
public override IHierarchicalEnumerable Select()
{
var hierarchy = new CMSPageHierarchicalEnumerable();
List<DAL.Node> topNodes;
if (String.IsNullOrEmpty(_viewPath))
{
//get all top level nodes (ones without parents)
topNodes = CMS.NodesDAL.GetTopLevelNodes().ToList();
}
else
{
//get the last node in the path
string[] nodes = _viewPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
topNodes = new List<DAL.Node>();
topNodes.AddRange(CMS.NodesDAL.GetNode(nodes[nodes.Length - 1]).NodeChildren);
}
//for each node in the path
foreach (var node in topNodes)
{
if (node.Page != null)
{
hierarchy.Add(node.Page);
}
}
return hierarchy;
}
}
}
I am adding a WebForm from which I would like to resolve routes to URLs. For example, in MVC I would just use
return RedirectToAction("Action", "Controller");
So, if you have a way of getting to that same URL from a WebForm in the same application, it would be appreciated.
Try something like this in your Webform:
<% var requestContext = new System.Web.Routing.RequestContext(
new HttpContextWrapper(HttpContext.Current),
new System.Web.Routing.RouteData());
var urlHelper = new System.Web.Mvc.UrlHelper(requestContext); %>
<%= urlHelper.RouteUrl(new { controller = "Controller", action = "Action" }) %>
Revised version of the code above for PageCommon ... as it currently is it breaks.
public static class MvcPages{
public static UrlHelper GetUrlHelper(this System.Web.UI.Control c)
{
var helper = new System.Web.Mvc.UrlHelper(c.Page.Request.RequestContext);
return helper;
}
public static HtmlHelper GetHtmlHelper(this System.Web.UI.Control c)
{
var httpContext = new HttpContextWrapper(HttpContext.Current);
var controllerContext = new ControllerContext(httpContext, new RouteData(), new DummyController());
var viewContext = new ViewContext(controllerContext, new WebFormView(controllerContext, "View"), new ViewDataDictionary(), new TempDataDictionary(), TextWriter.Null);
var helper = new HtmlHelper(viewContext, new ViewDataBag());
return helper;
}
private class ViewDataBag : IViewDataContainer
{
ViewDataDictionary vdd = new ViewDataDictionary();
public ViewDataDictionary ViewData
{
get
{
return vdd;
}
set
{
vdd = value;
}
}
}
private class DummyController : Controller
{
}
}
If you want to stay away from any MVC dependencies then this is the solution I came up with. It's very close to the accepted answer. I have a class my webform pages inherit and this UrlHelper is available in the ASPX pages.
using System.Net.Http;
using System.Web;
using System.Web.Http.Routing;
public class ClassOtherPagesInherit {
public UrlHelper Url = new UrlHelper(new HttpRequestMessage(new HttpMethod(HttpContext.Current.Request.HttpMethod), HttpContext.Current.Request.Url));
}
Then you can call this UrlHelper object like this
<%Url.Route("string", new {}) %>
For those looking for an actual HtmlHelper or a cleaner way to use the urlHelper in a page:
public static class PageCommon
{
public static System.Web.Mvc.UrlHelper GetUrlHelper(this System.Web.UI.Control c)
{
var helper = new System.Web.Mvc.UrlHelper(c.Page.Request.RequestContext);
return helper;
}
class ViewDataBag : IViewDataContainer
{
ViewDataDictionary vdd = new ViewDataDictionary();
public ViewDataDictionary ViewData
{
get
{
return vdd;
}
set
{
vdd = value;
}
}
}
public static System.Web.Mvc.HtmlHelper GetHtmlHelper(this System.Web.UI.Control c)
{
var v = new System.Web.Mvc.ViewContext();
var helper = new System.Web.Mvc.HtmlHelper(v, new ViewDataBag());
return helper;
}
}