I add some div into a panel on server side, when the page is generated, and I add a ID for each one :
HtmlGenericControl divContainerInside = new HtmlGenericControl("div");
divContainerInside.ID = "inside_" + m_oIDCategoria + "_" + numero;
than, on postback (after re-creating them), I cycle them :
foreach (HtmlGenericControl divInside in myPanel.Controls.OfType<HtmlGenericControl>())
{
Response.Write(divInside.ID);
}
all is ok! But, if I remove that divContainerInside.ID when I generate it, I get a NullException cycling them. Why?
I guess you get NullException when you try to read the ID, which you haven't set.
If you change your code like this, you'll get the value:
foreach (HtmlGenericControl divInside in myPanel.Controls.OfType<HtmlGenericControl>())
{
Response.Write(divInside.ClientID);
}
PS: I don't know if you have got this line of code:
myPanel.Controls.Add(divContainerInside);
If you want to find out more about web controls you can read this article and this.
You cant add a control to the page using response.Write you need to add it to the Pages or another controls control collection like below:
Page.Controls.Add(divInside);
Related
I am trying to read the value from an attribute I have added to a UserControl. Here is how I am implementing this.
The user control is added to my page as follows.
<uc1:myUserControl runat="server" id="myUserControl" />
From that pages code behind file. I have added the following attribute to this control to enable some configuration of how the user control will behave when loaded onto this page.
myUserControl.Attributes.Add("configSize", "Small");
The issue I then have, is making use of that value ('Small') from the UserControls code-behind page. I can iterate through the AttributeCollection, but I can only seem to be able to access the key ('configSize') and so the only thing I can then output is that key name. I am actually after it's value. This then lets me set some sizing config on the user control.
This is how I am at least getting 'something' to show, in this case just the key name. I have no idea how I can fetch that keys value.
IEnumerator keys = this.Attributes.Keys.GetEnumerator();
int i = 1;
while (keys.MoveNext())
{
test.InnerHtml = test.InnerHtml + "<br />" + (String)keys.Current;
i++;
}
I am outputting the text to a span control that I called 'test'. As mentioned above, this only outputs the keys name, and not it's value that I had set for it. I can't see to find any way to get it's value.
Any help would be greatly appreciated!!
Does anyone know if there is a way within Kentico CMS to nest a webpart within another webpart? I did a little research and I don't see many results on the topic so it seems the short answer is no, but maybe there is a workaround? On the project I am working on it is a requirement that the content author is able to place a hamburger menu on the page and then add other content within that hamburger menu via drag and drop. How can this be achieved within Kentico?
Thanks.
Typically a web part consists of user controls and not nested web parts. Take a look at the CMSRepeater for instance. It sets properties of a user control created by Kentico.
For what you're explaining it seems like you want a custom web part with widget zones in it. Those widget zones will allow you to drag and drop content in place (what content I have no idea really because you can't drag and drop content in Kentico, only areas/widgets).
For navigation, you might want to look at creating it based on the content tree but maybe a hamburger menu is not for navigation in your case.
The solution was to add a widget zone within the web-part.
Circling back to this post. Although adding a <cms:CMSEditableRegion /> tag to the page did indeed allow me to nest a Widget within a Webpart zone, it seemed a bit unnecessary for the user to have to switch between the design tab and page tab in order to achieve adding a nested component, not to mention having to register every webpart as a widget; quite unnecessary. I noticed Kentico's built in Layout webpart allowed for nested webparts so I looked at the code and was finally able to figure out how to implemented nesting a webpart within another webpart!
Ensure your webpart's code-behind inherits from CMSAbstractLayoutWebPart
Add the following method to your code-behind:
protected override void PrepareLayout()
{
StartLayout();
Append("<div");
Append(" style=\"width: ", "100%", "\"");
if (IsDesign)
{
Append(" id=\"", ShortClientID, "_env\">");
Append("<table class=\"LayoutTable\" cellspacing=\"0\" style=\"width: 100%;\">");
if (ViewModeIsDesign())
{
Append("<tr><td class=\"LayoutHeader\" colspan=\"2\">");
// Add header container
AddHeaderContainer();
Append("</td></tr>");
}
Append("<tr><td id=\"", ShortClientID, "_info\" style=\"width: 100%;\">");
}
else
{
Append(">");
}
// Add the tabs
var acc = new CMSAccordion();
acc.ID = ID + "acc";
AddControl(acc);
if (IsDesign)
{
Append("</td>");
if (AllowDesignMode)
{
// Width resizer
Append("<td class=\"HorizontalResizer\" onmousedown=\"" + GetHorizontalResizerScript("env", "Width", false, "info") + " return false;\"> </td>");
}
Append("</tr>");
}
// Pane headers
string[] headers = TextHelper.EnsureLineEndings("HEADER", "\n").Split('\n');
// Create new pane
var pane = new CMSAccordionPane();
pane.ID = ID + "pane";
pane.Header = new TextTransformationTemplate(string.Empty);
acc.Panes.Add(pane);
pane.WebPartZone = AddZone(ID + "-ContentArea", ID + "-ContentArea", pane.ContentContainer);
acc.SelectedIndex = 1;
if (IsDesign)
{
if (AllowDesignMode)
{
Append("<tr><td class=\"LayoutFooter cms-bootstrap\" colspan=\"2\"><div class=\"LayoutFooterContent\">");
// Pane actions
Append("<div class=\"LayoutLeftActions\">");
Append("</div></div></td></tr>");
}
Append("</table>");
}
Append("</div>");
FinishLayout();
}
I try to simply add a div wrapper around every control of type <asp:DropDownList> at a global level (if possible). At this point I have solved it with a asp skin adding "default-select" class to all <asp:DropDownList> and then jquery just adding a div for each of them.
$j(".default-select").wrap("<div class='myClass'></div>");
Now, my question. Is it possible to add this div wrapper from the code-behind instead of relying on a javascript.
Control Adapter:
I know this should be possible by writing a control adapter that override <asp:DropDownList> render method (as described here: Dropdownlist control with <optgroup>s for asp.net (webforms)?). However, I just want to add a wrapping div, not rewrite the entire rendering of the <asp:DropDownList> control (which I have to do if i override the method?). Any suggestions? Maybe there is a way to just add something to the existing adapter??
Custom User Control: Another solution would be to build a custom <mycustom:DropDownList> with the wrapping, but, this would force me to replace every instance of <asp:DropDownList> trough the whole project (large project). I rather just change the original control some how so that my styling applies everywhere.
So summary: Is there an easy way to just make all <asp:DropDownList> render as:
<div class="myClass">
<select><option...></select>
</div>
instead of just:
<select><option...></select>
My first attempt (on Page load): I tried to add this code in the Page_load method but I don't find any way to render that div out?
var j = 0;
foreach (DropDownList control in Page.Controls.OfType<DropDownList>())
{
HtmlGenericControl div = new HtmlGenericControl();
div.ID = "div" +j;
div.TagName = "div";
div.Attributes["class"] = "myClass";
div.Controls.Add(control); // or control.Controls.Add(div); but this wouldn't wrap it.
j++;
}
Your solution just about works. Server control can only exist within the scope of a server form, you will need to perform a recursive search on the page or look directly in the form controls collection. Once you have the DropDownList and wrapped it around a div container it will need to be added to the controls collection.
Also, I think it better to perform this in OnPreInit.
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
var j = 0;
foreach (DropDownList control in form1.Controls.OfType<DropDownList>().ToList())
{
var div = new HtmlGenericControl();
div.ID = "div" + j;
div.TagName = "div";
div.Attributes["class"] = "myClass";
div.Controls.Add(control); // or control.Controls.Add(div); but this wouldn't wrap it.
j++;
form1.Controls.Add(div);
}
}
I hope this is helpful. Let me know how you get on.
Either way what you're wanting is custom and you have to code for it. So IMO, the best and simplest option is the custom control. You may have to spend some time refactoring references to replace your <asp:DropDownList>, but in all the time you've spent trying another way, you could've been done by now. :)
I've learned the hard way that keeping it simple is usually the best way to go.
The issue I am having is I have a WebBrowser control called "Browser." The browser is populated from a different controls created by MEF:
//Apply Button that cretes the HTML that is loaded into the Browser
btnCreateHTMLPreview(object sender, RoutedEventArgs e)
{
//Clears the content of the observable collection
contents.Clear();
//usedControls is an observable collection of all loaded controls in the stack panel
foreach(var control in usedControls)
control.CreateHTML();
}
//Code in the MEF Control that creates the HTML that is will be loaded into the browser
CreateHTML()
{
string tempStuff = null;
tempStuff += "<h1>" + MyControl.lblHeader.Content + "</h1>\n";
tempStuff += MyControl.txtTextGoesHere.Text + "\n";
//Give the HTML back to the Application
parent.AcceptReport(tempStuff);
}
//Application side where it accepts the HTML and loads it into the Browser
AcceptHTML(string passedInContent)
{
//Observable collection that holds the content of all possible MEF Controls
contents.Add(passedInContent);
string tempStuffForBrowser = null;
tempStuffForBrowser = "<html>\n";
tempStuffForBrowser += "<body>\n";
//Add the content that was saved earlier
foreach (var strInd in contents)
tempStuffForBrowser += strInd;
tempStuffForBrowser = "<html>\n";
tempStuffForBrowser += "<body>\n";
Browser.NavigateToString(tempStuffForBrowser);
}
I did my best above to try and provide the meat of how I am populating the html and add that back into the browser. If there is anything that is unclear please just let me know.
If I have just one control added so that "content" only has the one control in it when I click the button to load the html, it works just fine and loads it in. However if I have more than one control loaded, I have to click that button twice to get it to show. I found this extremely bizarre. My attempt to solve this was to check and see if there was content in the Browser before leaving the event, but I am unsure how to do this. If anyone has any suggestions or any other ideas on how to solve this problem please let me know.
It looks like the WebBrowser control has some kind of issue where it doesn't load the first string it gets; I'm assuming there's some initialization that hasn't happened yet. I got it to work by calling
myBrowser.NavigateToString("");
from within the constructor of my class, and then using it from then on worked correctly. Hokey but it works.
Good Afternoon.
I have a list of panel that are dynamically created on Page_Load. Controls Are added via the Control.Add(p); method. code Follows
Panel p = new Panel();
p.ID = "cell_" + i + "_" + j;
p.Attributes.Add("runat", "server");
p.TabIndex = -1;
p.Attributes.Add("class", "box");
p.Attributes.Add("onClick", "clicked(this);");
p.Attributes.Add("onKeypress", "changeValue(event, this);");
p.Style.Add(HtmlTextWriterStyle.Top, top + "%");
p.Style.Add(HtmlTextWriterStyle.Left, left + "%");
p.Attributes.Add("Text", value);
PanelList.Add(p);
this block of code is in a for loop and the i, j, left, right, and value variables are altered every loop.
Now, When i call this function BEFORE Page_Load Finishes:
foreach (Control c in clientGrid.Controls)
{
Response.Write(c.ClientID.ToString());
}
It sucessfully writes all the client ID's of all the dynamically created panels.
However, When i run the foreach function on postback, the Response.write displays nothing. Its as if asp has forgotten these panels exist!
Now i hear that on Page_Init(), the controls need to be re-rendered!
Im not sure How to do this and after many googles, cant seem to find an answer.
Ive tried using recurtion to iterate through all Page.Controls and pull out the
System.Web.UI.WebControls.Panel
But still no luck :(
If my question in unclear, I cant provide more code and details :)
Thankyou
Alex
The dynamically added controls must be re-added to the page upon each postback. I don't know if this will meet your logical requirements but make sure you add your controls in the page_load method outside of your (!isPostback) condition. Then make sure your logic for writing out the client ids is called after the controls are added to the page.
If you need to store state information about these controls between postback, you will probably have to use some javascript and hiddenfields.
All of your event handlers should be called after Page_Load so if you add the controls in the Page_Load, you should be fine. OnPreRender is sometimes useful for this kind of thing. It gets called after Page_Load but before the post back finishes.