I have a gridview bound to a sql server datasource. I am currently moving selected items to a ListBox to show chosen records. I'd like to switch to the ReOrderList from the AJAX Toolkit to be able to reorder the selected items. Unfortunately, the ReorderList needs a true datasource to bind to. What is the best practice for creating some sort of temporary table that the user would use?
OK, what you could do is persist your temporary list datasource in viewstate. Here's a rough example:
<asp:ScriptManager ID="SM1" runat="server"></asp:ScriptManager>
<ajaxToolkit:ReorderList ID="RList" runat="server"
DragHandleAlignment="Left" ItemInsertLocation="End"
AllowReorder="true" ShowInsertItem="true" PostBackOnReorder="false">
<ItemTemplate>
<p><%# Eval("ID") %> = <%# Eval("Name") %></p>
</ItemTemplate>
</ajaxToolkit:ReorderList>
<asp:Button ID="ButtonAdd" runat="server" OnClick="ButtonClick_AddItem" Text="Add New" />
Then in codebehind:
public partial class SortList : System.Web.UI.Page
{
[Serializable]
public class MyItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public MyItem(Guid id, string name)
{
Id = id;
Name = name;
}
}
protected List<MyItem> MyList
{
get
{
if (ViewState["myClass"] == null)
ViewState["myClass"] = new List<MyItem>();
return (List<MyItem>)ViewState["myClass"];
}
}
protected void AddItem(Guid id, string name)
{
MyList.Add(new MyItem(id, name));
RList.DataSource = MyList;
RList.DataBind();
}
protected void ButtonClick_AddItem(object sender, EventArgs e)
{
AddItem(Guid.NewGuid(), DateTime.Now.Ticks.ToString());
}
}
Obviously you would substitute MyItem class with whatever you want to store and replace the button with the GridView select item event. But hopefully the principle is there?
I don't follow. The ReOrderList has a DataSourceID property to which you can just point at your existing SqlDataSource. Or do you not actually have an SqlDataSource control?
If not, how are you binding the data to your GridView? If you are binding to some kind of object colllection then you could use an ObjectDataSource instead, so long as it implements IList interface. Perhaps have a read of ReorderList - bind to DataTable if you are trying to bind to a DataTable instead.
Related
I have a nested class that contains order items for an order:
public class Order
{
public int ItemID { get; set; }
public int CustomerId { get; set; }
...
public List<OrderItem> Items { get; set; }
}
public class OrderItem
{
public int ItemId { get; set; }
...
}
and I have this databound to an asp repeater
var result = [method to get data]
rptOrders.DataSource = result;
rptOrders.DataBind();
and in the ascx page I have
<asp:Repeater ID="rptOrders" runat="server" HideControlForZeroRows="true" ZeroRowsText="You have no orders.">
<HeaderTemplate>
<table>
<tr class="tableHeader">
<td>Order #</td>
...
</tr>
</HeaderTemplate>
<ItemTemplate>
<ItemTemplate>
<tr>
<td><a href='#'><%# Eval("ItemID") %></a></td>
...
</tr>
</ItemTemplate>
but I want to use an accordion to show hide the order details, an example is here: http://jsfiddle.net/Xqk3m/, which means I have to add rows to my repeater table for the nested class items.
How do I reference the nested class to have another repeater iterate over the elements to add a for each of the nested items?
I have looked around the web and generally they are suggesting that I have a nested repeater call the nested class separately but really I want to make use of the fact that I have well defined classes. Hopefully I can do something like:
//parent repeater
<asp:Repeater ID="rptOrders" runat="server" HideControlForZeroRows="true" ZeroRowsText="You have no orders.">
....
//nested repeater
<asp:Repeater ID="rptOrderItems" runat="server" HideControlForZeroRows="true">
but how can I reference the order items for the order?
<asp:Repeater runat="server" DataSource="<%# Container.DataItem %>">
<ItemTemplate>
<tr>
<td><%# Eval("ItemId") %></td>
</tr>
</ItemTemplate>
</asp:Repeater>
You can add ItemDataBound event to rptOrders repeater:
protected void rptOrders_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var order = (Order)e.Item.DataItem;
Repeater innerRep = e.Item.FindControl("rptOrderItems") as Repeater;
innerRep.DataSource = order.Items;
innerRep.DataBind();
}
In fact you can have any other data-bound control inside repeater item and bind it using list from DataItem.
I'm trying to create a custom Context Menu as a user control. The code behind for this user control looks like this:
public partial class UCContextMenu : UserControl
{
private List<ContextMenuItem> m_menuItems = new List<ContextMenuItem>();
protected void Page_Load(object sender, EventArgs e)
{
}
[PersistenceMode(PersistenceMode.InnerProperty)]
public List<ContextMenuItem> Items
{
get { return m_menuItems; }
set { m_menuItems = value; }
}
public event EventHandler Command;
}
Then, I defined the ContextMenuItem type in the same namespace as the user control (in the same file actually) which is essentially a menu item:
public class ContextMenuItem
{
public string Name { get; set; }
public string Text { get; set; }
}
The ascx page for the user control includes a repeater control which is defined like this:
<div id="contentHolder">
<ul id="ulContextMenu" style="display: none; z-index: 1000; border-width: 0.8px;
font-size: 13px;" class="ui-corner-all">
<asp:Repeater runat="server" DataSource="<%# Items %>">
<ItemTemplate>
<li><a href='#<%# DataBinder.Eval(Container.DataItem, "Name") %>'>
<%# DataBinder.Eval(Container.DataItem, "Text") %></a>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</div>
And finally to use it in a page after registering it, I have:
<uc:ContextMenu runat="server" OnCommand="SomeMethod">
<Items>
<uc:ContextMenuItem Name="SomeName" Text="SomeText" />
</Items>
</uc:ContextMenu>
Now when I run this, I get a NullReference parse error on line
<uc:ContextMenuItem Name="SomeName" Text="SomeText" />
When not running, Visual Studio also says Element 'ContextMenuItem' is not a known element. It doesn't catch the exception at runtime either so maybe that way I could look at the stack trace to see what's going on. I was just wondering if anyone has encountered similar issues like this. Any help is appreciated.
Create ContextMenuItem as a normal user control. The fact that you are defining it in the same namespace as you have emphasized doesn't help you in any way.
So, just add ContextMenuItem.ascx to your project and then register and add the control on page or other control.
I have a bunch of methods which manipulate the ASPX page elements and at this point it makes sense to encapsulate them into their own static object. However, it seems like I do not have access into the form elements outside of the ASPX page. Any ideas on how to go about this?
You need to pass the Page itself into the class, see the example below:
ASPX page
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txtTest" runat="server" Text="Test" />
</div>
</form>
Code-Behind
protected void Page_Load(object sender, EventArgs e)
{
Process p = new Process(this);
string s = p.GetTextBoxValue();
}
Class
public class Process
{
public Page thePage { get; set; }
public Process(Page page)
{
thePage = page;
}
public string GetTextBoxValue()
{
TextBox tb = (TextBox)thePage.FindControl("txtTest");
return tb.Text;
}
}
Process is probably not the best name for the class, but this is purely a demo.
Also, passing the Page object into another class tight couples that class to the Page object. I would recommend reconsidering your design of the class you're trying to make to not rely on the Page object entirely.
If you really want to encapsulate functionality, I guess you best create a class in which you pass the relevant elements to the constructor.
If you are aiming on reuse in other pages, you could create a base page from which you inherit. Another option is to do stuff in a master page that you refer from your pages.
I think a more detailed question is required to give a more detailed answer.
You need to pass Page object as one of the parameters to your class methods, this way its elements will be accessible inside the class.
For example if you have a class like:
public class CMyDataClass {
public bool CompareText(System.Web.UI.Page i_oPage) {
TextBox oTextBox = i_oPage.FindControl("TextBox1");
return (oTextBox.Text == "My Data");
}
}
You can use it like this from the page:
CMyDataClass oMyDataClass = new CMyDataClass();
if (oMyDataClass.CompareText(this)) {
Response.Write("Ok!");
}
I have a base usercontrol in my ASP.Net app, There are HTML markup within this usercontrol that are set to runat="server" and id's. The problem I am having is when the usercontrol is loaded, the HTML markup is being returned as null
ASP.Net C# code:
public partial class webonlinecustombase : System.Web.UI.UserControl
{
public Event Event { get; set; }
public OnlineSystemPageCustom custompage { get; set; }
public OnlineSystemPageCustom.OnlineSystemPageHdr.OnlineSystemPageModule custommodule { get; set; }
public void Page_Load(object sender, EventArgs e)
{
string typeName = custommodule.ModuleInternetFile;
inpagelink.HRef = "#" + custommodule.ModuleName.Replace(" ", "").Replace("/", "");
modtitle.InnerText = custommodule.ModuleName;
Type child = Type.GetType(typeName);
UserControl ctl = Activator.CreateInstance(child) as UserControl;
if (ctl != null)
{
this.modsection.Controls.Add(ctl);
}
}
}
Here is the HTML Markup:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="webonlinecustombase.ascx.cs" Inherits="IPAMIntranet.IPAM_Controls.webtemplatecontrols.webonlinecustombase" %>
<a id="inpagelink" runat="server"></a>
<span id="modtitle" runat="server" style="width:100%;text-align:left">Scientific Overview</span>
<div id="modsection" runat="server" style="width:100%;">
</div>
<p>Back to Top</p>
Why is the inpagelink and modtitle being returned as null?
I have seen this happen in web applications (not web sites) when changes are made to the source (especially setting runat=server on items that were not previously runat=server), but you don't switch to the designer view.
The way that I resolve this issue is to switch to design view and dirty a property in one of the fields. This usually causes VS to update the designer code-behind file.
You can double-check this file to ensure the controls have been added. If you check it prior to doing this, you should see that they are missing.
asp.net does'n have span class, so you cant do anything in code behind with it.
use LinkButton or HyperLink instead of
the other solution is to create span or a in code, something like this
var span = new HtmlGenericControl("span");
span.InnerHtml = "From<br/>Date";
span.Attributes["class"] = "blue";
placeholder.Controls.Add(span);
hope I helped :))
I have a user control which uses objects as inner properties (some code is below).
I am having trouble with setting the attribute of the Step class programmatically, when set programmatically it is being lost across postback which would indicate something to do with Viewstate (?).
When setting the property of the Step class declaratively it's working fine.
Does anybody have any ideas of what this code be/what's causing it to lose the state across postback?
ASPX Page
<uc1:StepControl ID="StepControl1" runat="server">
<Step1 Title="1. Select your Products" Enabled="true">
<Content>
<div class="clearfix">
<div class="floatRight">
<asp:Button ID="btnGoToStep2"
runat="server"
Text="Next"
CausesValidation="false"
OnClick="btnGoToStep2_OnClick" />
</div>
</div>
</Content>
</Step1>
<Step2 Title="2. Select your Features">
<Content>
<div class="clearfix">
<div class="floatLeft">
<asp:Button ID="btnBackToStep1"
runat="server"
Text="Back"
CausesValidation="false"
OnClick="btnBackToStep1_OnClick" />
</div>
<div class="floatRight">
<asp:Button ID="btnGoToStep3"
runat="server"
Text="Next"
CausesValidation="false"
OnClick="btnGoToStep3_OnClick" />
</div>
</div>
</Content>
</Step2>
</uc1:StepControl>
ASPX code behind
protected void btnGoToStep2_OnClick(object sender, EventArgs e)
{
StepControl1.Step1.StatusText = "4 Products Selected";
}
protected void btnBackToStep1_OnClick(object sender, EventArgs e)
{
// StatusText (of Step1) gets lost at this point.
}
User control code behind
public partial class StepControl : System.Web.UI.UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[NotifyParentProperty(true)]
public Step Step1 { get; set; }
[PersistenceMode(PersistenceMode.InnerProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[NotifyParentProperty(true)]
public Step Step2 { get; set; }
protected void Page_Init(object sender, EventArgs e)
{
AddSteps();
}
private void AddSteps() { }
}
[Serializable()]
[ParseChildren(true)]
[PersistChildren(false)]
public class Step
{
[PersistenceMode(PersistenceMode.Attribute)]
public string Title { get; set; }
[PersistenceMode(PersistenceMode.Attribute)]
public string Status { get; set; }
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateInstance(TemplateInstance.Single)]
[TemplateContainer(typeof(StepContentContainer))]
public ITemplate Content { get; set; }
public class StepContentContainer : Control, INamingContainer { }
}
I think the string you set never makes it to the ViewState. I am a bit short of terminology here (read: I do not know the terminology) but I think your attribute [PersistenceMode(PersistenceMode.Attribute)] only tells ASP.NET it should look for an attribute called "Status" in the markup (ASPX-file) and if it finds one, set the property Status to its value (actually I am wondering where exactly it is put in your example?). It does not tell anybody to put something into ViewState though.
If you would define your property Status along these lines
[PersistenceMode(PersistenceMode.Attribute)]
public string Status
{
get
{
object o = ViewState["Status"];
if(o != null) {
return (string)o;
}
return string.Empty;
}
set
{
ViewState["Status"] = value;
}
}
you should be better off.
For the rest of it I am not sure if you have to call TrackViewState() in UserControls or even override SaveViewState and LoadViewState but I do not think so. If this would be the case the following links might help:
Microsoft: Understanding ASP.NET View State
ASP.NET Forum: How to preserve ViewState in user control
It might have something to do with the order of the creation of your controls in the page. If after a postback, the controls are not created in the same order as for the first load of the page, then retreiving the viewstate willl not work for those controls.
How do you set the attribute of step programmatically?