Nhibernate mapping in asp .net - asp.net

I am a newbie in NHibernate.I am facing problem in mapping file.I have 2 tables Fetures and Priority.
Feature FeatureID(PK),FeatureName,PriorityID(FK)
Priorty PriorityID(PK),PriorityName
I want to bind a grid to Feature table but but grid should contain PriorityName rather than PriorityID.
I have tried one-to-one,many-to-one and bag.
Please help me how can write mapping file so that I can get PriorityName for particular PriorityID in Feature class.
I know it is a very simple question.But nothing worked for me. After lots of googling I am posting here.
Please help me
Thanks in Advance

Here's a sample using Fluent NHibernate and SQLite:
using System.Data;
using System.IO;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using NHibernate;
public class Priority
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class Feature
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Priority Priority { get; set; }
}
public class PriorityMap : ClassMap<Priority>
{
public PriorityMap()
{
WithTable("Priority");
Id(x => x.Id, "PriorityID");
Map(x => x.Name, "PriorityName");
}
}
public class FeatureMap : ClassMap<Feature>
{
public FeatureMap()
{
WithTable("Feature");
Id(x => x.Id, "FeatureID");
Map(x => x.Name, "FeatureName");
References<Priority>(x => x.Priority, "PriorityID");
}
}
public static class SessionFactoryEx
{
private const string _dbFile = #"C:\data.db3";
static SessionFactoryEx()
{
if (File.Exists(_dbFile))
{
File.Delete(_dbFile);
}
using (var factory = SessionFactoryEx.GetSessionFactory())
using (var connection = factory.ConnectionProvider.GetConnection())
{
SessionFactoryEx.ExecuteQuery("create table Priority(PriorityID int, PriorityName string)", connection);
SessionFactoryEx.ExecuteQuery("create table Feature(FeatureID int, FeatureName string, PriorityID int)", connection);
SessionFactoryEx.ExecuteQuery("insert into Priority (PriorityID, PriorityName) values (1, 'p1')", connection);
SessionFactoryEx.ExecuteQuery("insert into Feature (FeatureID, FeatureName, PriorityID) values (1, 'f1', 1)", connection);
SessionFactoryEx.ExecuteQuery("insert into Feature (FeatureID, FeatureName, PriorityID) values (2, 'f2', 1)", connection);
SessionFactoryEx.ExecuteQuery("insert into Feature (FeatureID, FeatureName, PriorityID) values (3, 'f3', 1)", connection);
}
}
private static ISessionFactory _sessionFactory = null;
public static ISessionFactory GetSessionFactory()
{
if (_sessionFactory == null)
{
_sessionFactory = CreateSessionFactory();
}
return _sessionFactory;
}
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(
SQLiteConfiguration.Standard.UsingFile(_dbFile).ShowSql()
)
.Mappings(
m => m.FluentMappings.AddFromAssemblyOf<Priority>()
).BuildSessionFactory();
}
public static void ExecuteQuery(string sql, IDbConnection connection)
{
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}
}
And in your ASPX page you can bind data:
<%# Page Language="C#" AutoEventWireup="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
using (var factory = SessionFactoryEx.GetSessionFactory())
using (var session = factory.OpenSession())
using (var tx = session.BeginTransaction())
{
var features = session.CreateCriteria(typeof(Feature)).List<Feature>();
featuresGrid.DataSource = features;
featuresGrid.DataBind();
}
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="featuresGrid" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Id">
<ItemTemplate>
<%# Eval("Id") %>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<%# Eval("Name") %>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Priority Name">
<ItemTemplate>
<%# Eval("Priority.Name") %>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>

Related

Using ASPxComboBox with ASPxGridView, need to set initial value

