How to reference XML data that isn't bound to a repeater - c#

C# newbie asking, so if the question is stupid or the answer is really obvious, it's probably because I don't fully understand how XmlDataSource works.
Given the following XML file "super-simple-xml.xml" (formatted to save some space),
<items>
<item> <one id="ms">Microsoft</one> <two>MSFT</two> </item>
<item> <one id="in">Intel</one> <two>INTC</two> </item>
<item> <one id="de">Dell</one> <two>DELL</two> </item>
</items>
a repeater that looks something like this,
<asp:Repeater id="SuperSimple" runat="server" OnItemCommand="SuperSimple_ItemDataBound">
<HeaderTemplate>
<table border="1"><tr><th>Company</th><th>Symbol</th><th>Wrong</th></tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><asp:Label Text=<%#XPath("one") %> runat="server" /></td>
<td><asp:CheckBox Text=<%#XPath("two") %> runat="server" id="symbol" /></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
<asp:Button id="buttonOne" Text="Submit!" runat="server" />
</FooterTemplate>
</asp:Repeater>
and the following to bind the XML:
private void Page_Load(object sender, EventArgs e)
{
XmlDataSource xmlSource = new XmlDataSource();
xmlSource.DataFile = "super-simple-xml.xml";
xmlSource.XPath = "items/item";
if (!IsPostBack) // Did this to prevent an error
{
SuperSimple.DataSource = xmlSource;
SuperSimple.DataBind();
}
}
How would I go about pulling the id from each XML entry into a class or variable?
The idea here is that I am displaying the items in a Repeater. I added checkboxes, so I can check any of the <two> entries, and then press Submit. When it posts back, I want to store the checked entry in a class I've made. Getting <one> and <two> in are easy enough because they have IDs in the Repeater that I can reference. But the id attribute in the XML is never called, so I don't know how to get to it. I want to have the id in the class to reference as I pass the data along. Is this possible, and how do I do it?

Use the XPath # syntax for getting an attribute:
<%# XPath("one/#id") %>
You can bind this expression to a HiddenField and access that in the postback:
<asp:HiddenField runat="server" ID="hidID" Value='<%# XPath("one/#id") %>' />
Add a command button to the <ItemTemplate>:
<asp:Button runat="server" ID="btnGetID" Text="Get ID" CommandName="GetID" />
In the OnItemCommand event:
protected void SuperSimple_ItemDataBound(object sender, RepeaterCommandEventArgs e)
{
//check the item type, headers won't contain the control
if (e.CommandName == "GetID")
{
//find the control and put it's value into a variable
HiddenField hidID = (HiddenField)e.Item.FindControl("hidID");
string strID = hidID.Value;
}
}
This is an alternative (I originally posted because I was confused by the name of your OnItemCommand event and thought you wanted the values at DataBinding time):
In your <ItemTemplate>:
<asp:Button runat="server" ID="btnGetID" OnClick="btnGetID_Click" Text="Get ID" />
Code-behind:
protected void btnGetID_Click(object sender, e as EventArgs)
{
//sender is the button
Button btnGetID = (Button)sender;
//the button's parent control is the RepeaterItem
RepeaterItem theItem = (RepeaterItem)sender.Parent;
//find the hidden field in the RepeaterItem
HiddenField hidID = (HiddenField)theItem.FindControl("hidID");
//assign to variable
string strID = hidID.Value;
}

Maybe this helps, problem could be in wrong xml structure.
http://forums.asp.net/t/1813664.aspx/1?getting+xml+node+id+number

Related

How to access the current ItemType Item value from OnItemCommand method of ListView?

In aspx page:
<asp:ListView ID="ListViewPosts" ItemType="Post"
SelectMethod="ListViewPosts_GetData" runat="server"
OnItemCommand="Insert_Comment"
OnItemDataBound="ListViewPosts_ItemDataBound">
...
...
</asp:ListView>
Code behind:
protected void Insert_Comment(object sender, ListViewCommandEventArgs e)
{
...
Post p = Item; //where Item stands for the current Post record in ListView.
...
}
If I have this ListView where in ItemType="Post"; Post is a database table.
How to access the current value of Item (which stands for the current record from thePost table) in the code behind method Insert_Comment
I asked a question for OnItemDataBound method and the code:
Post p = e.Item.DataItem as Post works well. I tried the same code for OnItemCommand but the variable Post p gets null value!!.
I can use CommandArgument but I am wondering if I can get the Post item directly like the way I can with OnItemDataBound methos.
You can use use .DataItem only within OnItemDataBound. You may pass the Id of the Item and use it to bring the Item back from the database:
<asp:ListView ID="ListViewPosts" ItemType="Post"
SelectMethod="ListViewPosts_GetData" runat="server"
OnItemDataBound="ListViewPosts_ItemDataBound">
<ItemTemplate>
<asp:LinkButton runat="server" ID="btn_InsertComment" CommandName="Insert_Comment" CommandArgument='<%# Eval("PostID") %>' Text="Insert" />
</ItemTemplate>
</asp:ListView>
protected void Insert_Comment(object sender, ListViewCommandEventArgs e)
{
LinkButton btn_InsertComment = (LinkButton) sender;
string postId = btn_InsertComment.CommandArgument;
//use this id to create a new comment
}

