I have an asp.net application which uses the web part framework to allow users to customise their interface. One of the features of this is a catalog of available web parts, one is provided by default, but it can be overriden if you wish to change the layout, etc.
override void RenderCatalogPart(HtmlTextWriter writer, CatalogPart catalogPart)
That, as far as I can tell, is the only way to do it. At the moment I'm creating a panel with all the necessary elements in it, and using the panel's RenderControl method to output it to the htmlwriter. So far, so good. The problem occurs when I try to add a radtooltip to my panel, using the same RenderControl method, and I get the following runtime error:
Page cannot be null. Please ensure that this operation is being performed in the context of an ASP.NET request.
I can see why this might be a problem, since the tooltip presumably uses javascript and has to write it to the page - but the RenderCatalogPart method has no knowledge of which page it's going to be outputting to. Is there any way around this or am I going to have to come up with an alternative?
Thanks,
Mathew
5 Answers, 1 is accepted
I built up a test demo based on your explanations and I was able to reproduce the problem. The problem comes from the fact that you register the RadToolTip too late and as being a script control this should be done in PreRender in spite of render.
This being said, to achieve what you need, please follow the following steps:
1) Make sure you have added a ScriptManager on the page
2) Override PerformPreRender() method of your custom CatalogPartChrome
3) In the overridden in 2) method, add the tooltip to the Zone's Controls collection as follows:
public
override
void
PerformPreRender()
{
tip =
new
RadToolTip();
tip.Text =
"Test"
;
tip.RelativeTo = ToolTipRelativeDisplay.BrowserWindow;
tip.Position = ToolTipPosition.Center;
tip.Width = 200;
tip.Height = 200;
tip.ManualClose =
true
;
tip.VisibleOnPageLoad =
true
;
this
.Zone.Controls.Add(tip);
}
where tip is a global variable which will hold the reference to the tooltip.
4) Render the already registered tooltip in RenderCatalogPart method as you have already done:
public
override
void
RenderCatalogPart(HtmlTextWriter writer, CatalogPart catalogPart)
{
base
.RenderCatalogPart(writer, catalogPart);
tip.RenderControl(writer);
}
After I applied the above changes, everything started working correctly - for your convenience and reference I attached my sample demo to the thread.
I hope that my reply and the prepared demo are detailed enough and helpful, let me know how it goes.
Greetings,
Svetlina Anatithe Telerik team
Thanks very much for your detailed reply, I've tested it and it works great.
Now all I need to do is figure out how I'm going to add one for each catalog part :)
Regards,
Mathew
I am glad to hear I could help.
As to your new question, I suggest to use a collection, e.g you can use an ArrayList as follows:
public
class
MyCatalogPartChrome : CatalogPartChrome
{
ArrayList tips =
new
ArrayList();
public
MyCatalogPartChrome(CatalogZoneBase zone)
:
base
(zone)
{
}
public
override
void
PerformPreRender()
{
foreach
(CatalogPart p
in
Zone.CatalogParts)
{
RadToolTip tip =
new
RadToolTip();
tip.Text =
"Test"
;
tip.RelativeTo = ToolTipRelativeDisplay.BrowserWindow;
tip.Position = ToolTipPosition.Center;
tip.Width = 200;
tip.Height = 200;
tip.ManualClose =
true
;
tip.VisibleOnPageLoad =
true
;
tips.Add(tip);
p.Controls.Add(tip);
}
}
public
override
void
RenderCatalogPart(HtmlTextWriter writer, CatalogPart catalogPart)
{
base
.RenderCatalogPart(writer, catalogPart);
foreach
(var tip
in
tips)
{
(tip
as
Control).RenderControl(writer);
}
}
}
public
class
MyCatalogZone : CatalogZone
{
protected
override
CatalogPartChrome CreateCatalogPartChrome()
{
return
new
MyCatalogPartChrome(
this
);
}
}
I tested this and it worked fine on my side.
Please, note, that you can verify that there are 3 tooltips in this case by looking at the $create directives when you view the source of the loaded page. Only one tooltip will be visible, though, because by design you can have only one visible tooltip at a given time - that is why you will have 3 tooltips added on the page, but the last added one will force the previous to close.
At last, this suggestion is the easiest and first one that came to my mind and I suggest it as a start point - you could think of another structure or apply some additional performance optimizations to fine-tune the solution.
All the best,
Svetlina Anati
the Telerik team
I've done as you suggested and used the collection - I'm almost there, I can get the tooltips to render, but not to attach them to the specific controls.
public
override
void
PerformPreRender()
{
base
.PerformPreRender();
toolTips =
new
List<RadToolTip>();
panels =
new
List<Panel>();
foreach
(CatalogPart cp
in
Zone.CatalogParts)
{
foreach
(WebPartDescription partDescription
in
cp.GetAvailableWebPartDescriptions())
{
PortalWebPartBase webPart = cp.GetWebPart(partDescription)
as
PortalWebPartBase;
RadToolTip t =
new
RadToolTip()
{
HideEvent = ToolTipHideEvent.ManualClose,
ShowEvent = ToolTipShowEvent.OnMouseOver,
RelativeTo = ToolTipRelativeDisplay.Element
RegisterWithScriptManager =
true
};
Panel panel = CreatePanelForWebPart(partDescription, webPart);
panel.ID = String.Format(CultureInfo.InvariantCulture,
"DescriptionPanel{0}"
, partDescription.ID);
panels.Add(panel);
t.TargetControlID = panel.UniqueID;
t.IsClientID =
true
;
t.ID = String.Format(CultureInfo.InvariantCulture,
"DescriptionPanelTip{0}"
, partDescription.ID);
toolTips.Add(t);
this
.Zone.Controls.Add(t);
this
.Zone.Controls.Add(panel);
}
}
}
I'm then rendering both panels and tooltips in the RenderCatalogPart method, and the tooltips simply don't show up. If I set one to be visible when the page loads, I get a window is undefined error. I've also tried using javascript to call the tooltip's .show() method clientside when the mouse enters the panel, but I get a nullref when using <% find .... and when using document.getElementById().
Any suggestions?