I'm trying to use ASPxGridView to display a list of ASPxComboBox controls. Both the rows in the grid and the list of options in the combo boxes are populated from code. I'm having problems setting the initial value of the combo boxes.
I'm looking for it to look similar to the image below.
As you can see in the screenshot, I have been able to get both the grid view & the combo boxes to populate, but I can't figure out how to set the initial values of the combo boxes.
In the Init event of the inner combo boxes, there's no obvious property to retrieve the bound object.
I did find a couple other questions on StackOverflow, for which the answer was to add a bound property to the combo box. However, adding SelectedIndex='<%# Bind("Level") %>' to the declaration for InnerCombo gave me the error "Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control."
Here's what I have so far:
Testing.aspx:
<%# Page Title="" Language="C#" MasterPageFile="~/Light.master"
AutoEventWireup="true" CodeBehind="Testing.aspx.cs" Inherits="MyProject.Testing" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<dx:ASPxGridView ID="MyGridView" runat="server" KeyFieldName="Name">
<Columns>
<dx:GridViewDataColumn FieldName="Name" />
<dx:GridViewDataColumn FieldName="Level">
<DataItemTemplate>
<dx:ASPxComboBox
runat="server"
ID="InnerCombo"
ValueField="ID"
TextField="Desc"
ValueType="System.Int32"
OnInit="InnerCombo_Init" />
</DataItemTemplate>
</dx:GridViewDataColumn>
</Columns>
</dx:ASPxGridView>
<dx:ASPxButton runat="server" ID="btnSubmit" Text="Submit" OnClick="btnSubmit_Click" />
</asp:Content>
Testing.aspx.cs:
public partial class Testing : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.MyGridView.DataSource = GetDefaultSettings();
this.MyGridView.DataBind();
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
Debug.WriteLine("btnSubmit_Click");
for (int i = 0; i < MyGridView.VisibleRowCount; i++)
{
object[] row = (object[])MyGridView.GetRowValues(i, "Name", "Value");
// row[1] is null, but we can get the data by finding the combo box itself.
GridViewDataColumn col = (GridViewDataColumn)MyGridView.Columns["Value"];
ASPxComboBox innerCombo = (ASPxComboBox)MyGridView.FindRowCellTemplateControl(i, col, "InnerCombo");
Debug.WriteLine("{0} = {1}", row[0], innerCombo.Value);
}
}
protected void InnerCombo_Init(object sender, EventArgs e)
{
Debug.WriteLine("InnerCombo_Init");
ASPxComboBox innerCombo = sender as ASPxComboBox;
if (innerCombo != null)
{
innerCombo.DataSource = GetValues();
innerCombo.DataBind();
}
}
private static List<ValueClass> GetValues()
{
// Simple for testing; actual method will be database access.
return new List<ValueClass>()
{
new ValueClass(0, "Zero (default)"),
new ValueClass(1, "One"),
new ValueClass(2, "Two"),
new ValueClass(3, "Three"),
};
}
private static List<SettingClass> GetDefaultSettings()
{
// Simple for testing; actual method will be database access + post-processing.
return new List<SettingClass>()
{
new SettingClass("AA", 0),
new SettingClass("BB", 1),
new SettingClass("CC", 0),
};
}
public class ValueClass
{
public int ID { get; private set; }
public string Desc { get; private set; }
public ValueClass(int id, string desc)
{
this.ID = id;
this.Desc = desc;
}
}
public class SettingClass
{
public string Name { get; set; }
public int Value { get; set; }
public SettingClass(string name, int value)
{
this.Name = name;
this.Value = value;
}
}
}

Source code of receiving email