How to find table cell in asp.net using c#

I want to hide an itemtemplate's data in listview using the td visibility property. Once I click a button it should show the data again that's within the itemtemplate. However, I cannot find the td control using c# in the code behind. Is there a way to find this control or another way to handle this?
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
<asp:Button ID="Button1" runat="server" Text="Search" OnClick="ButtonClick" />
<asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
<asp:View ID="View1" runat="server">
<asp:ListView ID="SectionListView" runat="server" InsertItemPosition="FirstItem" OnPagePropertiesChanged="SectionListView_PagePropertiesChanged">
<ItemTemplate>
<tr style="">
<td></td>
<td id="row1" style="visibility:hidden;" runat="server">
<asp:Label ID="SectionItemLabel" runat="server" Text='<%# Eval("SectionItem") %>' />
</td>
</tr>
</ItemTemplate>
Here is part of the code for the button click:
protected void ButtonClick(object sender, EventArgs e)
{
var temp = (System.Web.UI.HtmlControls.HtmlTableCell)Page.Master.FindControl("MainContent").FindControl("row1");
}
You have a couple of issues. First, when you try to find "row1" within "MainContent", if won't find it because "row1" is actually a child of other children of "MainContent". It won't find them recursively unless you tell them to.
Second, since each ListViewItem within your ListView contains "row1", they are each given their own unique ID, such as SectionListView_ctrl0_row1, SectionListView_ctrl1_row1, etc. Because of this, you need to use FindControl() on each ListViewItem.
But, because you need to do it on each ListViewItem and because each ListViewItem contains "row1", each row will get the same property (i.e. all visible or all invisible). Here is how that could be done:
protected void ButtonClick(object sender, EventArgs e)
{
foreach (ListViewItem lvi in SectionListView.Items)
{
if (lvi.ItemType == ListViewItemType.DataItem)
{
HtmlTableCell row1 = (HtmlTableCell)lvi.FindControl("row1");
row1.Style.Add("visibility", "hidden");
}
}
}
If you need to style each cell individually, they would each need to be named differently. It is common to attach some sort of number or database ID to the end of the ID if that is the case.

ASP.NET Button OnClick within Repeater and LoginView

I'm developing a ASP.NET website with a C# backend. I'm having a problem with how to set an onclick event for buttons that are nested inside of both a loginview and a repeater. The code works fine for displaying all of the other data (anonymous view displays only an error message) but right now the buttons just redirect to the same page and remove the repeater and all contents, whereas they're supposed to run a specific delete function. The repeater, as it is right now, uses an alternatingitem template. If I remove the buttons from the nested controls, they work. I've tried this with buttons, linkbuttons, and imagebuttons. I'd rather use the latter, if possible. Is it possible to assign an Onclick to these buttons if they're nested like this? If not, what approach should I use?
<asp:LoginView ID="LoginLinksView" runat="server" EnableViewState="false">
<AnonymousTemplate>
<asp:Label ID="errorlabel" runat="server"></asp:Label>
</AnonymousTemplate>
<LoggedInTemplate>
<asp:Repeater id="Repeater" runat="server" >
<HeaderTemplate>
<table cellspacing="0" cellpadding="0">
<thead></thead>
</HeaderTemplate>
<ItemTemplate>
<tr class="Repeaterrow">
<!--Additional code here-->
<asp:ImageButton ID="delbutton" runat="server" ImageUrl=
"~/Images/delete.png" Onclick="DeleteOnClick"/>
</tr>
</ItemTemplate>
<AlternatingItemTemplate>
<tr class="Repeaterrow">
<!--Additional code here-->
<asp:ImageButton ID="delbutton" runat="server" ImageUrl=
"~/Images/delete.png" Onclick="DeleteOnClick"/>
</tr>
</AlternatingItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</LoggedInTemplate>
</asp:LoginView>
Here are the problems with your approach
1- The button issues postback as it should. But you need to put some CommandArgument with to identify "key" or which row you are processing it for.
2- Re Bind your Repeater with source. Below is the sample code for you.
protected void Page_Load(object sender, EventArgs e)
{
BindRepeater();
}
private void BindRepeater()
{
List<int> items = new List<int>();
for (int i = 0; i < 10; i++)
{
items.Add(i);
}
Repeater.DataSource = items;
Repeater.DataBind();
}
protected void DeleteOnClick(object sender, EventArgs e)
{
ImageButton delbutton = (sender as ImageButton);
//1- call your method with passing in delbutton.CommandArgument - it will give you key/ whatever you like
//2- Rebind the Repeater here and that will bind controls again...
BindRepeater();
}
protected void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
ImageButton delbutton = (sender as RepeaterItem).FindControl("delbutton") as ImageButton;
if (delbutton != null)
{
delbutton.CommandArgument = (sender as RepeaterItem).ItemIndex.ToString();
}
}
and ASPX Repeater definition would change to
Thanks,
Riz

