Lets say I have a class that stores user information complete with getters and setters, and it is populated with data from an XML file. How would I iterate over all of the instances of that class like you would do with java beans and tag libraries?
For outputting formatted HTML, you have a few choices. What I would probably do is make a property on the code-behind that accesses the collection of objects you want to iterate over. Then, I'd write the logic for iterating and formatting them on the .aspx page itself. For example, the .aspx page:
[snip]
<body>
<form id="form1" runat="server">
<% Somethings.ForEach(s => { %>
<h1><%=s.Name %></h1>
<h2><%=s.Id %></h2>
<% }); %>
</form>
</body>
</html>
And then the code-behind:
[snip]
public partial class _Default : System.Web.UI.Page
{
protected List<Something> Somethings { get; private set; }
protected void Page_Load(object sender, EventArgs e)
{
Somethings = GetSomethings(); // Or whatever populates the collection
}
[snip]
You could also look at using a repeater control and set the DataSource to your collection. It's pretty much the same idea as the code above, but I think this way is clearer (in my opinion).
This assumes you can acquire all instances of your class and add them to a Generic List.
List<YourClass> myObjects = SomeMagicMethodThatGetsAllInstancesOfThatClassAndAddsThemtoTheCollection();
foreach (YourClass instance in myObjects)
{
Response.Write(instance.PropertyName.ToString();
}
If you don't want to specify each property name you could use Reflection, (see PropertyInfo) and do it that way. Again, not sure if this is what your intent was.
Related
The ASP.NET function ClientScript.RegisterClientScriptBlock can be used to register a chunk of JavaScript code that will be added to the page when it's rendered. The idea here is that you could have multiple instances of various user controls trying to register the same script over and over, but this ensures that it will only be included once.
The problem is, you don't really have any control over where the code is added to the page. This will insert the code inside the BODY tag of your page, but I need to add something (not limited to JavaScript code) into the HEAD block.
I'm well aware of various methods of adding something to the HEAD block via a ContentPlaceHolder block or by "Head.Controls.Add but these options do not address the problem of the same thing being added multiple times.
Is there an existing way to do this, or do I have to write a class that does something similar to ClientScript.RegisterClientScriptBlock except targeting the HEAD block?
I threw together a user control. There's nothing in the markup at all, so you can just add a new Web Forms User Control to your project and put this in the code behind:
public partial class ScriptControl : System.Web.UI.UserControl
{
private Dictionary<string, string> _scripts = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public void RegisterScript(string key, string script)
{
if(!_scripts.ContainsKey(key)) _scripts.Add(key, script);
}
protected override void Render(HtmlTextWriter writer)
{
writer.WriteFullBeginTag("script");
foreach(var script in _scripts.Values) writer.Write(script);
writer.WriteEndTag("script");
}
}
Just add the directive to your page markup:
<%# Register TagPrefix="uc" TagName="ScriptControl"
Src="ScriptControl.ascx" %>
(where "ScriptControl.ascx" is whatever you've named the control)
and then you can add it wherever you need to, including in the header.
<head runat="server">
<uc:ScriptControl id="HeaderScriptControl" runat="server"/>
</head>
The usage is pretty much the same:
HeaderScriptControl.RegisterScript("myScript",
#"alert(""hello, world!"")");
I have to move my UI page from a .cshtml file to an .aspx file. Now I'm having a couple of compiling errors.
First is that 'ViewBag' does not exist in the current context. Can I not use it in .aspx? If not, what is a good substitute?
Second, the .cshtml page had a model declaration:
#model myProject.Models.Navigation
I changed it so that it would work in the .aspx page as follows:
<%# Import Namespace="myProject.Models" %>
I'm still not sure that's a correct substitute, because I could not include the word "Navigation" without getting an error. And now, in the code where I used to have:
#foreach (myProject.Models.Navigationitem item in Model.navigationItems){...
I've replaced it with:
<% foreach (myProject.Models.Navigationitem item in Model.navigationItems){...
And I get this error:
The name 'Model' does not exist in the current context
Apparently, I'm the only guy who has ever gone from razor to aspx, because there's exactly zilch about it online. Appreciate any help.
WebForms don't usually use a ViewBag, which is just a way to make data available to your View in ASP.Net MVC. With WebForms, a nice way to make data available to your "View" (the aspx page containing the HTML) is to expose a property containing that data.
The MVC way might be to set ViewBag.MyValue = "Some Value"; in your Controller, and reference it in your view with <h1>#ViewBag.MyValue</h1>. To do the equivalent in WebForms you would first define a property in your codebehind:
protected string MyValue { get; set; }
Then, set the value somewhere, perhaps in your Page_Load:
protected void Page_Load (object sender, EventArgs e)
{
this.MyValue = "Some Value";
}
And write the value on the page using WebForms syntax:
<h1><%= MyValue %></h1>
For your specific case, you don't seem to actually be using ViewBag. That's ok, you can make objects available as properties also:
protected MyProject.Models.Navigation Model { get; set; }
protected void Page_Load (object sender, EventArgs e)
{
this.Model = SomeMethodThatReturnsModel();
}
With the property defined and the value set, the code you have above for your ASPX should work just fine.
Your page should have
<%# Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of myProject.Models.Navigation)" %>
at the top to specify the model type.
Instead of ViewBag, you can use ViewState, as shown in the example below.
private List<TrimPackage> Packages
{
get
{
return (List<TrimPackage>)ViewState["Packages"];
}
set
{
ViewState["Packages"] = value;
}
}
I have the following two pages:
Default.aspx
Default.aspx.cs
How do I access variables in the code-behind file (Default.aspx.cs) from my embedded code in (Default.aspx) with the <% %> syntax?
Any public or protected (but not private, the "page" itself inherits from the code-behind Page class) class-level member can be accessed in this way. For example, if your code-behind class has a property:
protected string SomeValue { get; set; }
Then in your aspx code you can refer to it:
<% =SomeValue %>
Simply reference them as if they are part of the current class.
<%= this.Foo %>
If you don't specify the access modifier for the variable the default is private and hence you cannot access it inside your page. It works for public, protected and friend. I prefer to use protected variables than public ones.
as the title said is SqlDataSource can be shared across different aspx page?
i have exact same sqldatasource on multiple aspx page, is it possible to create one and shared for all the pages.
thanks
Sure. If you really mean shared, as in all pages use the same SqlDataSource, create a Master Page and put the data source in the master. In the codebehind, expose it as a property of the master. From there, you can reference it from any page that uses the Master.
Second option - create a base Page class:
public class MyPage : Page
{
private SqlDataSource mDataSource;
public override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// some code to init your data source - depending on your
// implementation, this may need to be in OnInit instead
}
public SqlDataSource DataSource
{
get { return mDataSource; }
}
}
In this case, any time you create a new page, go to the code behind and change the declaration from implementing Page to MyPage. All pages that implement MyPage will have an SqlDataSource member, though each would have its own instance, so that's not really "sharing" the same SqlDataSource.
Either option gets you where you want to go I think.
UPDATE: Poster requested an example of exposing in as a property of the master:
Given a Master Page with the following:
<asp:SqlDataSource runat="server" ID="mDataSource" ... the rest of your properties .... />
<asp:ContentPlaceHolder runat="server" ID="MainContent"/>
In the code-behind for the master, define the property:
public class SiteMaster : System.Web.UI.MasterPage
{
public SqlDataSource MasterDataSource
{
get { return mDataSource; }
}
// the rest of your master page's codebehind
}
In the pages you define for using your master page, add the following below the #Page declaration:
<%# MasterPage VirtualPath="~/site.master"%>
Now, in the codebehind for that page, you can reference:
protected void Page_Load(object sender, EventArgs e)
{
SqlDataSource ds = this.Master.MasterDataSource;
}
As long as you have as long as you have a <%# MasterType VirtualPath="~/ PATH TO YOUR MASTER" %> in your aspx page, you can reference any properties you expose in the master.
Happy coding.
B
Controls are specific to pages. To share it across pages put it in a UserControl and then expose it through the public property of the UserControl.
If you mean the connection string, the answer is yes. You can put it in a public shared class.
If you mean the connection being open during several pages. No.
You should always close the connection ASAP to avoid memory leaks.
I have a UserControl that is working fine. It is declared like this.
public partial class DynamicList : System.Web.UI.UserControl
{
protected static BaseListController m_GenericListController = null;
public DynamicList()
{
m_GenericListController = new GenericListController(this);
}
}
Now I want to override this control so I can change some of the properties. I have created a class like this.
public partial class JobRunningList : DynamicList
{
public JobRunningList()
{
m_GenericListController = new JobListController(this);
(m_GenericListController as GenericListController).ModuleId = 14;
}
}
It appears that the controls in the DynamicList are not getting created though when I use the JobRunningList control now causing predictably bad results. The DynamicList UserControl has a ListView on it and a few other controls. It appears these are not created when using the JobRunningList. Is there any secret to this?
The boring workaround would be to make JobRunningList as plain old user control that contains a DynamicList and just sets the properties of the inner control in its OnLoad. That's awkward if DynamicList has many other properties that you want to access from the page though, as JobRunningList would have to define matching properties of its own. Getting back to the inheritance approach, then...
The DynamicList class just contains the code behind logic, so what you're doing works nicely if you want the second control to reuse the logic behind the first but provide a new UI of its own.
The markup in your .ascx file gets compiled into another class that inherits DynamicList, so if you can get your JobRunningList class to inherit that class instead of DynamicList, you'll get the result you want. This class gets a default name derived from the filename, but you can avoid guessing that by setting a ClassName in the control directive to use instead of the automatic name.
Take a simple base control like
<%# Control Language="C#" AutoEventWireup="true"
CodeFile="HelloControl.ascx.cs" Inherits="HelloControlBase"
ClassName="MyControls.HelloControl" %>
Hello <%= Name %>
with an unexciting code-behind like
public partial class HelloControlBase : System.Web.UI.UserControl
{
public string Name
{
get;
set;
}
}
Now we want to override the Name property in a new control. First we need HelloAlice.ascx
<%# Control Language="C#" AutoEventWireup="true"
CodeFile="HelloAliceControl.ascx.cs"
Inherits="HelloAliceControl" %>
Not much to see here, since we're leaving all the work to the original ascx. Now in the code-behind,
public partial class HelloAliceControl : MyControls.HelloControl
{
protected void Page_Load(object sender, EventArgs e)
{
this.Name = "Alice";
}
}
We just inherit MyControls.HelloControl and set the Name property, and it looks like we're done.
The problem is knowing when MyControls.HelloControl is visible. As long as your derived control is in the same directory as the parent control you'll probably be OK, otherwise it's quite easy to run into build errors complaining that the class doesn't exist because the parent control hasn't been compiled yet.
If I understand correctly, you want the interface to be the same. In that case, I would create some properties instead. Perhaps just a simple enumeration i.e. ListType.