ASP.NET create repeater programmatically - asp.net

I'm trying to create an ASP:Repeater programmatically and I have a problem when trying to bind the columns. The tutorials I've read are quite confusing and many of them don't get to the point of binding.
My problem is only in the point of binding data, when I would write this in a "static" repeater:
<%# DataBinder.Eval(Container.DataItem, "Name")%>
I don't know what should be when working in code-behind, it's within a class so I don't have an event handler. This is my code so far:
Dim DsArbol As New SqlDataAdapter(query, System.Configuration.ConfigurationManager.ConnectionStrings("CNX").ConnectionString)
Dim tablaCarpetas As New DataTable
DsArbol.Fill(tablaCarpetas)
Dim RepArbol As New Repeater
RepArbol.DataSource = tablaCarpetas
RepArbol.ID = "repArbolCarpetas"
Dim header As New TemplateBuilder
Dim item As New TemplateBuilder
Dim footer As New TemplateBuilder
header.AppendLiteralString("<ul class=""arbol-carpetas"">")
item.AppendLiteralString(String.Format("<li id=""li_carpeta_{0}"">{1}</li>", 1, DataBinder.Eval(Container.DataItem, "Name")))
footer.AppendLiteralString("</ul>")
RepArbol.HeaderTemplate = header
RepArbol.ItemTemplate = item
RepArbol.FooterTemplate = footer
RepArbol.DataBind()
PanelArbolCarpetas.Controls.Add(RepArbol)
What should I write instead of DataBinder.Eval(Container.DataItem, "Name")?

I am not too sure about using TemplateBuilder as it is meant for consumption for ASP.NET framework and there is not much documentation available. However, you may try changing below line as
item.AppendLiteralString("<li id=\"li_carpeta_1\"><%# Eval(\"Name\") %></li>")
The alternate way is to build your own template control - for example
public class MyTemplate : ITemplate
{
ListItemType _type;
public MyTemplate(ListItemType type)
{
_type = type;
}
public void InstantiateIn(Container control)
{
switch(_type)
{
case ListItemType.Header:
control.Contorls.Add(new LiteralControl("<ul class=\"arbol-carpetas\">"));
break;
case ListItemType.Footer:
control.Contorls.Add(new LiteralControl("</ul>"));
break;
case ListItemType.Item:
case ListItemType.AlternatingItem:
var c = new GenericHtmlControl("<li>");
c.ID = "L";
... // add needed attributes etc.
container.Controls.Add(c);
// manage data binding
container.DataBinding += (o,e) =>
{
c.InnerText = DataBinder.Eval(Container, "Name");
};
break;
}
}
}
RepArbol.HeaderTemplate = new MyTemplate(ListItemType.Header);
RepArbol.ItemTemplate = MyTemplate(ListItemType.Item);
RepArbol.FooterTemplate = MyTemplate(ListItemType.Footer);
RepArbol.DataBind()
Disclaimer: Untested code - just to give you an idea about building a template dynamically and manage data binding by capturing data-binding event.

Related

Render ascx control from outside page context

When trying to render the HTML of an ascx UserControl from a WebService, I get the error RegisterForEventValidation can only be called during Render.
This is a duplicate of this question. However the answers given do not work...
The solution always involves EnableEventValidation="false" and override VerifyRenderingInServerForm but these are only available on a Page, not on a Control (what the ascx is).
When changing the ascx to an aspx, the following code fails: page.LoadControl("mycontrol.ascx/aspx") and rendering an aspx is apparently not so easy according to this question.
The Question
How can I render my ascx without the exception?
Bonus question:
Why is EnableEventValidation not available on a Control while there are many examples on the net that claim otherwise? (StackOverflow, CodeProject, ...)
I found the solution:
var page = new System.Web.UI.Page();
// Or RenderControl throws 'RegisterForEventValidation can only be called during Render'
page.EnableEventValidation = false;
// Or generates a second hidden field with ID=_VIEWSTATE
page.EnableViewState = false;
var sb = new StringBuilder();
var ctl = (SomeAscx)page.LoadControl("SomeAscx.ascx");
using (var sw = new StringWriter(sb))
using (var htw = new HtmlTextWriter(sw))
{
ctl.RenderControl(htw);
}
string result = sb.ToString();
Key was setting:
page.EnableEventValidation = false;
page.EnableViewState = false;

Object reference not set to an instance of an object. This happens while adding checkboxlist control dynamically