Placing ListView DataItem Property into UserControl Template

Sort of new to .NET and trying to understand how best to accomplish this task: I have a listview with a datasource containing a list of string values. The last property is some text that I'd like to place in the Text template; normally when not used inside a listview I can place markup and text inside the template successfully, so I'd like to keep this structure. But what would be a way of placing that string inside there? I've tried Databinder.Eval but as expected it says that the template doesn't contain the property I'm referring to from Container.DataItem (which becomes the template).
<asp:ListView runat="server"
ID="ListView1"
OnItemDataBound="ListView1_ItemDataBound">
<LayoutTemplate>
<div class="navigation">
<asp:PlaceHolder runat="server" id="itemPlaceholder" />
</div>
</LayoutTemplate>
<ItemTemplate>
<my:Control id="VideoLink1" runat="server">
<Text>
--- PLACE CONTENT HERE --
</Text>
</my:Control>
</ItemTemplate>
</asp:ListView>
Anyone have an idea how to accomplish this? Would be greatly appreciated.
Use ItemDatabound event of the ListView. In that find your control and then assign the desired properties.
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
YourControl VideoLink1= e.Item.FindControl("VideoLink1") as YourControl ;
if(VideoLink1!= null)
{
YourClass obj = ((YourClass)(((System.Web.UI.WebControls.ListViewDataItem)(e.Item)).DataItem));
VideoLink1.TextProperty = obj .TextProperty ;
}
}
}

How to pass in runtime a index of row for ListView?

I have an question, On my page i have a ListView control, I also have a button that has CommandArgument. I know i can read and find a control in the ListView as :
ListView.Items[i].FindControl("controlname");
and my button in ListView is like that
asp:Button ID="WisdomButton" runat="server" CommandName="UpdateWisdom" CommandArgument='<%# need my index for Item[i] to post here %>'
OnCommand="UpdateWisdom" Text="Update" />
I want to add index value in runtime to the CommantParameter, so when i go to the Function onCommand i will know exactly from what row[i] i Need to get my controls from ListView.
So my question is, how do i dinamicly add index of ListView.Rows[i] into CommmandArgument for the Button in runtime ?
Thanks in advance.
Check out the API
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listviewcommandeventargs.aspx
The ListViewCommandEventArgs item has an index, IE it is already available in the argument
ListViewDataItem dataItem = (ListViewDataItem)e.Item;
int i = dataItem.DisplayIndex;
But from here you will have access to those controls
e.Item.FindConrol("controlName");
If you are calling the method a different way you could aways assign the index through an ItemDataBound Event
void MyListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
((Button)e.Item.FindControl("WisdomButton")).CommandArgument = ((ListViewDataItem)e.Item).DisplayIndex;
}
OR try something like this for giggles
<asp:Button runat="server" CommandArgument='<%# DisplayIndex %>'/>
// OR
<asp:Button runat="server" CommandArgument='<%# NextIndex() %>'/>
It might help to know a little bit more about what your are trying to do. If your end goal is to get any of the properties from your bound object you can just cast the dataItem from the ListViewCommandEventArgs of the ItemCommand event. You don't need to retain the index or call FindControl at all.
Here is an example of how to get the bound Customer object.
ListView
<asp:ListView runat="server" id="Customers" ItemCommand="Customers_ItemCommand">
<LayoutTemplate>
<ul>
<asp:placeholder runat="server" id="itemPlaceholder" />
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<asp:Button runat="server" id="Select" CommandName="Select" />
<%# Eval("Name")%>
</li>
</ItemTemplate>
</asp:ListView>
CodeBehind
public void Page_Load()
{
if (!Page.IsPostBack)
{
this.Customers.DataSource = GetCustomers();
this.Customers.DataBind();
}
}
public void Customers_ItemCommand(object sender, ListViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
if (e.Item.ItemType != ListViewItemType.DataItem)
return;
var customer = ((ListViewDataItem)e.Item).DataItem as Customer;
if (customer != null)
{
// Now work directly with the customer object.
Response.Redirect("viewCustomer.aspx?id=" + customer.Id);
}
}
}
Edit: In addtion when you cast the item to a ListViewDataItem, then you also expose a ((ListViewDataItem)e.Item).DataItemIndex property that might help you.

Categories