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.
Related
It's been a while since I worked on WebForms so I need a refresher when working on an old site.
I have a userControl on the page that I need to programatically set the enabled state
<%# Register Src="CalandarControl.ascx" TagName="CalandarControl" TagPrefix="uc" %>
I have this at the C# code but Enabled is not available here. What am I missing?
if (c is UserControl)
{
var x = c.GetType();
if (x.Name == "calendarcontrol_ascx")
{
((UserControl)c).Enabled = true;
}
}
Thanks
You should have something on the code-front that places the control on the page, like:
<uc:CalendarControl ID="dtePrepaymentExpiresDate" FieldName="Prepayment expires date" runat="server" Enabled="false" />
Then in the code behind, you can set this custom property as follows:
dtePrepaymentExpiresDate.Enabled = true;
If you really need to do it in the loop, then you need to cast c as the CalendarControl and not UserControl because CalendarControl has the property Enabled while a normal UserControl does not.
((CalandarControl)c).Enabled = true;
you can define a panel in usercontrol witch cotaines all of controls of the user control, then define a property Enabled named as bool (panelMain.Enabled;) and from ur page set it,
in user control ascx
<asp:panel runat="server" id="panelMain" Enabled="false">
<!-- define ur other controls between panel-->
</asp:panel>
in usercontrol ascx.cs
public bool Enabled
{
get { return panelMain.Enabled; }
set { panelMain.Enabled = value; }
}
in page first register ur usercontrol and then set Enabled property from code behind ....
for example
protected void Page_load(object sender,EventArgs e )
{
panelMain.Enabled = true;
}
as simple as drink water :))
This is my ascx Code:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="Demo.ascx.cs"
Inherits="Demo" %>
<asp:HiddenField ID="hidden" runat="server" Value="" />
And the aspx:
<%# Register TagName="Hidden" TagPrefix="CRS" Src="~/Demo.ascx" %>
<div>
<CRS:Hidden ID="hid" runat="server" />
</div>
Now How to access Hidden variable ID From ascx page to this cs page backend
Do you mean the actual ID? or the Value within the hidden field?
You can access the value using the FindControl method
HiddenField hf = (HiddenField)this.hid.FindControl("hidden");
string theValue = hf.Value;
Not sure if this is exactly what you are looking for.
Alternatively, you can declare some public properties in the UserControl in which you can access directly
In the ascx code:
public string theValue { get; set; }
In the aspx code:
string theValue = this.hid.theValue;
To access the HiddenField inside the UserControl from the asp.net web page you will need to wire up something called a Public Property.
This code should be added to the UserControl ascx.cs code behind:
public string Value
{
get { return hidden.Value; }
set { hidden.Value = value; }
}
You could then write code like this in your asp.net page:
string SomeHiddenValue = hid.Value;
hid.Value = "Its a secret!";
Note: I haven't compiled this so I am not sure if the public property name of Value will compile. I am also not sure if the second value in set { hidden.Value = value; } needs capitalising. Try changing these two values if you encounter problems.
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.
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 am trying to add a template to a simplified composite control containing a Label and a TextBox. I want my mark up to look something like this:
<test:FormItem ID="fi" runat="server" Title="MyTitle" Text="My Text!">
<TestTemplate>
<i>
<%# Container.Title) %></i>
<br />
<%# Container.Text %>
</TestTemplate>
</test:FormItem>
I have a templateContainer class that has properties for the TextBox and Label.
public class TemplateContainer : WebControl, INamingContainer
{
public TextBox Text { get { return m_item.Text; } }
public Label Title { get { return m_item.Title; } }
private FormItem m_item;
public TemplateContainer(FormItem item)
{
m_item = item;
}
}
In the main FormItem class I have a CreateControlHierarchy() method that is being called from CreateChildControls():
protected virtual void CreateControlHierarchy()
{
m_itemTemplateContainer = new TemplateContainer(this);
TestTemplate.InstantiateIn(m_itemTemplateContainer);
Controls.Add(m_itemTemplateContainer);
}
What I WANT is for the Template to render the actual control. Instead, it's calling ToString() on the control and displaying System.Web.UI.WebControls.Label and System.Web.UI.WebControls.TextBox. Is there a way to make the template add the controls to it's collection instead of just calling ToString() on them?
Note: I've also tried adding the textbox and label to the controls collection of the container which does the same thing.
Ok. So I tried a few things and I came up with an OK solution.
First, I tried to use methods in the data binding expression and then keep track of where in the container's Control collection the textbox or label would go. However, the CompiledTemplateBuilder (which is what .Net internally builds for ITemplates specified in mark up) put all of the markup before and after both binding expressions into one DataBoundLiteral control and the Control collection was already built when the method was called.
What did work was to create a new WebControl which serves as a place holder for the controls within the composite control. It has one property Control and when set, it add the control to it's Controls Collection.
public class FormItemPlaceHolder : WebControl, INamingContainer
{
public WebControl Control
{
get
{
if(Controls.Count == 0)
return null;
return Controls[0] as WebControl;
}
set
{
if (Controls.Count != 0)
Controls.Clear();
Controls.Add(value);
}
}
}
Then in the mark up, I create a control of this type and bind it's Control property to the correct property in the container.
<test:FormItem ID="fi" runat="server" Title="MyTitle" Text="My Text!">
<TestTemplate>
<i>
<test:FormItemPlaceHolder ID="ph" runat="server"
Control='<%# Container.Title %>' />
</i>
<br />
<test:FormItemPlaceHolder ID="ph2" runat="server"
Control='<%# Container.Text %>' />
</TestTemplate>
</test:FormItem>
Does anyone have a better solution?
The container should not define the controls, just the data.
It is in the markup that you should define the actual controls of the data, and assign them the values in from the container.
E.g.
public class TemplateContainer : UserControl
{
public string Text { get { return m_text; } }
public string Title { get { return m_title; } }
private string m_text;
private string m_title;
private FormItem m_item;
public TemplateContainer(FormItem item)
{
m_item = item;
}
}
And in the markup:
<test:FormItem ID="fi" runat="server" Title="MyTitle" Text="My Text!">
<TestTemplate>
<i><asp:Label runat="server" Text='<%# Container.Title) %>' /></i>
<br />
<asp:TextBox runat="server" Text='<%# Container.Text %>' />
</TestTemplate>
</test:FormItem>
If you are trying to create a composite control that does not require controls to be added in the markup, then why are you using a Template? If it is just for styling then perhaps creating your own Style object may be more effective?