Object reference not set to an instance of an object.
protected void cmdSave_Click(object sender, EventArgs e)
{
string strNames = string.Empty;
CheckBoxList Chkboxx = (CheckBoxList)PlaceHolder1.FindControl("Chkbox");
foreach (ListItem em in Chkboxx.Items) //-------- (Showing error)
{
if (em.Selected)
{
strNames += em.Value + ", ";
}
}
string final_name = strNames.Substring(0, strNames.Length - 2);
lblNames.Text = final_name;
}
Actually I am adding Checkbox control dynamically :
protected void ddl_varient_SelectedIndexChanged1(object sender, EventArgs e)
{
string query = "select prd_vrtyvalue_id,varient_value from tbl_ProductVariety_Value where varient='" + ddl_varient.SelectedItem.Text + "' " +
" order by varient_value asc ";
DataTable abc = new DataTable();
SqlDataAdapter ada = new SqlDataAdapter(query, new CommonClass().connection());
ada.Fill(abc);
ChkboxList.ID = "Chkbox";
for (int i = 0; i < abc.Rows.Count; i++)
{
ChkboxList.Items.Add(new ListItem(abc.Rows[i]["varient_value"].ToString(), abc.Rows[i]["prd_vrtyvalue_id"].ToString()));
}
ChkboxList.RepeatColumns = 2;
PlaceHolder1.Controls.Add(ChkboxList);
}
Can Anybody tell me, what exactly i am doing wrong !
The way ASP.NET WebForms work is that the entire page is re-built during each post back. So, I imagine this is what is occuring:
Page gets "built" and includes only controls defined within your ASCX/ASPX file.
User clicks on DDL_VARIENT checkbox and the ChkboxList is added to PlaceHolder1
Form is rendered back to the user so they can see ChkboxList
Save button is clicked, causing another postback.
Page is re-built, setting all the controls back to what is defined within your ASPX/ASCX code. This does not include ChkboxList.
Your code is hit, ChkboxList no longer exists and you get your problem.
To fix, you could re-add your ChkboxList on Page_Load depending on the value of your DDL_VARIENT checkbox. If I were you though, I'd be tempted to define the ChkboxList within your ASPX/ASCX code and then set the visibility of the list depending on the value of the DDL_VARIENT checkbox within Page_Load.
I should add, the entire of the above is dependant upon you using ASP.NET WebForms. If you're using MVC then it's probably wrong.

C#/ASP.Net - Extract bit value of column in a gridview

I have a gridview that is SQL bound. In some of the columns there are bit values. When I use C# to get the values into the gridview, checkboxes are displayed. I need to extract the value of that column into text.
SqlConnection sConnection = new SqlConnection(MyConnectionString);
SqlCommand sCommand = new SqlCommand();
using (sConnection)
{
sCommand.Connection = sConnection;
sCommand.CommandText = "MyStoredProcedure";
sCommand.CommandType = CommandType.StoredProcedure;
sCommand.Connection.Open();
SqlDataReader reader = sCommand.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
gridView.DataSource = reader;
gridView.DataBind();
}
for (int i = 0; i < gridView.Rows.Count; i++)
{
ListBox1.Items.Add(gridView.Rows[i].Cells[3].Text);
}
}
}
The gridview column data type is 'bit'. I do not have access to the database or stored procedure to change anything there. I need to somehow extract the '0' or '1' value, but when I do it like above, the text is blank.
I also tried to use 'GetOrdinal'. It returned a True/False value from the database, but I could not figure out how to get the value for each item in the gridview.
if (!reader.IsDBNull(reader.GetOrdinal("MyColumn1")))
{
ListBox1.Items.Add(reader.GetOrdinal("MyColumn1").ToString());
}
General overview:
You need to be able to find the CheckBox that's generated and get the value of it's "Checked" property.
To do this, you need to be able to use the FindControl() method on the GridViewRow.
To use FindControl, the CheckBox needs a predictable name.
To get a predictable name, you need to have that column be a TemplateColumn so that you can specify the name of the CheckBox in the markup on the ASPX page.
There's a full working set of code here: http://www.codeproject.com/Articles/25056/The-RIGHT-Way-to-Use-Checkboxes-in-a-NET-Repeater
This shows the code for a Repeater, but it's the same principle and general code for any DataBound control.
The code below should work with modifications to match your DB names:
<asp:TemplateField>
<ItemTemplate >
<asp:checkbox id="MyColumnNameCheckbox" runat="server" />
</ItemTemplate>
</asp:TemplateField>
string defaultvalue = "0"; // To be used to display the value of the original bit field.
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox chkBx = (CheckBox)row.FindControl("MyColumnNameCheckbox");
if (chkBx != null && chkBx.Checked)
{
defaultvalue = "1";
}
}
I was able to figure it out. Thanks, David Stratton, for pointing me in the right direction.
I did it by assigning an id to the dynamically created control first. then did the FindControl()...
Control ctrl = GridView1.SelectedRow.Cells[4].Control[0];
ctrl.ID = "ctrl";
Boolean result = Convert.ToBoolean(((Checkbox)GridView1.Rows[0].Cells[4].FindControl("ctrl")).Checked);
TextBox1.Text = result.ToString();
This returns a value of "True" or "False"...
Thanks again.
Another way to resolve it:
bool result = (GridView1.SelectedRow.Cells[4].Control[0] as Checkbox).Checked;
TextBox1.Text = result.ToString();
it resolve the problem with less code :)

Get all selected items from asp.net ListBox

