I am creating Tridion GUI Extension, in this i have created a button ("InsertCP") in the Ribbon toolbar.
The scenario is:
1.User selects any text from the Rich Text Box of the component
2.User clicks the "InsertCP" button from the ribbon toolbar.
3.when the user clicks the button , i am opening my custom aspx page.
4.From the custom aspx page, user can select "Component" and "Component Template".
5.I am storing the selected component and component template tcm id in a variable.
6.I have submit button in the custom aspx page.
7.when the user clicks the submit button, i need to format the selected text as below in the Rich Text box source.
Ex:
Selected Text
I have done upto the step 6, i am tryng the step 7, when i click the submit button am not able to submit the selected ID.
My ASPX page:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://www.sdltridion.com/web/ui/controls">
<head runat="server">
<title></title>
<cc:tridionmanager runat="server" editor="ExampleEditor" isstandaloneview="true">
<dependencies runat="server">
<dependency runat="server">Tridion.Web.UI.Editors.CME</dependency>
<dependency runat="server">Tridion.Web.UI.Editors.CME.Controls</dependency>
</dependencies>
</cc:tridionmanager>
</head>
<div>
<asp:TextBox ID="txttags" runat="server" Width="800px" ></asp:TextBox>
<asp:Button ID="btnsubmit" runat="server" Text="Submit" onclick="btnsubmit_Click" />
<c:button id="InsertButton" runat="server" class="customButton greybutton" label="Insert" />
</div>
Cs code :
protected void btnsubmit_Click(object sender, EventArgs e)
{
txttags.Text = "anyvalue.";
}
and java script are same as exiting one..
But i am getting error on runtime.Do i need to add any namespace in cs page.
My CS page will have so many events like below.Cant i use tridion control button for this page.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tridion.ContentManager.CoreService.Client;
using System.Xml.Linq;
using System.Xml;
namespace Somename
{
public partial class Classname
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ddSelectOption_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void lbPublication_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void lbPubFolders_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void lbComponent_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void lbComponentTemplate_SelectedIndexChanged(object sender, EventArgs e)
{
}
I'll provide a second answer to your updated question, although you are still keeping us a bit in the dark since you only mention you get a runtime error and not what that exactly is (it is impossible for me to provide a good answer if I don't know what error you get).
Your ASPX page should look something like this:
<%# Page Language="C#" AutoEventWireup="true" Inherits="Example.MyPopup" ClassName="MyPopup" %>
<%# Import Namespace="Tridion.Web.UI" %>
<%# Register TagPrefix="ui" Namespace="Tridion.Web.UI.Editors.CME.Controls" Assembly="Tridion.Web.UI.Editors.CME" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html id="MyPopup" class="tridion popup" xmlns:c="http://www.sdltridion.com/web/ui/controls" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My Popup Example</title>
<cc:TridionManager runat="server" Editor="ExampleEditor" IsStandAloneView="false">
<dependencies runat="server">
<dependency runat="server">Tridion.Web.UI.Editors.CME</dependency>
<dependency runat="server">Tridion.Web.UI.Editors.CME.Controls</dependency>
</dependencies>
</cc:TridionManager>
</head>
<body>
<table id="tblHeight" border="0" cellpadding="0" cellspacing="0">
<tr>
<td id="InputField" valign="top">
<table>
<tr>
<td id="NameLabelCell" nowrap="nowrap">My Label</td>
<td><input id="txttags" name="txttags" value="" tabindex="1" /></td>
</tr>
</table>
</td>
</tr>
<tr id="FooterRow">
<td class="footer" align="right">
<div class="BtnWrapper">
<c:Button ID="BtnOk" runat="server" TabIndex="2" Label="<%$ Resources: Tridion.Web.UI.Strings, OK %>" />
<c:Button ID="BtnCancel" runat="server" TabIndex="3" Label="<%$ Resources: Tridion.Web.UI.Strings, Cancel %>" />
</div>
</td>
</tr>
</table>
</body>
</html>
Note: the table markup is copied directly from the Anchor popup, feel free to use divs instead and style them any way you want, the example is meant to show you how to reuse the existing Tridion controls
Your CS would then become:
using Tridion.Web.UI.Core;
using Tridion.Web.UI.Controls;
using Tridion.Web.UI.Core.Controls;
using Tridion.Web.UI.Editors.CME.Views.Popups;
namespace Example
{
[ControlResources("Example.MyPopup")]
public class MyPopup : PopupView
{
}
}
It doesn't contain anything, and it doesn't need to, as all the actions you will be doing in your JavaScript as explained before.
Looking at your update I gather what you want is to create an anchor element based on the information from your ASPX page into the selected text of the Rich Text field of the Component.
To build something like that you can best look at something similar which is available. Simplest example I can think of is the Hyperlink button in the Format ribbon toolbar. That consists of two items:
..\Tridion\WebUI\Editors\CME\Views\Popups\Link\Link.aspx
..\Tridion\WebUI\Editors\CME\Views\Popups\Link\Link.js
The magic all happens inside the JavaScript file (as usually is done in these UI extensions). In the initialize() method, the selected part is extracted like so:
var p = this.properties;
var c = p.controls;
// Get selected acronym
p.OldLink = (window.dialogArguments && window.dialogArguments.link) ? window.dialogArguments.link : {};
The post back to the Rich text field is done in the _onOkButtonClicked(event) method like so:
this._buildNewLinkHtml();
this.fireEvent("submit", { link: this.properties.NewLink });
window.close();
You can take a closer look at the rest of the code in the Link.js file and rebuild it to suit your needs.
By the way, looking at the info you want to post back in the href, I would say its easier if you format it a bit more according to some sort of standard, you could for instance place your URIs there like JSON:
text
Or possibly even abuse the title attribute for your Component Template URI:
text
Since I'm assuming your Component Template code will use these values to do something special with this hyperlink construct.
Edit
The unrecognized tag prefix c error you show in the added image, you can solve by adding the correct namespace reference as I indicated in my answer here. So just add it in your HTML element:
<html xmlns:c="http://www.sdltridion.com/web/ui/controls" xmlns="http://www.w3.org/1999/xhtml">
As for the unrecognized cc tag prefix, you shouldn't need to bother with that one, it seems to be resolved at runtime just fine since you are running this inside the Tridion context.
Related
In my ASP .NET Web Forms I have the following declarative code:
<asp:TextBox runat="server" ID="txtbox" CssClass='<%=TEXTBOX_CSS_CLASS%>' />
The constant TEXTBOX_CSS_CLASS is defined in a base class that the page's code-behind class inherits from:
public class MyPageBase : Page
{
protected internal const string TEXTBOX_CSS_CLASS = "myClass";
}
The edit-time compiler however warns me that "This is not scriptlet [sic]. Will output as plain text".
True to its word, the css class is rendered as literally "<%=TEXTBOX_CSS_CLASS%>".
What does this error message mean and is there a workaround so I can still use a constant in a base class?
You cannot use <%= ... %> to set properties of server-side controls.
Inline expressions <% %> can only be used at
aspx page or user control's top document level, but can not be embeded in
server control's tag attribute (such as <asp:Button... Text =<% %> ..>).
If your TextBox is inside a DataBound controls such as GridView, ListView .. you can use: <%# %> syntax. OR you can call explicitly DataBind() on the control from code-behind or inline server script.
<asp:TextBox runat="server" ID="txtbox" class='<%# TEXTBOX_CSS_CLASS %>' />
// code Behind file
protected void Page_Load(object sender, EventArgs e)
{
txtbox.DataBind();
}
ASP.NET includes few built-in expression builders that allows you to extract custom application settings and connection string information from the web.config file. Example:
Resources
ConnectionStrings
AppSettings
So, if you want to retrieve an application setting named className from the <appSettings> portion of the web.config file, you can use the following expression:
<asp:TextBox runat="server" Text="<%$ AppSettings:className %>" />
However, above snippet isn't a standard for reading classnames from Appsettings.
You can build and use either your own Custom ExpressionBuilders or Use code behind as:
txtbox.CssClass = TEXTBOX_CSS_CLASS;
Check this link on building Custom Expression builders.
Once you build your custom Expression you can display value like:
<asp:TextBox Text="<%$ SetValue:SomeParamName %>"
ID="setting"
runat="server" />
The problem is that you can't mix runat=server controls with <%= .. %>code blocks. The correct way would be to use code behind: txtbox.CssClass = TEXTBOX_CSS_CLASS;.
This will work.
Mark up
<asp:TextBox runat="server" ID="txtbox" class='<%# TEXTBOX_CSS_CLASS %>' />
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
txtbox.DataBind();
}
}
But its a lot cleaner to access the CssClass property of the asp:TextBox on Page_Load
Ok, I've already learned that in order to keep the dynamic (created) controls and their viewstate in asp.net we must (re)create them in the Page init event, so they already exist within the page's control hierarchy before the view state is loaded.
As it says in this article.
There is no problem to achieve this behaviour if the criteria to create these controls is outside the web environment, for example a database. But what should I do if what I use to decide how many dynamic controls I have to create is actually a value that is in the controls?
I try to explain it with an example, maybe it's clearer:
Let's say that we have a textbox and two buttons. In the textbox I write the number of how many dynamic controls I want to create, for example 4 checkbox. When I hit the button1 the controls should be created. No problem. Then I check some checkboxes and hit the button2 just to fire a postback. Now I should recreate the controls in the page init event, like we said before, in order to maintain the controls and their state.
And here comes the problem. Because of I'm in the init stage I have no viewstate so I'm no able to access the value in the textbox that tells me how many dynamic checkbox should I create.
I thought that storing the value in the session object would do the trick, but it doesn't. The session object is no accessible as well.
Where can I save the value that it'll be accessible from the init event too?
Thanks and sorry for the long post!
First thing - textbox value is not stored/retrieved from view state, you cannot get textbox value from viewstate.
Coming to actual problem, here is the sequence of (imp) events init -> load view state -> bind postback data -> page load. You can retrieve textbox value only after bind postback data event (which actually takes posted data and binds to the textbox control).
In init only option is to use Request.Form{"textboxid"] to get the textbox value.
You are on the right track.
If you use TextBox, you do not need another ViewState to keep track of how many controls has been created, because TextBox control has its own ViewState already.
You can use either Page_Init or Page_Load to load control back.
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs"
Inherits="WebApplication2010.WebForm1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox runat="server" ID="NumberTextBox" />
<asp:Button runat="server" ID="CreateControlButton"
OnClick="CreateControlButton_Click"
Text="Create Control" />
<br />
<asp:PlaceHolder runat="server" ID="PlaceHolder1"></asp:PlaceHolder>
</div>
</form>
</body>
</html>
using System;
using System.Web.UI;
namespace WebApplication2010
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
int ids;
if (Int32.TryParse(NumberTextBox.Text, out ids))
{
for (int i = 0; i < ids; i++)
{
Control ctrl = Page.LoadControl("WebUserControl.ascx");
ctrl.ID = i.ToString();
PlaceHolder1.Controls.Add(ctrl);
}
}
}
}
protected void CreateControlButton_Click(object sender, EventArgs e)
{
}
}
}
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="WebUserControl.ascx.cs"
Inherits="WebApplication2010.WebUserControl" %>
<asp:CheckBox runat="server" ID="CheckBox1" />
<asp:Button runat="server" ID="Button1" OnClick="Button_Click"
Text="Post Back" />
<asp:Label runat="server" ID="Label1" />
<br />
using System;
namespace WebApplication2010
{
public partial class WebUserControl : System.Web.UI.UserControl
{
protected void Button_Click(object sender, EventArgs e)
{
Label1.Text = " This control was posted back.";
}
}
}
This is the common paradox with page lifecycle when you work with code behind. For example, you save the editing customerid in viewstate but controls need to bind on init to be able to read their posted values.
Best real life solution is to do what bound controls do on postback, call explicilately the LoadPostBackData on IPostBackDataHandler interface that all controls implement, after you have created them in Page Load event.
You should create an extension method for Controls and call it when needed:
control.DataBind();
control.LoadPostedData(); // extension method
I need to create a radiobuttonlist containing a "other" option, and i have to put a textbox next to it. Here is what i did.
if(!ispostpage){
PlaceofWork.DataSource = workplace;
PlaceofWork.DataBind();
PlaceofWork.DataTextField = "WorkPlace1";
PlaceofWork.DataValueField = "WorkID";
PlaceofWork.Items.Add(new ListItem("Other - Specify<input name=\"OtherWorkPlace\" type=\"text\" value=\"test\" id=\"OtherWorkPlace\"/>", "-1"));
This radiobuttonlist is in a usercontrol.
at the first I didn't add if(!ispostpage) so when i try Request.Form["OtherWorkPlace"], it didn't return anything
after i add the code if(!ispostpage), it pop up the error "Object reference not set to an instance of an object"
So how can I get the value of the input textbox?
Not sure if this would help you out, but wouldn't it help if you place a asp:TextBox control in the page and retrieve the value from it only if 'Other' radio button is checked? This text box can be made visible in the client side once the 'Other' radio button is checked. The text box can be placed next to the radio button using CSS.
You could use a hidden field control on the asp .net side.
<asp:HiddenField runat="server" ID="rbOtherText" />
The set the value of the control using a javascript onblur event.
PlaceofWork.Items.Add(new ListItem("Other - Specify<input name=\"OtherWorkPlace\" type=\"text\" value=\"test\" onblur=\"document.getElementById('" & rbOtherText.ClientID & "').value = this.value;\" />", "-1"));
Then in the code behind just reference the HiddenField.
The runat="server" is not buying you anything, it's probably just being rendered directly into the output. If you can see it when you View Source on the page, then it's not being processed as a server side control. I would get rid of that.
Add an ID attribute with the same value as the name attribute:
PlaceofWork.Items.Add(new ListItem("Other - Specify<input id=\"OtherWorkPlace\" name=\"OtherWorkPlace\" type=\"text\" value=\"test\"/>", "-1"));
Remember that IDs must be unique, so you can only have one of these per page without changing the naming convention. Then you are able to see it in the Form collection, as you previously tried.
ASPX
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
<%# Register src="WebUserControl1.ascx" tagname="WebUserControl1" tagprefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<uc1:WebUserControl1 ID="WebUserControl11" runat="server" />
<br />
<asp:Button ID="Button1" runat="server" Text="Submit" />
</div>
</form>
</body>
</html>
ASPX Code behind
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
string result = Request.Form["OtherWorkPlace"].ToString();
}
}
ASCX
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs" Inherits="WebApplication1.WebUserControl1" %>
<asp:RadioButtonList ID="RadioButtonList1" runat="server">
</asp:RadioButtonList>
ASCX Code behind
protected void Page_Load(object sender, EventArgs e)
{
var list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
if (!IsPostBack)
{
RadioButtonList1.DataSource = list;
RadioButtonList1.DataBind();
//RadioButtonList1.DataTextField = "Value";
//RadioButtonList1.DataValueField = "Key";
RadioButtonList1.Items.Add(new ListItem("Other - Specify<input id=\"OtherWorkPlace\" name=\"OtherWorkPlace\" type=\"text\" value=\"test\" />", "-1"));
}
}
If your RadioButtonList is in a UserControl, it sounds like you want to re-use this in multiple places, possibly even on the same page. If so, you are definitely going to have to come up with a way to manage the IDs so they don't conflict.
<form id="form1" action="Detail.aspx" runat="server">
<input type="submit" id="save" name="Submit" value="Save and Add"/>
<asp:Button ID="Exit" runat="server" Text="Exit" onclick="Exit_Click" />
</form>
CodeBehind
protected void Exit_Click(object sender, EventArgs e)
{
Response.Redirect("Show.aspx");
}
When I click the Exit Button the response is not going to Show.aspx.It goes to Details.aspx.I am unable to understand why the control is not passing to Show.aspx;
I have added a new page to my site that matches what you are describing, and it seems to work exactly as you wish it to:
In the code behind:
using System;
namespace MyProduct.Web.Pages
{
public partial class Details : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
Response.Write("If this text is visible then it works...");
}
}
protected void Exit_Click(object sender, EventArgs e)
{
Response.Redirect("Show.aspx");
}
}
}
In the markup:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Details.aspx.cs" Inherits="MyProduct.Web.Pages.Details" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" action="Details.aspx" runat="server">
<input type="submit" id="save" name="Submit" value="Save and Add"/>
<asp:Button ID="Exit" runat="server" Text="Exit" onclick="Exit_Click" />
</form>
</body>
</html>
If i click "Save and Add" button then i remain on the same page (Details.aspx) and i see the text "If this text is visible then it works..."
If i click the "Exit" button then i am taken to a page called Show.aspx
Be sure that you have AutoEventWireup="true" in the top of your aspx page. This might be why you are not hitting the Exit_Click handler.
I hope this helps
clicking on a button in a form submits the form, take look at http://www.w3schools.com/aspnet/aspnet_forms.asp
Please use this method: Response.redirect(Server.MapPath("Show.aspx"));
The Show.aspx may into a folder in your website so you should write the explicit path of the page like "/Home/Customer/Show.aspx" but in Asp.Net you can use the Server.Mappath method to let the server serch the location of the file for you, that is to say, this method return the explicit path of the page.
I've created a class library which exposes my back-end object model. I don't wish to databind straight to SQL or XML, as a surprising number of tutorials/demos out there seem to assume.
In my Page_Load(), within the if (!IsPostbak), I currently set all the values of my controls from the object model, and call Databind() on each control.
I have a button event handler which deletes an item from the object model (it's a List in this case) and rebinds it to the Repeater. First of all, this is messy - rebinding each time - but more importantly, no values are displayed when the page reloads. Should I put the databinding code outside the if statement in Page_Load()?
The second part of the question is regarding going back to basics - what's the best way to databind in Asp.net? I'm mainly interested in binding against lists and arrays. I would have imagined there being a way to tell a control (e.g. TextBox) to databind to a string variable, and for the string to always reflect the contents of the text box, and the text box to always reflect the contents of the string. I tried the <%#...%> syntax but got no further than using the code-behind as described above.
I've read several overviews of databinding, but nothing out there seems to do what I want - they all talk about linking DataSets to a SQL database!
Turning to the knowledge of StackOverflow.
You'll need to databind on every page load so you need to remove the code from within your !IsPostBack block.
When using a list or array handle the databinding event on the control. For a repeater you'll need to handle the ItemDataBound event.
This example has been modified from http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.repeater.itemdatabound.aspx:
<%# Page Language="C#" AutoEventWireup="True" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html >
<head>
<title>OnItemDataBound Example</title>
<script language="C#" runat="server">
void Page_Load(Object Sender, EventArgs e) {
ArrayList values = new ArrayList();
values.Add(new Evaluation("Razor Wiper Blades", "Good"));
values.Add(new Evaluation("Shoe-So-Soft Softening Polish", "Poor"));
values.Add(new Evaluation("DynaSmile Dental Fixative", "Fair"));
Repeater1.DataSource = values;
Repeater1.DataBind();
}
void R1_ItemDataBound(Object Sender, RepeaterItemEventArgs e) {
// This event is raised for the header, the footer, separators, and items.
// Execute the following logic for Items and Alternating Items.
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
if (((Evaluation)e.Item.DataItem).Rating == "Good") {
((Label)e.Item.FindControl("RatingLabel")).Text= "<b>***Good***</b>";
}
}
}
public class Evaluation {
private string productid;
private string rating;
public Evaluation(string productid, string rating) {
this.productid = productid;
this.rating = rating;
}
public string ProductID {
get {
return productid;
}
}
public string Rating {
get {
return rating;
}
}
}
</script>
</head>
<body>
<h3>OnItemDataBound Example</h3>
<form id="form1" runat="server">
<br />
<asp:Repeater id="Repeater1" OnItemDataBound="R1_ItemDataBound" runat="server">
<HeaderTemplate>
<table border="1">
<tr>
<td><b>Product</b></td>
<td><b>Consumer Rating</b></td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td> <asp:Label Text='<%# DataBinder.Eval(Container.DataItem, "ProductID") %>' Runat="server"/> </td>
<td> <asp:Label id="RatingLabel" Text='<%# DataBinder.Eval(Container.DataItem, "Rating") %>' Runat="server"/> </td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
<br />
</form>
</body>
</html>
EDIT:
In addition, (and you may already be aware of this) you'll need to persist your list/array somehow. You can go all the way back to the database and reconstitute the list there or you can store it in memory with cache, viewstate, or session as viable options depending on your needs.
Spring.NET Web will provide you with two-way databinding with nice, easy to maintain code. Give it a try!