I am making email client in asp.net C#. In it, GridView is not taking data of more than 5 rows. I am having 250 mails in my mailbox. But GridView is not showing that data. It is showing only up to 5 rows and after that five to six rows data are presented out of the GridView.
<%# Page Language="C#" AutoEventWireup="true" CodeFile="CS.aspx.cs" Inherits="CS" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
</script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.9/jquery-ui.js" type="text/javascript">
</script>
<link href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.9/themes/start/jquery-ui.css"
rel="stylesheet" type="text/css"
/>
<script type="text/javascript">
$("[id*=lnkView]").live("click", function () {
var subject = $(this).text();
var row = $(this).closest("tr");
$("#body").html($(".body", row).html());
$("#attachments").html($(".Attachments", row).html());
$("#dialog").dialog({
title: subject,
buttons: {
Ok: function () {
$(this).dialog('close');
}
}
});
return false;
});
</script>
</head>
<body style="font-family: Arial; font-size: 10pt">
<form id="form1" runat="server">
<asp:GridView ID="gvEmails" runat="server" OnRowDataBound="OnRowDataBound" DataKeyNames="MessageNumber"
AutoGenerateColumns="false">
<Columns>
<asp:BoundField HeaderText="From" DataField="From" HtmlEncode="false" />
<asp:TemplateField HeaderText="Subject">
<ItemTemplate>
<asp:LinkButton ID="lnkView" runat="server" Text='<%# Eval("Subject") %>' />
<span class="body" style="display: none">
<%# Eval("Body") %></span>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Date" DataField="DateSent" />
<asp:TemplateField ItemStyle-CssClass="Attachments">
<ItemTemplate>
<asp:Repeater ID="rptAttachments" runat="server">
<ItemTemplate>
<asp:LinkButton ID="lnkAttachment" runat="server" OnClick="Download" Text='<%# Eval("FileName") %>' />
</ItemTemplate>
<SeparatorTemplate>
<br>
</SeparatorTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<div id="dialog" style="display: none">
<span id="body"></span>
<br />
<span id="attachments"></span>
</div>
</form>
</body>
</html>
Code Behind:
public partial class CS : System.Web.UI.Page
{
protected List<Email> Emails
{
get { return (List<Email>)ViewState["Emails"]; }
set { ViewState["Emails"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
this.Read_Emails();
}
}
private void Read_Emails()
{
Pop3Client pop3Client;
if (Session["Pop3Client"] == null)
{
pop3Client = new Pop3Client();
pop3Client.Connect("pop.gmail.com", 995, true);
pop3Client.Authenticate("example#gmail.com", "password", AuthenticationMethod.TryBoth);
Session["Pop3Client"] = pop3Client;
}
else
{
pop3Client = (Pop3Client)Session["Pop3Client"];
}
int count = pop3Client.GetMessageCount();
this.Emails = new List<Email>();
int counter = 0;
for (int i = count; i >= 1; i--)
{
Message message = pop3Client.GetMessage(i);
Email email = new Email()
{
MessageNumber = i,
Subject = message.Headers.Subject,
DateSent = message.Headers.DateSent,
From = string.Format("<a href = 'mailto:{1}'>{0}</a>", message.Headers.From.DisplayName, message.Headers.From.Address),
};
MessagePart body = message.FindFirstHtmlVersion();
if (body != null)
{
email.Body = body.GetBodyAsText();
}
else
{
body = message.FindFirstPlainTextVersion();
if (body != null)
{
email.Body = body.GetBodyAsText();
}
}
List<MessagePart> attachments = message.FindAllAttachments();
foreach (MessagePart attachment in attachments)
{
email.Attachments.Add(new Attachment
{
FileName = attachment.FileName,
ContentType = attachment.ContentType.MediaType,
Content = attachment.Body
});
}
this.Emails.Add(email);
counter++;
if (counter > count)
{
break;
}
gvEmails.DataSource = this.Emails;
gvEmails.DataBind();
}
//gvEmails.DataSource = this.Emails;
//gvEmails.DataBind();
}
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
Repeater rptAttachments = (e.Row.FindControl("rptAttachments") as Repeater);
List<Attachment> attachments = this.Emails.Where(email => email.MessageNumber == Convert.ToInt32(gvEmails.DataKeys[e.Row.RowIndex].Value)).FirstOrDefault().Attachments;
rptAttachments.DataSource = attachments;
rptAttachments.DataBind();
}
}
protected void Download(object sender, EventArgs e)
{
LinkButton lnkAttachment = (sender as LinkButton);
GridViewRow row = (lnkAttachment.Parent.Parent.NamingContainer as GridViewRow);
List<Attachment> attachments = this.Emails.Where(email => email.MessageNumber == Convert.ToInt32(gvEmails.DataKeys[row.RowIndex].Value)).FirstOrDefault().Attachments;
Attachment attachment = attachments.Where(a => a.FileName == lnkAttachment.Text).FirstOrDefault();
Response.AddHeader("content-disposition", "attachment;filename=" + attachment.FileName);
Response.ContentType = attachment.ContentType;
Response.BinaryWrite(attachment.Content);
Response.End();
}
}
[Serializable]
public class Email
{
public Email()
{
this.Attachments = new List<Attachment>();
}
public int MessageNumber { get; set; }
public string From { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public DateTime DateSent { get; set; }
public List<Attachment> Attachments { get; set; }
}
[Serializable]
public class Attachment
{
public string FileName { get; set; }
public string ContentType { get; set; }
public byte[] Content { get; set; }
}

Custom user control data source

I have a custom control that has a DropDownList inside and it's created by CreateUserControl. I'm saving data source directly to dropdown control. After page postbacked my binded data disappear. Should i save/restore my binded data myself in some tricky way?
public class EnumDropDownList : UserControl
{
private readonly DropDownList _ddlSelector;
private Dictionary<long, string> _dataSource;
public EnumDropDownList()
{
_ddlSelector = new DropDownList();
_dataSource = new Dictionary<long, string>();
}
public object DataSource
{
set
{
// datasource logic
}
}
public long SelectedValue
{
get { return Convert.ToInt64(_ddlSelector.SelectedValue); }
set { _ddlSelector.SelectedValue = value.ToString(); }
}
public override void DataBind()
{
_ddlSelector.DataSource = _dataSource;
_ddlSelector.DataTextField = "Value";
_ddlSelector.DataValueField = "Key";
_ddlSelector.DataBind();
base.DataBind();
}
[PermissionSet(SecurityAction.Demand, Name = "Execution")]
protected override void CreateChildControls()
{
Controls.Add(_ddlSelector);
}
}
You code is combination of UserControl and CustomServerControl.
It could have be a lot easier if you implement one instead of combination.
I created two controls - UserControl and CustomServerControl.
UserControl
Place the dropdownlist to ASPX instead of loading dymaiclally. If you load dynamically, you'll have to take care of persistence of control.
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="EnumDropDownList.ascx.cs"
Inherits="WebApplication2010.EnumDropDownList" %>
<asp:DropDownList runat="server" ID="DropDownList1" />
public partial class EnumDropDownList : System.Web.UI.UserControl
{
private Dictionary<long, string> _dataSource;
public EnumDropDownList()
{
_dataSource = new Dictionary<long, string>();
}
public Dictionary<long, string> DataSource
{
set { _dataSource = value; }
}
public long SelectedValue
{
get { return Convert.ToInt64(DropDownList1.SelectedValue); }
set { DropDownList1.SelectedValue = value.ToString(); }
}
public override void DataBind()
{
DropDownList1.DataSource = _dataSource;
DropDownList1.DataTextField = "Value";
DropDownList1.DataValueField = "Key";
DropDownList1.DataBind();
base.DataBind();
}
}
Custom Server Control (it is a lot easier to implement for your case)
It basically inherits DropDownList web control.
public class MyDropDownList : DropDownList
{
public long SelectedInt64Value
{
get { return Convert.ToInt64(SelectedValue); }
set { SelectedValue = value.ToString(); }
}
public Dictionary<long, string> DataSource
{
get { return (Dictionary<long, string>)ViewState["DataSource"]; }
set { ViewState["DataSource"] = value; }
}
public override void DataBind()
{
foreach (var item in DataSource)
Items.Add(new ListItem(item.Value, item.Key.ToString()));
base.DataBind();
}
}
Usage
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm5.aspx.cs" Inherits="WebApplication2010.WebForm5" %>
<%# Register Src="EnumDropDownList.ascx" TagName="EnumDropDownList" TagPrefix="uc1" %>
<%# Register TagPrefix="asp" Namespace="WebApplication2010" Assembly="WebApplication2010" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<uc1:EnumDropDownList ID="EnumDropDownList1" runat="server" />
<asp:Button runat="server" ID="Button1" Text="Submit" OnClick="Button1_Click" />
<asp:MyDropDownList id="MyDropDownList1" runat="server" />
</form>
</body>
</html>
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
Dictionary<long, string> dataSource = new Dictionary<long, string>();
dataSource.Add(1, "One");
dataSource.Add(2, "Two");
EnumDropDownList1.DataSource = dataSource;
EnumDropDownList1.DataBind();
MyDropDownList1.DataSource = dataSource;
MyDropDownList1.DataBind();
}
}
In some cases I have saved the dataset in a session variable. Whicn can then be referenced after postbacks. Something like this:
Session.Add("dataSource", _dataSource);//create the session variable
Then you can reference it, depending on the type the data source is (in example I used a datable)
_ddlSelector.DataSource = (DataTable)Session["dataSource"];
THis Is aspx file :
<telerik:RadComboBox ID="cmbCurrency" runat="server" Width="200px" MaxHeight="200px"
EmptyMessage="Select a currency" AutoPostBack="true" Filter="Contains" EnableLoadOnDemand="true">
</telerik:RadComboBox>
This is code Behind :
if (!IsPostBack)
{
popCurrencyName();
}
public void popCurrencyName()
{
DataTable dtCurrency = objCurrencyBAL.getCurrency(long.MinValue);
if (dtCurrency.Rows.Count > 0)
{
cmbCurrency.DataSource = dtCurrency;
cmbCurrency.DataTextField = "Name";
cmbCurrency.DataValueField = "CurrencyId";
cmbCurrency.DataBind();
}
}
Try this code:

Binding Grid view with Generic list (Error: "Field\Property not assigned")

I am new to .NET. I am trying to bind a generic List to a GridView in the aspx page. I set AutoGenerateColumns="false", I defined the columns on my .aspx page, and bound them but it's still throwing the error error A field or property with the name 'Assigned' was not found on the selected data source.
I tried all options but end up no where. CL is an alias for my namespace.
SITESTATUS CLASS
public class SiteStatus
{
public string Opened;
public string Assigned;
public string LocationAddress;
public string LocationId;
public SiteStatus(string Assigned, string Opened, string LocationAddress, string LocationId)
{
this.Assigned = Assigned;
this.Opened = Opened;
this.LocationAddress = LocationAddress;
this.LocationId = LocationId;
}
}
Aspx File
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="SiteSurveyStatus.aspx.cs" MasterPageFile="~/Site.Master" Inherits="Website.WebForms.SiteSurveyStatus" %>
<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<form id="form1" runat="server">
<asp:Label ID="SiteSurvey" runat="server" Text="Site Survey Status" Font-Bold="True"></asp:Label>
<asp:GridView ID="GridView1" runat="server" PageSize="15" CellPadding="0" Width="100%" AutoGenerateColumns="false" EnableViewState="True">
<Columns>
<asp:BoundField HeaderText="Assigned" DataField="Assigned" SortExpression="Assigned" />
<asp:BoundField HeaderText="Opened" DataField="Opened" SortExpression="Opened" />
<asp:BoundField HeaderText="Location" DataField="LocationAddress" />
<asp:BoundField HeaderText="LocationId" DataField="LocationId" />
</Columns>
</asp:GridView>
</form>
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
List<CL.SiteStatus> list = new List<CL.SiteStatus>();
list.Add(new CL.SiteStatus("09/12/2011", "User123", "Dallas TX 75724", "USATX75724"));
list.Add(new CL.SiteStatus("10/11/2011", "User234", "Houston TX 77724", "USATX77724"));
list.Add(new CL.SiteStatus("02/30/2011", "User567", "Austin TX 70748", "USATX70748"));
list.Add(new CL.SiteStatus("03/01/2011", "User1234", "El Paso TX 71711", "USATX71711"));
list.Add(new CL.SiteStatus("04/02/2011", "User125", "Chicago IL 33456", "USAIL33456"));
GridView1.DataSource = list.ToList();
GridView1.DataBind();
}
The problem looks like it lies with your SiteStatus class. You have properties but no modifiers, so no external code can access them.
Try:
public class SiteStatus
{
public string Opened { get; set; }
public string Assigned { get; set; }
public string LocationAddress { get; set; }
public string LocationId { get; set; }
public SiteStatus(string Assigned, string Opened, string LocationAddress, string LocationId)
{
this.Assigned = Assigned;
this.Opened = Opened;
this.LocationAddress = LocationAddress;
this.LocationId = LocationId;
}
}
The rest of your markup looks fine to me.