Anyone know of a smooth way to get all of the selected items in a listbox control by using extension methods?
And, please, spare me the argument of it's irrelevant as to how one gets such a list because in the end everything uses a loop to iterate over the items and find the selected ones anyway.
var selected = yourListBox.Items.GetSelectedItems();
//var selected = yourDropDownList.Items.GetSelectedItems();
//var selected = yourCheckBoxList.Items.GetSelectedItems();
//var selected = yourRadioButtonList.Items.GetSelectedItems();
public static class Extensions
{
public static IEnumerable<ListItem> GetSelectedItems(
this ListItemCollection items)
{
return items.OfType<ListItem>().Where(item => item.Selected);
}
}
Extension method:
public static List<ListItem> GetSelectedItems(this ListBox lst)
{
return lst.Items.OfType<ListItem>().Where(i => i.Selected).ToList();
}
You can call it on your listbox like:
List<ListItem> selectedItems = myListBox.GetSelectedItems();
You could also do the conversion using a 'Cast' on the list box items like:
return lst.Items.Cast<ListItem>().Where(i => i.Selected).ToList();
Not sure which will perform better OfType or Cast (my hunch is Cast).
Edit based on Ruben's feedback for a generic ListControl method which would indeed make it much more useful extension method:
public static List<ListItem> GetSelectedItems(this ListControl lst)
{
return lst.Items.OfType<ListItem>().Where(i => i.Selected).ToList();
}
Hello i've created one solution for this problem in this post using VB.NET:
Getting all selected values from an ASP ListBox
This code below is the same as the link above:
Public Shared Function getSelectedValuesFromListBox(ByVal objListBox As ListBox) As String
Dim listOfIndices As List(Of Integer) = objListBox.GetSelectedIndices().ToList()
Dim values As String = String.Empty
For Each indice As Integer In listOfIndices
values &= "," & objListBox.Items(indice).Value
Next indice
If Not String.IsNullOrEmpty(values) Then
values = values.Substring(1)
End If
Return values
End Function
I hope it helps.

switch statement in linq

My code for sql connection using linq is:
var query1 = from u in dc.Usage_Computers
where u.DomainUser == s3
select u; // selects all feilds from table
GridView1.DataSource = query1;
GridView1.DataBind();
I have a field called "Operation" in the table "Domainuser" which has values like "1, 2, 3". When I populate these values to data grid I wanted to convert them to meaningful values like if the value of Operation is 1 then display in datagrid as "logon", if 2 then "logoff" etc...
How do i assign values for them after retrieving from database?
This technique does not seem particularly applicable to your problem, but here it is anyway.
You can create a SQL case statement in LinqToSql by using the C# ? : operator.
var query1 =
from u in dc.Usage_Computers
where u.DomainUser == s3
select new {usage = u,
operation =
u.DomainUser.Operation == 1 ? "login" :
u.DomainUser.Operation == 2 ? "logoff" :
"something else"
};
Use a template field in your gridview:
<asp:GridView ID="gvDomain" runat="server" OnRowDataBound="gvDomain_RowDataBound">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
Operation
</HeaderTemplate>
<ItemTemplate>
<asp:Label id="lblLogon" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Then use the gridviews RowDataBound event to discover the label and assign its text:
Protected Sub gvDomain_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvStates.RowDataBound
Dim lblLogon As Label = DirectCast(e.Row.FindControl("lblLogon"), Label)
Dim drv As DataRowView = DirectCast(e.Row.DataItem, DataRowView)
If lblLogon IsNot Nothing Then
Select Case drv("Operation").ToString()
Case "1"
lblLogon.Text = "Logon"
Break
Case "2"
lblLogon.Text = "Logoff"
Break
//etc...
End Select
End If
End Sub
static Func<int?, string> MapSqlIntToArbitraryLabel = (i =>
{
// for performance, abstract this reference
// dictionary out to a static property
Dictionary<int, string> labels = new Dictionary<int, string>();
labels.Add(1, "logon");
labels.Add(2, "logoff");
labels.Add(...);
if (i == null) throw new ArgumentNullException();
if (i < 1 || i > labels.Count) throw new ArgumentOutOfRangeException();
return labels.Where(x => x.Key == i.Value)
.Select(x.Value)
.Single();
}
that return statement can also be expressed as:
return (from kvp in labels
where kvp.Key == i.Value
select kvp.Value).Single();
Then you can use call that function from your linq query like so:
var query1 = from u in dc.Usage_Computers
where u.DomainUser == s3
select {
Operation = MapSqlIntToArbitraryLabel(u.Operation)
// add other properties to this anonymous type as needed
};
I've tried every suggested method of fooling Linq2Sql into running my code and this method is the only one that i've found that allows me to run code as part of a deferred-execution projection.
I've done something similar using TemplateFields. Using an ASP:Label bound to the property and adding an OnPreRender event handler for the control. In the event handler for the control I translate the text based on it's current value and set the new value:
protected void label_OnPreRender( object sender, EventArgs e )
{
Label l = (Label)sender;
switch (l.Text) {
case "1":
l.Text = "Logon";
break;
...
default:
break;
}
}
If the form is in edit mode, you'll need to handle it differently. You'll also probably need to add handlers for Inserting and Updating to the View control you are using to translate the data supplied by the page into its database representation.

Resources