Can anyone give me some pointers on how to display the results of an XPath query in a textbox using code (C#)? My datascource seems to (re)bind correctly once the XPath query has been applied, but I cannot find how to get at the resulting data.
Any help would be greatly appreciated.
XMLDataSource is designed to be used with data-bound controls. ASP.NET's TextBox is not a data-bound control. So to accomplish what you want you either have to find a textbox control with data binding or display the result in some other way.
For example, you could use a Repeater control and create your own rendering template for it.
<asp:Repeater id="Repeater1" runat="server" datasource="XMLds">
<ItemTemplate>
<input type="text" value="<%# XPath("<path to display field>")%>" />
</ItemTemplate>
</asp:Repeater>
Some more information would be nice to have to be able to give you a decent answer. Do you have any existing code snippets you could publish here?
The general idea is to use the XmlDataSource.XPath property as a filter on the XmlDataSource.Data property. Did you try displaying the contents of the Data prop in your textbox?
Based on a slection in a DropDownList, when the SelectedIndexChanged event fires, the XPath for an XMLDataSource object is updated:
protected void ddl_SelectedIndexChanged(object sender, EventArgs e)
{
XMLds.XPath = "/controls/control[#id='AuthorityType']/item[#text='" + ddl.SelectedValue + "']/linkedValue";
XMLds.DataBind();
}
The XPath string is fine, I can output and test that it is working correctly and resolving to the correct nodes. What I am having problems with, is getting at the data that is supposedly stored in the XmlDataSource; specifically, getting the data and outputting it in a TextBox. I'd like to be able to do this as part of the function above, i.e.
protected void ddl_SelectedIndexChanged(object sender, EventArgs e)
{
XMLds.XPath = "/controls/control[#id='AuthorityType']/item[#text='" + ddl.SelectedValue + "']/linkedValue";
XMLds.DataBind();
myTextBox.Text = <FieldFromXMLDataSource>;
}
Thank you for your time.
Related
I have a dropdownlist inside a template column on a obout grid. Currently i am populating the dropdownlist on page load with a sqldatasource. However, i now have to load the dropdownlist dependent on the value of a certain column. For example: If status = 1, i populate the dropdownlist with a list of available options that pertain to status 1.
<obout:Column ID="colStatus" DataField="wf_status_id" Align="center" HeaderText="Status" HeaderAlign="center" Width="130px" Wrap="true" runat="server" AllowGroupBy="true" AllowFilter="true">
<TemplateSettings EditTemplateId="tmpStatusIDEdit" TemplateId="tmpStatusID" />
</obout:Column>
<obout:GridTemplate runat="server" ID="tmpStatusID" >
<Template>
<%# Container.DataItem["Status"]%>
</Template>
</obout:GridTemplate>
<obout:GridTemplate runat="server" ID="tmpStatusIDEdit" ControlID="ddlStatus" ControlPropertyName="value">
<Template>
<obout:OboutDropDownList runat="server" ID="ddlStatus" Width="100%" Height="200" MenuWidth="215" DataSourceID="sdsStatus" DataTextField="wf_status_text" DataValueField="wf_status_id" />
</Template>
</obout:GridTemplate>
public void OnGridRowDataBound(object sender, Obout.Grid.GridRowEventArgs e)
{
if (e.Row.RowType == Obout.Grid.GridRowType.DataRow)
{
DropDownList ddlStatus = new DropDownList();
ddlStatus = (DropDownList)e.Row.FindControl("ddlStatus");
//LOAD DROP DOWN HERE//
}
}
When i attempt to execute this code, it shows that ddlStatus is null everytime. I have a tried a multitude of ways to get this and for some reason cannot seem to get it. Perhaps aother set of eyes or other ideas could help me out. Please let me know what it is i am doing wrong. Thank you ahead of time
UPDATE:DATABOUND EVENT CODE
<obout:OboutDropDownList runat="server" ID="ddlStatus" Width="100%" Height="200" MenuWidth="215" OnDataBinding="ddlStatus_DataBinding" DataSourceID="sdsStatus" DataTextField="wf_status_text" DataValueField="wf_status_id" />
protected void ddlStatus_DataBinding(object sender, EventArgs e)
{
Obout.Interface.OboutDropDownList ddl = (Obout.Interface.OboutDropDownList)(sender);
string statusID = Eval("wf_status_id").ToString();
}
I added the DataSource because i do not see another way to have the databinding event triggered.
I don't really know anything about obout controls but I have to assume they act very similar to the asp.net controls and have just been extended. With that assumption in mind, I will try and answer your question.
Your RowDataBound event has a few coding issues... for example, I am not sure why you are defining a new DropDownList and then trying to overwrite it with the next line. Also it sounds like the next line is returning null anyways.
First off I suggest not using the DataBound event at the row level. Use the control's DataBinding event as it will localize your code a lot better because you can trigger off the specific control's DataBinding and therefore not have to search for it. If your code changes (markup or codebehind) it is also a lot easier to change as it will not affect other things and there is less room for introducing bugs.
So I would make the following changes to address this:
Change your DropDownList definition to implement DataBinding:
<obout:OboutDropDownList runat="server" ID="ddlStatus" Width="100%" Height="200"
MenuWidth="215" OnDataBinding="ddlStatus_DataBinding" />
Then implement the OnDataBinding event (get rid of your DataBound event if you weren't using it for anything else):
protected void ddlStatus_DataBinding(object sender, System.EventArgs e)
{
// This will point to ddlStatus on the current row that is DataBinding so you
// don't have to search for it.
OboutDropDownList ddl = (OboutDropDownList)(sender);
// Now you can fill the DropDownList and set the default value how ever you like
...
}
You can also see this other question I answered a long time ago to see if it helps as it is doing the same thing but with a Repeater but it is pretty much the same thing as a grid:
Populating DropDownList inside Repeater not working
EDIT: Changed the code to use OboutDropDownList in the DataBinding.
you can find plenty of samples on obout knowledge base and examples. These should help you out: http://www.obout.com/combobox/aspnet_integration_grid.aspx, http://www.obout.com/grid/aspnet_ajax_cascading_comboboxes.aspx
(they refer to comboBox, but you can easily adapt them do a ddl)
I have a repeater in one of the sublayouts in Sitecore 6.6. rev 120918. Inside this repeater, I have a placeholder. On ItemDataBound, I assign a key with a GUID to it, and using Nick Wesselman's GetAllowedRendering pipeline, I am able to render the insert options for this.
The repeater code is very simple:
<asp:Repeater runat="server" ID="rptrTimelineItemsEdit" OnItemDataBound="rptrTimelineItemsEdit_OnItemDataBound">
<ItemTemplate>
<sc:Placeholder ID="scTimelineItemPlaceholder" Key="timelineitemcontent" runat="server" />
</ItemTemplate>
</asp:Repeater>
The Item Data bound is also pretty simple:
protected void rptrTimelineItemsEdit_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Item item = (Item)e.Item.DataItem;
Placeholder scTimelineItemPlaceholder = (Placeholder)e.Item.FindControl("scTimelineItemPlaceholder");
scTimelineItemPlaceholder.Key = "timelineitemcontent" + item.ID.ToString().ToLower();
}
}
Everything works up to this point. After I choose the sublayout I want to insert in the placeholder, it throws me an in the JS error popup. After inspecting in the chrome inspector, I see the error is:
Could not find the rendering in the HTML loaded from server PlaceholderChromeType.js:601
Sitecore.PageModes.ChromeTypes.Placeholder.Sitecore.PageModes.ChromeTypes.ChromeType.extend._frameLoaded
So - it would seem like that in the page reload, the sublayout renderings are happening before the repeater bindings, so it can't find the placeholder key.
I did some google, and found that there is a way to change the layout engine sequence using the layoutpageevent setting:
However, this didn't solve my problem. I'm out of ideas. Help!
Hi there Ive found a solution to this issue, it had me stumped as well.
It only occurs to placeholders that sit under a repeater.
Overwrite PlaceholderChromeType.js in Website\sitecore\shell\Applications\Page Modes\ChromeTypes\
With the one ive dropboxed (also available on the credit link below)
https://www.dropbox.com/s/7m99b8jgdz3cgl2/PlaceholderChromeType.
Your keys then have to have dynamic in them for it to work.
Example code:
protected void R1_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
var p = e.Item.FindControl("andysplaceholder") as Placeholder;
p.ID = "Andy" + (e.Item.ItemIndex + 1);
p.Key = "dynamic" + p.ID;
}
<asp:repeater id="MyRepeater" runat="server" OnItemDataBound="R1_ItemDataBound">
<ItemTemplate>
<sc:placeholder runat="server" id="andysplaceholder" key="dynamicandysplaceholder" ></sc:placeholder>
</ItemTemplate>
</asp:repeater>
On top of this i do my repeater binding in the oninit method
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
and i set the web.config setting from preInit to load
<setting name="LayoutPageEvent" value="load" />
Although that might be overkill, I will revert today to page_load and preinit today and see if it still works.
Credit to Sitecore support and Mickey Rahman for this http://mickeyrahman.wordpress.com/2014/05/05/an-ode-to-sitecore-support/#respond
This should also work with the dynamic key apprach from Nick, you'll just have to make sure the keys generated by his code have dynamic in them
You have not implemented it in the way it's explained by Nick.
What you need to do is create a WebControl class for your Dynamic Placeholder.
That will ensure that things are processed in the same order as it would have with a 'real' Placeholder.
So the first thing I would do is make sure you do it in the same way as it's been described by Nick.
Then verify that it works with just 1 dynamic placeholder on the page.
Secondly, you should take a look at this blog post: Dynamic Placeholders and IExpandable
It explains how to deal with adding multiple dynamic placeholders in repeaters (and other controls).
He also thought that it had something to do with the change in the LayoutPageEvent, but it did not turn out to be that.
EDIT:
I've reproduced the issue and I highly doubt that you're going to solve it with this approach.
The placeholders are not loaded yet when the Page Editor is requesting their renderings after trying to add controls to them.
Even when you create the Placeholders in the OnInit (which is the earliest), it doesn't work.
If I get more time I'll try to look into it further.
Ruud referenced my blog post Dynamic Placeholders and IExpandable in his answer, and I think that he's definitely on the right track. I know that you haven't used dynamic placeholders in the way that I describe, however you are still creating placeholders dynamically.
I personally have never had any success with the LayoutPageEvent; which is why I decided to post about the use of IExpandable as it isn't something that's been highlighted that much.
You ought to create your placeholders in the Expand method and also expand them after you add them to the page. I would personally advise against using a Repeater to do so - add them to the controls collection or maybe to a normal ASP.Net PlaceHolder control.
public class YourSublayout : UserControl, IExpandable
{
public void Expand()
{
var myListOfItems = GetItems()
foreach (var item in myListOfItems)
{
var placeholder = new Placeholder { Key = "key" + item.ID.ToString() };
container.Controls.Add(placeholder); // add to a control container
placeholder.Expand();
}
}
}
Hopefully that should get you a bit further (if you haven't solved it already). Just keep in mind the other things I mention on my post, namely that the Expand method can be called before the control gets added to the page, and so getting your DataSource may break if you rely on getting it from the parent control.
I'm trying to add a button to the webpage, from the code behind. I have a single empty div on my main page that visible on and off, when needed. However the content I wish to create dynamically as the div content can change dependent on conditions.
I have realised that within my ASP Control I use a / (backslash) which cancels out my HTML. The problem I now have is understanding how I can get around this with code, is there a way to add ASP Controls to the web page? I am open to suggestions outside of the InnerHtml.
I'm creating my Button like so (in my Code Behind):
string buttonout = string.Format("<asp:Button ID=\"helpButton_0\" CommandArgument=\"0\" CssClass=\"HelpButton\" runat=\"server\" Text=\"?\"/>");
innercontent[0] = string.Format("<table><tr><td>Lead Passenger Information</td></tr><tr><td>Here by deafaul we used your detaisl from your profile, if you're not the lead passenger (As in you're booking for someone else) then please change details.</td></tr><tr><td>{0}</td></tr></table>"+ buttonout);
As Said above, The reason this doesn't work is because of InnerHtml hating backslashes, I think.
I do have a solution to this; and that's by adding more divs to the page.
<div id="HelpBoxDiv" runat="server" Visible="false">
<div id="HelpBoxDiv_Top" runat="server" Visible="true">
</div>
<div id="HelpBoxDiv_Bottom" runat="server" Visible="true">
<asp:Button ID="button_HelpBox_false" runat="server" />
</div>
</div>
I would then add my Innerhtml to the _Top Div, instead of the HelpBoxDiv which I am currently doing now. However this solution doesn't teach me anything.
I am hesitant to ask questions here, as I know a lot of question have been asked and I am sure this one has before, but I didn't find a solution. Any help is much appreciated.
Thank you.
I have realised that within my ASP Control I use a / (backslash) which
cancels out my HTML. The problem I now have is understanding how I can
get around this with code, is there a way to add ASP Controls to the
web page? I am open to suggestions outside of the InnerHtml.
You cannot add ASP.Net server control like a literal string.
Instead, you want to add the dynamic server control to the following approach -
ASPX
<asp:PlaceHolder runat="server" ID="PlaceHolder1"></asp:PlaceHolder>
Code Behind
protected void Page_Init(object sender, EventArgs e)
{
var button = new Button
{
ID = "helpButton_0",
CommandArgument = "0",
CssClass = "HelpButton",
Text = "?"
};
button.Command += button_Command;
PlaceHolder1.Controls.Add(button);
}
private void button_Command(object sender, CommandEventArgs e)
{
// Handle dynamic button's command event.
}
I have the following problem.
I have a asp:textbox on the page, runat server with an id of say txt
This text box is in a <div>, nothing special. ie:
<div>
<asp:TextBox id="txt" runat="server"></asp:TextBox>
</div>
The problem is there is some java script which when you push the corresponding button it doubles (copies) the div. This is by design. It is meant to.
When you hit save but at the bottom of the page on a asp:Button, it can't find the value I need because it returns two results.
In the code behind:
(Textbox) blah = (Textbox)senderbutton.FindControl("txt");
string test = blah.text
But the result is essentially--> "The value in the textbox , The value in the textbox"
I.e. it is there twice. I have worked around this by doing the following:
string[] test = blah.text.split(new[] { ',' })
and then only calling the second value in the array or whatever.
BUT, now I have this situation but the problem is that a user can enter a string with a ' , ' in it, hence the splitting goes to crap....
So can I find a control with an id, but only find the nth occurence of it in the code behind?
Seems you need to give different name(like txt0,txt1...) for each copy of the input controls.
You can do this using javascript up on client click(prior to form submission) of your asp button
-- Javascript method
function ModifyName() {
var x = 0;
$("input[name='txt']").each(function () {
$(this).attr("name", $(this).attr("name") + x);
x++;
});
}
-- asp:Button
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
OnClientClick="ModifyName();" onclick="btnSubmit_Click" />
So in code behind you can get the values like this...
protected void btnSubmit_Click(object sender, EventArgs e)
{
var resultArr = Request.Form.AllKeys.Where(x => x.Contains("txt"))
.Select(x => Request.Form[x]).ToArray();
}
Not a very nice solution, but you could examine the Request.Form collection directly upon postback and write some code to process your dynamically added textbox fields.
The best solution would be: avoiding copying the div in js. Since you said "This is by design. It is meant to."(even I really doubt it), there are some alternative solutions:
(1) Don't use the default submit behavior of the form. That is, in the click (js) event of the save button, organize the data in the form and then submit it.
(2) Modify the second(copied) textbox's id so that its id is different from the original one, and then get the data in code behind.
I am not sure why you using FindControl method to find the control when you can directly access the txt control from code behind.
You can get results easily
String test = txt.Text;
I feel a little embarassed posting two questions relating to the same problem, but the first one ended up answering a question that I believe is unrelated to the solution so I'm leaving it up and outlining what I'm trying to accomplish with the hopes that someone can help out a .Net noob.
What I need to be able to do is create a field in my gridview that contains a link that passes two variables. One is pulled from within the gridviews datasource and the other needs to be pulled from a textbox control outside the gridview.
From what I've read so far you cannot use a hyperlinkfield for this as the datanavigateurlfields cannot be set to pull from anything but the gridview's data source.
What I attempted to do was create a template field where in the itemtemplate I called:
Test
That comes back with an error like this:
DataBinding: 'System.Data.DataRowView' does not contain a property with the value 'TestData'
Any clues to make this happen would be appreciated, like I said I'm pretty new to .Net so please be gentle. I tried to do my homework before posting this.
How about putting a hyperlink server control in your GridView template column as below.
<asp:Hyperlink id="hyperlink" runat="server" onDataBinding="hyperlink_DataBinding" text="Click ME" />
Then in your code behind add this data binding event for the hyperlink.
protected void hyperlink_DataBinding(object sender, EventArgs e) {
HyperLink link = (HyperLink) sender;
string param1 = Eval("field").ToString();
string param2 = ExampleList.SelectedItem.Value;
link.NavigateUrl = "example.aspx?e=" + param1 + "&f=" + param2;
}