I have a CompositeDataBoundControl defined as below:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="ReportSection.ascx.cs" Inherits="WebReports.ReportSection" %>
<div class="report-section span-24">
<h3>
<%= Title %></h3>
</div>
public partial class ReportSection : CompositeDataBoundControl
{
public string Title { get; set; }
protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
{
//throw new NotImplementedException();
return 1; // JUst something to avoid exceptions.
}
}
Yet when I try and load a web form containing this control, I get the following parser error:
'WebReports.ReportSection' is not allowed here because it does not extend class 'System.Web.UI.UserControl'.
This seems very odd to me, because I get the impression that CompositeDataBoundControl is intended as a base class for user controls, or is it perhaps only for use with server controls?
It is intended for server controls, not UserControls. UserControls are more similar to Pages than to other controls (both inherit from TemplatedControl).
You can see from the MSDN description for CompositeDataBoundControl that it's not really intended for user controls:
Represents the base class for a tabular data-bound control that is
composed of other server controls.
Related
I've created a templated ASP.NET user control based on the RadDock control. However, when adding such a control to a RadDockZone causes a runtime error stating that it can only contain RadDock controls. Is there any way to solve this?
Templated user control markup
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="TemplatedDock.ascx.cs" Inherits="TemplatedDock" %>
<telerik:RadDock ID="RadDock1" runat="server" EnableAnimation="True" DockHandle="Grip" Resizable="True">
<ContentTemplate>
<asp:PlaceHolder ID="dockPlaceholder" runat="server"></asp:PlaceHolder>
</ContentTemplate>
</telerik:RadDock>
Templated user control code-behind
public partial class TemplatedDock : System.Web.UI.UserControl
{
private ITemplate _content;
[TemplateContainer(typeof(ContentContainer))]
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateInstance(TemplateInstance.Single)]
public ITemplate Content
{
get
{
return _content;
}
set
{
_content = value;
}
}
void Page_Init()
{
if (_content != null)
{
ContentContainer container = new ContentContainer();
_content.InstantiateIn(container);
dockPlaceholder.Controls.Add(container);
}
}
}
public class ContentContainer : Control, INamingContainer{}
}
Usage in RadDockZone
<telerik:RadDockZone ID="RadDockZone1" runat="server">
<a:TemplatedDock>
<Content>
<telerik:RadGrid ID="someGrid" runat="server"></telerik:RadGrid>
</Content>
</a:TemplatedDock>
</telerik:RadDockZone>
There is no way for this to happen. A RadDockZone must have only RadDock controls as children. Custom controls have a different type and will, therefore throw an exception.
The zone is tightly coupled with the dock to offer easy integration like drag-drop, state saving, etc., and this has its price.
I saw on several web pages how to interface to a public method defined in a master file from a web page call behind code that uses that master file.
(I am using ASP.Net 4.0 on Visual Studio 2012.)
The procedure is (copied from article):
Make sure the function is accessible to the page (i.e. declared
public), and use the MasterType declaration in the ContentPage:
<%# Page .... %>
<%# MasterType VirtualPath="~/masterpage.master" %>
In the page, use Page.Master.MyFunction() to access the function.
*Note: before being able to access the function, you'll need to save & build.
The problem is that I do not see the method. Here is what I have:
Web Page (stored in /MyFolder, so /MyFolder):
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Logout.aspx.cs" Inherits="BvCorpMain.Candidates.Logout" %>
<%# MasterType VirtualPath="/SiteMasters/Site.Master" %>
Site.Master CS file (stored in /SiteMasters folder):
public void UpdateUserBlocksToCookie()
{
}
When I go into the code behind for the logout page and in a method I type in "Page.Master.", I do not see my method.
Your page is inheriting from System.Web.UI.Page, which only knows that its master page is of type System.Web.UI.MasterPage. If you are making modifications to a child class of MasterPage, then you need to cast the Page.Master property to your child class.
public class MyPage : System.Web.UI.Page
{
public new MyMaster Master { get { return base.Master as MyMaster; } }
public void Page_Load(object sender, EventArgs e)
{
Master.MyMasterPageFunction();
}
}
public class MyMaster : System.Web.UI.MasterPage
{
public void MyMasterPageFunction()
{
}
}
The previous answer did educate me, however I believe the resolution was to restart VS2012, maybe cleaning the solution and rebuilding did not hurt. Either way.
Microsoft adds in the following code automatically to the .aspx.designer.cs file.
/// <summary>
/// Master property.
/// </summary>
/// <remarks>
/// Auto-generated property.
/// </remarks>
public new MyNamespace.Site Master {
get {
return ((BvCorpMain.Site)(base.Master));
}
The previous answer conflicts with this definition. Also, the previous answer of MyMaster, although granting access does not give (automatically at least) to needed form information. I checked. Using the existing master file is the cleanest.
The definition for the master.cs file is:
namespace MyNamespace
{
public partial class Site : System.Web.UI.MasterPage
As you can see, Microsoft did give access to MyNamespace.Site, which is what I needed, with "Master.".
I did not think to check the .aspx.designer.cs file for that definition, when I was having the problems. Possibly the definition was lacking and got added later, when either I rebuilt or did a save, which I had previously done, or whatever.
Knowing the addition does simplify things, as I can add that in manually if it does not exist using that construct.
I've written a templated user control, MinimalTemplate, which currently does nothing other than render the HTML passed into its "ContentTemplate" placeholder. I want Visual Studio 2008 to have the same intellisense features for MinimalTemplate that it has for built-in templated controls such as Repeater.
Possibly related: I can manually type out my ContentTemplate tags, and it will build and run properly, but I get a validation error. I have already deleted the contents of my ReflectedSchemas folder, as suggested in this question.
Complete source for Minimal Template:
MinimalTemplate.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="MinimalTemplate.ascx.cs" Inherits="MyProject.MinimalTemplate" %>
<asp:placeholder runat=server id="contentPlaceHolder" />
MinimalTemplate.ascx.cs
using System.Web.UI;
namespace MyProject
{
[ParseChildren(false)]
public partial class MinimalTemplate : System.Web.UI.UserControl
{
[TemplateContainer(typeof(MessageContainer))]
[TemplateInstance(TemplateInstance.Single)]
public ITemplate ContentTemplate
{ get; set; }
void Page_Init()
{
if (ContentTemplate != null)
{
MessageContainer container = new MessageContainer();
ContentTemplate.InstantiateIn(container);
contentPlaceHolder.Controls.Add(container);
}
}
public class MessageContainer : Control, INamingContainer { }
}
}
What changes can I make to my MinimalTemplate code so that Visual Studio will validate and autocomplete its ContentTemplate tag?
Related.
Add [PersistenceMode(PersistenceMode.InnerProperty)] to ContentTemplate's attribute list. After adding it and rebuilding, the validation error disappeared and "ContentTemplate" appeared as expected in the Intellisense dropdown.
During my investigation, I'm certain I tried adding this property two or three times to no effect, so I expect the VS validator is a bit flaky. It smacks of voodoo programming, but do a Clean/Rebuild All and wait a few seconds before seeing whether the validation error persists.
(Also, you don't need the ParseChildren attribute for this control.)
I'm working with Templated User Control's. In the final markup of the control, the data is being accessed by the Container keyword. I'm using the word 'keyword' freely, because I do not understand whether this is a keyword, or where the Container word is coming from. Below is an example from my book.
//Address User Control markup
<%# Control Language="C#" AutoEventWireup="true"
CodeFile="AddressUcTemplated.ascx.cs" Inherits="AddressUcTemplated" %>
<asp:PlaceHolder runat="server"
ID="PlaceHolderAddressTemplate">
</asp:PlaceHolder>
--
//Address User Control code-behind
public partial class AddressUcTemplated :
System.Web.UI.UserControl
{
protected void Page_Init(object sender, EventArgs e)
{
//clear the controls from the placeholder
PlaceHolderAddressTemplate.Controls.Clear();
if (LayoutTemplate == null)
{
PlaceHolderAddressTemplate.Controls.Add(
new LiteralControl("No template defined."));
}
else
{
AddressUcContainer container = new
AddressUcContainer(this.Address);
this.LayoutTemplate.InstantiateIn(container);
//add the controls to the placeholder
PlaceHolderAddressTemplate.Controls.Add(container);
}
}
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(AddressUcContainer))]
public ITemplate LayoutTemplate { get; set; }
public Address Address { get; set; }
}
--
//Naming Container Class
public class AddressUcContainer : Control, INamingContainer
{
public AddressUcContainer(Address address)
{
this.Address = address;
}
public Address Address { get; set; }
}
--
//Page using the user control; the Container keyword is confusing me in the below //statement
...
<%# Register src="AddressUcTemplated.ascx" tagname="AddressUcTemplated"
tagprefix="uc1" %>
<uc1:AddressUcTemplated ID="AddressUcTemplated1"
runat="server" AddressType="Home">
<LayoutTemplate>
<h1>Edit Home Address</h1>
<table>
<tr>
<td>Address Line 1:</td>
<td>
<asp:TextBox ID="TextBoxAddress" runat="server"
Text="<%#Container.Address.AddressLine1%>"></asp:TextBox>
...
My example code is as follows:
<asp:Repeater runat="server">
<ItemTemplate><%# Container.DataItem %></ItemTemplate>
</asp:Repeater>
Intellisense states that Container is a field/variable of type RepeaterItem. The variable-part tells me that this is some special parsing, since it would most probably been a property if it was public stuff.
Anyway, my code is parsed into, amongst other, the following databinding code:
public void __DataBind__control4(object sender, EventArgs e) {
var target = (DataBoundLiteralControl)sender;
var Container = (RepeaterItem)target.BindingContainer;
target.SetDataBoundString(0, Convert.ToString(Container.DataItem, CultureInfo.CurrentCulture));
}
<%# ... %> is a DataBoundLiteralControl, and Container is the variable that's exposed to intellisense. This also shows that there's a target variable, which does not show up in intellisense, but compiles without any problems. Note that this also gives you access to everything private in the generated class, like __fileDependencies.
<%# target %> works, while <%# dummy %> doesn't. And while at it, <%# __DataBind__control4(null, null) %> creates two compilation errors, 1) "The best overloaded method match for 'System.Convert.ToString(object, System.IFormatProvider)' has some invalid arguments" and 2) "Argument 1: cannot convert from 'void' to 'object'".
This looks like a simple case of whatever is written between <%# ... %> is placed in Convert.ToString(..., CultureInfo.CurrentCulture). It's probably more advanced, involving different ControlBuilders, TemplateParsers, and an ounce of magic, but I think my abstraction works well enough to understand this.
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.