I've created a UserControl that contains a grid.
In main page, users can select options from a combo, then, I need to generate a UserControl for each option that user's selected.
I've 2 problems:
I need to pass the parameters to the user control for configure the grid's datasource, but I don't know how to do it.
If I set default parameters for test, when a PostBack occurs, the user controls are removed.
I don't see any code of yours, so I leave you a simple example here.
First, define a property for the value you need to pass in:
public partial class SomeControl : System.Web.UI.UserControl
{
public int AProperty { get; set; }
...
}
So then, from the aspx where you need to use your user control, first register it as usual:
<%# Register Src="~/MyControls/SomeControl.ascx" TagPrefix="my" TagName="SomeControl" %>
And later use it, and pass the value to the property, like this:
<my:SomeControl runat="server" ID="SomeControl1" AProperty="1" />
You can also set that property from the code behind of your aspx which contains the control, like this:
SomeControl1.AProperty = 1;
Dynamic controls
You can create this controls dynamically like this:
var ctrl = new SomeControl();
ctrl.AProperty = 1;
And later add those controls to a <asp:PlaceHolder in your aspx:
somePlaceHolder.Controls.Add(ctrl);
Upon postback (ie on selectedindexchanged of a dropdownlist), all the controls inside that place holder will desappear, but the information is still in your viewstate, so all you need to do is recreate the corresponding controls inside the same placeholder and the old values from viewstate will be attached to the recreated controls.
Related
I have following user control my .ascx Page. (Test.ascx)
<uc:Addresses runat="server" itemId='<%# StringId %>'></uc:SNETAddresses>
In the code behind of Test.ascx I have
protected string StringId = "{2A06199B-ED96-42F0-AB9A-602139E58BFB}";
In the code behind of user control Addresses.cs I have:
public string itemId { get; set; }
So basically I want to pass a string to the variable itemId. But Somehow its not getting the value of variable "StringId". This simple thing is taking my so much time. I checked this post asp.net passing string variable to a user control but I am so sorry I could not get the answer. The reply is:
You may need to call DataBind on your Page in CreateChildControls or some other method
I am new to Asp.Net and I didn't get what the user mean here.
You need to call Page.DataBind(), e.g. in your Page_Load() event handler.
Data-binding expressions (<%# ... %>) are only processed when you call the DataBind() method.
Alternatively (instead of using a data-binding expression), you can also simply assign the value to the user control's property from your page's code-behind:
// add an ID to the user control (in the markup)
<uc:Addresses runat="server" id="myControl"></uc:SNETAddresses>
Then in your Page_Load() method simply assign the value to the user control's property:
myControl.itemId = StringId;
Is it possible to implement custom UserControl or Control, which will act like a PlaceHolder, but with my logic? Example of using:
<x:MyControl runat="server">
<Template>
<asp:TextBox runat="server" ID="MyTextBox" />
..... any custom code here ........
</Template>
</x:MyControl>
And then in code-behind:
MyTextBox.Text = "ABC";
I implemented test control, but I am unable to access nested ASP controls on the page level. Error is The name "MyTextBox" does not exist in the current context.
You must call the function "FindControl" in you user control MyControl.
Name you MyControl with and id="mcContainer", then on your code behind call ((TextBox)mcContainer.FindControl("MyTextBox")).Text = "ABC";.
Wiki about this here How to: Create Templated ASP.NET User Controls
Why can I write MyTextBox.Text="ABC" when it is in the Page and why isn't that possible when the text box is inside of naming container implemented by a user control?
Well, when you drag N dropped your text box the ASP.NET Page designer declared a variable for you in the partial class of your page reserved for the designer itself, is in that designer part of your class that your controls in you page are declared.
So when you drag and drop your user control, and create a text box inside of it's naming container you can't access it directly because your page doesn't hold a reference to that control, the reason for that is because that control will only be available at runtime during the instanciation of the user control itself, the motive is related in part with the way that ASP.NET page parser renders controls.
Quoting this resource:
When working with composite controls it is important to be familiar with a number of properties and methods, as well as with the INamingContainer interface. All composite controls should implement the INamingContainer interface. Controls that implement this interface do not need to add any methods or properties; rather, the implemented interface merely indicates that the control is being used as a composite control. The effect is that child controls—that is, controls in the composite control's Controls collection—are rendered so that their ID is prefixed with the ID of the control's naming container. This ensures that all the child controls will have unique ID values, even if there are multiple instances of the parent control on a Form. The WebControl class has a NamingContainer property that returns the control's parent.
So, when you write MyTextBox, your text box name should at least something like $mcContainer$MyTextBox. So because of this there is no way to transparently do what you intend.
Solution.
Create class like this:
public class ToolTip : PlaceHolder
{
protected override void CreateChildControls()
{
HtmlGenericControl div1 = new HtmlGenericControl("div");
div1.Attributes.Add("id", ClientID);
div1.Attributes.Add("class", "tooltip");
while (Controls.Count != 0)
div1.Controls.Add(Controls[0]);
Controls.Add(div1);
}
}
Then register it in ASPX file like this:
<%# Register Assembly="YOUR_ASSEMBLY" TagPrefix="x" Namespace="YOUR_NAMESPACE" %>
Then use it like this:
<x:ToolTip runat="server">
... any your content here ......
</x:ToolTip>
Now you are able to nest any controls inside of x:ToolTip and add any composition logic to CreateChildControls().
A few weeks back I created a Templated User Control, for the most part based on the example here:
http://msdn.microsoft.com/en-us/library/36574bf6(v=VS.90).aspx
The difference is that I did not implement the "MessageContainer" class as I wanted just an empty template that I could add whatever controls I wanted to at design time.
This TUC has been working great, but I ran into a scenario I hadn't anticipated when I created the thing. The need to dynamically add this TUC to a page, which means that I would need to dynamically add the controls within the template of the TUC as well.
I found another example here on how to dynamically create a Template and add it to the Templated Control:
http://msdn.microsoft.com/en-us/library/y0h809ak(v=vs.71).aspx
This second example article discusses only the "DataList, Repeater, and DataGrid controls" but I figure since I am using the ITemplate interface here, it should be the same thing.
However, I am unable to get this to work, I keep getting an "Object reference not set to an instance of an object." error when I attempt to populate the TUC.
Here's what I am doing....
Like the example above I created an ITemplate class:
public class XPCTemplate : ITemplate
{
private readonly Control _control;
public XPCTemplate(Control control)
{
_control = control;
}
public void InstantiateIn(Control container)
{
container.Controls.Add(_control);
}
}
Then, in the test page code-behind I attempt to load up and display the TUC dynamically:
ExpandCollapseRegion xpcRegion; // The Templated User Control
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder ph;
// .... code here to dynamically create some labels, textboxes, etc. ....
// Create an instance of the TUC
xpcRegion = new ExpandCollapseRegion();
// Pass into the TUC's template the controls dynamically created above
xpcRegion.LayoutTemplate = new XPCTemplate(ph);
// add the dynamic TUC to the page
phDynamicUC.Controls.Add(xpcRegion);
phDynamicUC.Controls.Add(new LiteralControl("<br />"));
}
Test page HTML Source:
<body>
<form id="form1" runat="server">
<div>
Dynamically Loading User Control
<br />
<asp:PlaceHolder ID="phDynamicUC" runat="server" />
</div>
</form>
</body>
When I run the page, I get the "Object reference not set to an instance of an object" error on the "container.Controls.Add(_control);" line of the XPCTemplate class. When I debug the test page and TUC control, the code of the TUC receives the XPCTemplate into its LayoutTemplate during the TUC's Page_Init() method, but when the InstantiateIn() event back in the XPCTemplate fires immediately afterwards, the "container" argument is NULL.
I'm not sure why this is happening, it's like the InstantiateIn() method of the XPCTemplate class is trying to actually set the PlaceHolder control within the TUC rather than just passing the contents. Maybe this is supposed to be the way and I am missing something on the TUC side to allow this behavior?
This is the first TUC I have created and likewise the first time trying to dynamically fill/load it, so I am sure I am missing something needed to accomplish this. Any help is greatly appreciated.
-- Andrew
Found the solution to the problem, which was how I was loading the TUC.
Incorrect:
xpcRegion = new ExpandCollapseRegion();
Correct:
xpcRegion = (ExpandCollapseRegion)LoadControl("ExpandCollapseRegion.ascx");
Making this simple change took care of the problem. Also, found that I could forego the need for a custom ITemplate class by using the CompiledTemplateBuilder() method. Really simplifies the code.
-- Andrew
I believe the problem is that you haven't instantiated your PlaceHolder ph that you are passing into your template. So, the line it is complaining on is because it can't add the control to the PlaceHolder because it is null/nothing.
Also, I believe you're going to need to put your placeholder somewhere. Otherwise, you're adding items to a container that is never added to the page.
I have a usercontrol which contains a textbox. I now want to add variable to that user control, lets call it Text, which will populate the textbox with the value passed in. I thought this could be done in the "set" of the variable in the code behind of the user control.
public string Text
{
get {}
set
{
txtBox.Text = value;
}
}
txtBox is the ID of the textbox within the usercontrol. Does anyone know how this can be done?
Thanks
Edit
The problem I suspect is that I am setting the text value in the Page_Load of the page hosting the user control. Where should I be setting this value?
If your problem is that txtBox is null then I can suggest you the following:
If you're creating a user control dynamically then don't forget to add it to the page's control tree BEFORE (implicitly or explicitly) accessing its child controls. Otherwise all these child controls will remain uninitialized:
MyUserControl ctrl = (MyUserControl )Page.LoadControl("~/MyUserControl.ascx");
base.Controls.Add(ctrl);
ctrl.Text = "some value";
If your user control is declared in the page's markup then don't forget to register using the Register directive with the "Src" property set to location of your user control:
<%# Register TagPrefix="controls" TagName="MyUserControl"
Src="~/MyUserControl.ascx" %>
<controls:MyUserControl id="ctrl1" Text="some value" runat="server" />
Registering the user control using the following technique WILL NOT work (not the case if all child controls are created dynamically. But then you don't need a user control - you just need a class derived from the Control class):
<%-- Will not work for user controls --%>
<%# Register Assembly="MyControlsAssembly.Shell" Namespace="MyControls"
TagPrefix="controls" %>
Hope this will help you.
When defining the markup for an asp gridview and the tag Columns, one can only choose from a predefined set of controls to add within it (asp:BoundField, asp:ButtonField etc).
Im curious about if i can add the same type of behavior, say restricting the content to a custom control with the properties "Text" and "ImageUrl" to a TemplateContainer defined in a standard usercontrol and then handle the rendering of each element within the container from code behind somehow?
Alright i finally solved it, which means i can do the following
<%# Register src="~/Controls/Core/ContextMenu.ascx" tagname="ContextMenu" tagprefix="uc" %>
<%# Register Assembly="App_Code" Namespace="Core.Controls.ContextMenu" TagPrefix="cc" %>
<uc:ContextMenu ID="ContextMenuMain" runat="server">
<Items>
<cc:ContextMenuItem Text="New" ImageUrl="..." />
<cc:ContextMenuItem Text="Save" ImageUrl="..." />
</Items>
</uc:ContextMenu>
Where each ContextMenuItem is a custom class in app code, notice that i have to register the app_code assembly in order for the markup to recognize the class.
The namespace points to the location of the class.
For the code behind of the usercontrol we just add this:
private List<ContextMenuItem> items = new List<ContextMenuItem>();
[PersistenceMode(PersistenceMode.InnerProperty), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<ContextMenuItem> Items
{
get
{
if (items == null)
{
items = new List<ContextMenuItem>();
}
return items;
}
set
{
items = value;
}
}
Which can be processed by the usercontrol when its time to render :)
FYI The fields (asp:BoundField, asp:ButtonField etc) are not actually controls but are instead derived from the DatControlField class. Likewise, the columns property is not a ITemplate but is a DataFieldCollection.
Something like that should be possible if your controls all derive from the same class or implement the same interface.
I'm thinking maybe you want something like this:
http://www.developer.com/net/asp/article.php/10917_3609991_1
If you want to create a custom column type for a GridView, you need to start out by deciding what goes in each cell of the column. Is it just a TextBox or Button? Or is it something more complicated? If it's more complicated, you need to create your own template class by inheriting from ITemplate.
Once you have that done, you need to write a class that inherits from the proper column type (BoundField, ButtonField, etc. for simple columns or TemplateField if you need to plug in your own template).
You can create your own properties for your custom column class (e.g., Text and ImageUrl), but if it's a TemplateField, you will have to actually loop through your cells to manipulate the data of the controls that comprise each cell. This is not hard to do, but it's not as easy as just using a BoundField and setting DataField property.