I have 5 or so different pieces of HTML in my page that contain the same scaffolding HTML surrounding it, something like this:
//PanelBase.ascx
<div class="panel" id="[PANEL-SPECIFIC-ID]">
<h3>[PANEL-SPECIFIC-HEADER]</h3>
...
[PANEL-SPECIFIC-HTML]
...
</h3>
</div>
Where all the PANEL-SPECIFIC things are different for each panel type. Is there a way I can create a common base control to handle this scaffolding and inherit from it to supply the PANEL-SPECIFIC-HTML? The PANEL-SPECIFIC-ID and PANEL-SPECIFIC-HEADER I can just pass to the panel directly, but since the panel specific HTML is so large I don't want to pass it directly as a string.
Or is there some way to do it like this in each child control's ascx file:
<my:PanelBase PanelId="myChildPanel" Header="My Child's Header">
// HTML for my child panel.
</my:PanelBase>
Basically, I'm looking for some way to reuse the common portions of my control so I don't have to duplicate it for each child.
I guess the "most proper" way of doing this would be to have the main content of your container as a template, however that requires you to type <ContentTemplate></ContentTemplate> inside all your panels, which is less than ideal.
If I had to do this, I'd probably override AddParsedSubObject, collect any child controls into a collection and add them to a PlaceHolder or something similar in CreateChildControls. This can be done either with a custom control or a user control (.ascx).
For the headings and whatnot, just use Literals and create properties that wrap the Literal.Text properties.
Yes, and its generally good practice to do so. What would be ideal would be to put labels or literals in the places where you have content that would be modifiable. Then in the code behind you would put properties relating to each of them:
'These attributes allow you to specify individual properties about your control
'particularly if you want to be able to bind data to it, list it in the properties
'in your IDE, etc.
<BrowsableAttribute(True), Bindable(False), Category("Misc"), DefaultValue("true"), _
Description("Gets or sets the content title.")> _
Public Property DisplayContentTitle() As String
Get
Return _displayContentTitle
End Get
Set(ByVal value As Boolean)
_displayContentTitle = value
Me.litContentTitle.Text = value ' Optional
End Set
End Property
Then when you include the control in your page you would configure it in the following manner:
<asp:MyHtmlControl ID="blah" runat="server" DisplayContentTitle="Some text" />
This gives you the ability to modify, validate, manipulate or whatever in the code behind of the user control. It also allows the control itself to modified during runtime. You can also override loading and rendering events of your common control to perform specific actions based on any of these settings you create.
You might want to look into Nested Master Pages.
Related
I have multiple RichTextBoxes and I would like to store a boolean on them so I can access it for each of them. Is there any way?
I tried using the Extensions Methods, like I do to have more overloads for AppendText, but I had no luck there.
You can add whatever property you want. If you need to be able to change it at design time (from property editor) you just have to decorate with with the Browsable attribute.
Other attributes that might help:
CategoryAttribute - this attribute indicates in wich category of your property grid will reside your property.
DescriptionAttribute - this attribute adds a description for your property that will apear as a text description in the bottom of the property grid.
BUT if you cannot modify existing control, you must use inheritance (inherit in your case from RichTextBox). If the class is sealed then I would create another control that decorates current one (the decorator pattern) and add a new property on it.
You can use the Tag Property. Its defined on Control so is available for all controls including your RichTextBox MSDN
Quick simple solution (maybe not as elegant), but for the sake of simplicity, you can just create hidden fields using #Html.HiddenFor(x=>x.MyField1Bool). That is if you are posting back to the server. You'd need to create the extra boolean fields to your ViewModel of course.
Also, just in case you are planning to use javascript to access these booleans. You should have a look at data attributes, for example:
<input type="text" data-flag="true"/>
These are easy to access in javascript. And in Razor syntax you just add them as attributes.
I've been trying to iterate over a placeholder in sitecore. Essentially, there control that needs to be repeated by the page for a collection of elements (say a tab). I've only gotten the placeholder to render once. The following tabs don't have content inserted into them.
The code for something like what I'm trying to do is:
<asp:Repeater ID="rptTabs" runat="server">
<sc:Placeholder ID="plSocialSharing" runat="server" Key="Social"/>
<sc:Placeholder ID="plTab" runat="server" Key="content"/>
</asp:Repeater>
Should something like what I'm doing work? If it doesn't, do I need to user another sitecore control (something more dynamic?). Should I instead be using user controls I place there, or should I stick with the sitecore framework approach?
Since each of your tabs will contain the same rendering the I would not bother with placeholders. I think you will be adding more complexity than is required.
Assuming you are going to be using the jQuery UI Tab plugin then I would use the same technique you used in the previous question you asked, i.e. render out the content of the div tabs in the repeater, and you will need another repeater to create the ul list of the actual tabs.
Assuming you have a tree structure like:
- Social Sharing
-- Facebook
-- Twitter
-- Email
You could now Social Sharing use as the datasource of your Repeater and still allow the content of the tabs to be editable if you use Sitecore controls.
If you wanted something much more dynamic, like different rendering for each of the tabs, for example one with rich text, one with 2 column, one with table etc, then again there are a couple of ways of achieving this. One way would be to use standard <asp:PlaceHolder> in your repeater and add the rendering in this from your codebehind on ItemDataBound event.
Another option would be to add a bunch of different renderings into the placeholder in the page editor and set the datasource of each to content item. It will be difficult to use jQueryUI Tabs with this though since you would want markup like this in each control to make them self contained:
<div class="tab-title">Tab Title</div>
<div class="tab-content">Put whatever content you want in here</div>
As long as each rendering followed this structure then it would be easy to add several of these to the page and they would still be editable in the Page Editor, albeit listed one after another (not in tab format) in Editing mode. You would need to roll your own tab plugin, but it could be something as simple as:
Only in Preview or Normal mode
Get all .tab-title elements
Create a ul list and prepend to the tab container
Now call jQuery UI Tabs on the element
Hopefully given you some options at least, I can expand on any of these if it something you need but will have to get some code samples together.
Basically I want a boolean property in a ascx control which could be read without loading the full control (I'd like to avoid LoadControl triggering the events).
I have database rows which store what different sets of controls should be seen by different users by the virtual path to the controls. I need to add the ability to print these controls, but only certain controls will have the ability to print.
I was thinking of having an interface for those controls that support it, then as i build the print page i check the type of each control to see if it has that interface or not.
Along those lines I'm wondering if there is any way to get the control type from the url of a file. I know Page.LoadControl(url).GetType() would work but i would like to avoid the overhead of building the control if possible.
Reason:
Since the ability to print might be added to other controls during development having the code of the ascx file store that property in some way would be ideal. Rather than needing to update properties in each database list.
You can get the Type of the UserControl by using the BuildManager class in the System.Web.Compilation namespace.
Type ctrlType = BuildManager.GetCompiledType("~/PrintableControl.ascx");
bool isPrintable = typeof(IPrintable).IsAssignableFrom(ctrlType);
I am almost too embarrassed to ask this question, but here we go...
I am not an expert with user controls, and need some design advise regarding trying to achieve a specific desired functionality.
The goal is to have a usercontrol that would render as a complex structure of html elements and css to form an elegant container box. The problem lies in how to populate the contents of the box as each instance of the usercontrol would have its own individual HTML content. The content container div of the usercontrol would be nested deep within the structure of the rendered html. It is undesirable to programmatically set the contents of the usercontrol, or use properties.
In psuedo-code, the desired syntax would be something like:
<usercontrol Title="Some Title"><p>some random html content</p></usercontrol>
A sample of the rendered usercontrol would be:
<div class="CommonBox">
<div class="Title">Some Title</div>
<div class="Content"><p>some random html content</p></div>
</div>
I hope my explanation is adequate. Does this make sense to anyone or is the desired functionality unachievable?
Cheers!
EDIT
I attempted the templated user control suggestion in the hopes of coming to a decent solution. I "waybacked" this site and now have a working templated user control. My next question is, how can I programmatically access the controls nested within the template... say there is a textbox control in the "Description" template from the example link and I want to set its value programmatically? Is this possible?
What you're looking for is definitely possible. One solution is to create a templated user control. In the end you can define the contents similar to how your example looks. Something like:
<uc:MyControl Title="Some TItle" runat="server">
<ContentsTemplate>
<p>some random html content</p>
</ContentsTemplate>
</uc:MyControl>
Here's a simple how-to. I've done this in the past with success. There are lots of resources found through Google as well on the topic.
Yes this is very possible. First you can create a custom control as I describe in this post. Properties in the control become attributes like "Title" you have in your example. Then you can extend your control with the technique shown in this post to add child nodes for the other html inputs you will require.
Enjoy!
It looks like you need two properties for your custom server control.
Title property to render first inner div's content,
Content for the second one. If you want to set contents inside your server control, you should use [PersistenceMode(PersistenceMode.InnerDefaultProperty)] attribute for your property, like this :
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public string Contents
{
get
{
string contents = (string)ViewState["Contents"];
return (contents == null) ? String.Empty : contents;
}
set
{
ViewState["Contents"] = value;
}
}
PersistenceModeAttribute is explained in MSDN like that :
PersistenceModeAttribute Passing the
InnerDefaultProperty parameter
specifies that a visual designer
should persist the property to which
the attribute is applied as an inner
default property. This means that a
visual designer persists the property
within the control's tags. The
attribute can be applied to only one
property, because only one property
can be persisted within the control's
tags. The property value is not
wrapped in a special tag.
For more information take a look at the last example here.
I am writing what i will call a survey system. The surveys will consist of a series of questions, split into sections. The survey definitions will be stored in a database. The questions can be of various types, that have different input methods and validation (e.g.textbox, numeric textbox, selectlist etc.) I am creating a set of user controls that map to different question types. I would like to completely abstract the survey rendering logic from the, survey definition logic. The way i thought i would do this is to use a dumb rendering control that simply takes a collection of controls and renders them out in a for each loop a super simplified version of what I am doing.
private void RenderControls()
{
foreach (UserControl CurrentControl in this.ControlsToRender)
{
MyPlaceholder.Controls.Add(CurrentControl)
}
}
This works in the sense that the correct controls get added to the place holder,however nothing renders. Presumably this is because it does not have the markup in the asxc file.
If i do something like this
private void RenderControls()
{
foreach (UserControl CurrentControl in this.ControlsToRender)
{
MyPlaceholder.Controls.Add(this.LoadControl("path to ascx file")
}
}
It will create the correct number of controls, but i don't want to instantiate the controls here because i would need to to set various properties based on cconditional logic i want to abstract away from this pure rendering layer.
what i want to do is instantiate the controls else where, set the relevant properties and then simply pass a collection of these into the rendering control to render out.
Is there a way to do this with user controls? Would i have to create custom controls instead?
.ascx usercontrols are difficult to make into distributable, portable components. There are ways of doing it, but they have a lot of restrictions and requires several steps. In the end it's not worth it.
Your best bet would be to make custom controls that encapsulate their own rendering.
You could do either, but it sounds to me like you might want to use custom controls.
You could use user controls by exposing properties on the user control.
MyPlaceholder.Controls.Add(CurrentControl)
by the time you get to the above line, the control has already been instantiated. just set those properties on instantiation and you should be set.
alternatively you could set the properties anytime before render