How do I create an ASP.NET control that simulates switch/case?

I've got a repeater looping through a list of objects that are of different types. I'd like to render the objects differently depending on their type. For this I need some kind of control (since I want to avoid using the code-behind) that has a behavior similar to a switch/case statement. Basically it could look like this:
<xxx:TestType Object='<%# Container.DataItem %>'>
<Case Type="Namespace.ClassX">
<asp:Label ... />
</Case>
<Case Type="Namespace.ClassY">
<asp:TextBox ... />
</Case>
<Default>
<p>Other</p>
</Default>
</xxx:TestType>
I've made web controls before, but this is a rather complex one...
How do I make it support multiple <Case> elements?
Is it possible to implement the <Case Type="..."> elements, or am I limited to attribute-less elements?
I'm guessing I have to make a type for the <Case> elements and somehow specifying it for the main web control?
I'd be grateful for any pointers, links to tutorials, etc!
Alternative
Alternatively, suggest a nicer way of rendering different HTML/ASP.NET controls based on the type of the currently bound object. The first method that popped into my head was this, which I consider (very) ugly:
<asp:PlaceHolder Visible='<%# CheckType(Container, typeof(ClassX)) %>' runat="server">
...
</asp:PlaceHolder>
<asp:PlaceHolder Visible='<%# CheckType(Container, typeof(ClassY)) %>' runat="server">
...
</asp:PlaceHolder>
The MultiView control is the closest thing out-of-the-box in ASP.NET to a C# switch statement.
Look at implementing ITemplate interface
public class Case
{
[PersistenceMode(PersistenceMode.Attribute)]
public string Type { get; set; }
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public ITemplate Template { get; set; }
}
public class DeclarativeCase
: CompositeControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public List<Case> Cases { get; set; }
[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate Default { get; set; }
}
<xxx:DeclarativeCase runat="server" ID="test">
<Cases>
<xxx:Case Type="Namespace.TypeName">
<Template>
<asp:Label ID="Label1" runat="server"></asp:Label>
</Template>
</xxx:Case>
</Cases>
<Default>
<asp:Label ID="Label2" runat="server"></asp:Label>
</Default>
</xxx:DeclarativeCase>
Why don't you ditch the server control and use the C# switch statement. All you need is to wrap it in the code tags.
Another approach is a iteration (for loop). Create an interface with a type property and a render method. Then iterate over the interfaces until you've found the correct type.
I had a similar requirement a while ago and I did something similar to:
[ParseChildren(true, "Templates")]
public class TypedRepeater : CompositeDataBoundControl
{
[
PersistenceMode(PersistenceMode.InnerProperty),
Browsable(false),
MergableProperty(false)
]
public TypedTemplateCollection Templates
{
get;
}
protected TypedTemplate GetTemplate(object dataItem)
{
if (dataItem == null)
{
return null;
}
foreach (TypedTemplate template in Templates)
{
Type itemType = dataItem.GetType();
if (dataItem.IsAssignableFrom(template.Type))
{
return template;
}
}
return null;
}
protected TypedTemplateRepeaterItem CreateItem(int index, object dataItem, bool dataBinding)
{
TypedTemplateRepeaterItem repeaterItem = new TypedTemplateRepeaterItem();
if ((!dataBinding) && (ViewState[string.Format("TemplateIxc_{0}", index)] is int))
{
int _template = (int)ViewState[string.Format("TemplateIxc_{0}", index)];
if ((_template >= 0) && (_template < Templates.Count) && (Templates[_template].ItemTemplate != null))
{
Templates[_template].ItemTemplate.InstantiateIn(repeaterItem);
}
else
{
DefaultTemplate.InstantiateIn(repeaterItem);
}
}
else if (dataBinding)
{
TypedTemplate template = GetTemplate(dataItem);
ITemplate itemTemplate = DefaultTemplate;
if (template != null)
{
itemTemplate = template.ItemTemplate;
ViewState[string.Format("TemplateIxc_{0}", index)] = Templates.IndexOf(template);
}
else
{
ViewState[string.Format("TemplateIxc_{0}", index)] = -1;
}
repeaterItem.DataItem = dataItem;
repeaterItem.DataItemIndex =
repeaterItem.DisplayIndex = index;
itemTemplate.InstantiateIn(repeaterItem);
repeaterItem.DataBind();
repeaterItem.DataItem = null;
}
return repeaterItem;
}
protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
{
int count = 0;
if (dataSource != null)
{
foreach (object dataItem in dataSource)
{
TypedTemplateRepeaterItem repeaterItem = CreateItem(count, dataItem, dataBinding);
Controls.Add(repeaterItem);
count++;
}
}
return count;
}
}
where TypedTemplateCollection is a StateManagedCollection of a TypedTemplate class:
[ParseChildren(true, "ItemTemplate")]
public class TypedTemplate
{
public Type Type
{
get { return Type.GetType(TypeName); }
}
[
PersistenceMode(PersistenceMode.Attribute),
Browsable(true),
DefaultValue("")
]
public string TypeName
{
get;
set;
}
[
PersistenceMode(PersistenceMode.InnerProperty),
Browsable(true),
DefaultValue(typeof(ITemplate), null),
TemplateContainer(typeof(TypedTemplateRepeaterItem))
]
public ITemplate ItemTemplate
{
get;
set;
}
}
and TypedTemplateRepeaterItem is:
public class TypedTemplateRepeaterItem : WebControl, INamingContainer, IDataItemContainer
{
#region IDataItemContainer Members
public object DataItem
{
get;
set;
}
public int DataItemIndex
{
get;
set;
}
public int DisplayIndex
{
get;
set;
}
#endregion
}
The MSDN site has a simple clear example of templating and it certainly seems like the way to go in your case.

Resources