p2p.wrox.com Forums

p2p.wrox.com Forums (http://p2p.wrox.com/index.php)
-   BOOK: ASP.NET 2.0 Website Programming Problem Design Solution ISBN: 978-0-7645-8464-0 (http://p2p.wrox.com/forumdisplay.php?f=264)
-   -   Passing articleID to ObjectDataSource.. (http://p2p.wrox.com/showthread.php?t=72634)

philthy February 8th, 2009 06:20 PM

Passing articleID to ObjectDataSource..
 
I’m working on tags for my articles. Everything is pretty much working now. I can create tags, and when I create a new article, I have the available tags listed in a checkbox list, so I can check the ones I want associated with my article. When I hit save, everything is saved correctly in the database.



Now, I want to show the tags for each article in the articles listing, and this is where I’m a little stuck. I have built my article list with a ListView. I have made a class Tag, which has a GetTagsByArticle method. So, I put an ObjectDataSource control on the page and set my Tag class as type for it. Then In my ListView, I tried to put a BulletedList control and hook it up to my ObjectDataSource. When I run the page, I get no output.



To test it, I tried to set a default value for the asp:Parameter to an articleID that exists in the database, and this works, it writes out all the tags for that particular article. Of course, this is not how it should be, it should write out the tags for each article, so I need to get the articleID for the current article in each loop of the ListView.



So far, I have been using Eval to get the values from the ObjectDataSource. I feel like this should be as easy as hooking the Datacontrol up to the ObjectDataSource, but I can’t figure it out. Maybe I have been staring myself blind on it…
Any ideas?

This is the code for the ObjectDataSource.

<asp:ObjectDataSource ID="ObjTags" runat="server" SelectMethod="GetTagsByArticle"
TypeName="SG.Blog.BLL.Articles.Tag" OldValuesParameterFormatString="original_{0}">
<SelectParameters>
<asp:Parameter Name="articleID" Type="Int32"/>
</SelectParameters>
</asp:ObjectDataSource>

Lee Dumond February 10th, 2009 12:11 PM

Not sure I understand the question.

Are you saying that you want a list of articles, and for each article in the list, you want to display a list of relevant tags for that article in a bulleted list? Kind of like this?:

Article: My Favorite Websites
  • personal
  • web
Article: Good Places to Stay
  • vacations
  • hotels
  • reviews
Article: Interview with Valentino Rossi
  • interviews
  • motorcylces
  • racing

philthy February 10th, 2009 12:34 PM

Hey Lee.

Not specifically a bulleted list. My problem is that I don't get any output from the Tag ObjectDataSource at all. For instance, I tried putting in a ListView, and hooking that up to the ObjectDataSource (the code I posted) and this gives me no output. However, when I set a default value for an articleID in the parameter element in the ObjectDataSource, I get the tags written out for that article. So it seems that it works, but I can't get the right articleID to the ObjectDataSource. I have no idea why...
Code:

        <SelectParameters>
            <asp:Parameter Name="articleID" Type="Int32"/> 
      </
SelectParameters>

Gives no output in the ListView

Code:

  <SelectParameters>
        <asp:Parameter Name="articleID" Type="Int32" DefaultValue="9"/>
      </SelectParameters>

Writes the tags from article ID = 9.

This is the ListView I tested with:
Code:

<asp:ListView ID="ListViewTags" runat="server" DataSourceID="ObjTags" ItemPlaceholderID="tags"
                                DataKeyNames="ID">
                                <LayoutTemplate>
                                    <asp:PlaceHolder runat="server" ID="tags"></asp:PlaceHolder>
                                </LayoutTemplate>
                                <ItemTemplate>
                                    <span>
                                        <asp:Label ID="Label1" CssClass="" runat="server" Text='<%# Eval("TagName") %>'></asp:Label></span>
                                </ItemTemplate>
                            </asp:ListView>

Soeren...

Lee Dumond February 10th, 2009 01:06 PM

I must be stupid today.

I think I kinda get it, but I am still having a hard time getting a "picture" of what you want the output to look like. Can you show a rough idea of the final rendering you're going for here?

Part of the problem I am having a hard time picturing this is that you're wrapping the label in a span tag, and Labels are already rendered with <span>, so you would end up with <span><span> here. Plus, it looks like there's no separation between tag names?

Sorry...

philthy February 10th, 2009 01:31 PM

Not at all Lee, I really appreciate all the help you provide :-)

I know the code I provided looks a little weird, but it is mostly test code, which allways looks kinda weird :-D So far, I have been trying with a ListView and a BulletedList, but I can't get any output from the ObjectDataSource, not without providing a default value, which is not what I want. Doing so, shows me that my BLL/DAL/Database works fine, and that I have, apparently, configured my ObjectDataSource/ListView correctly.

The problem is getting the articleID to the GetTagsByArticle method, in every loop of the ListView. I thought this was just a matter of hooking the ListView up to the ObjectDataSource. It works in all the other pages I have used ObjectDataSource/ListView.

My problem is not so much with layout, but more with getting som sort of output to layout :-) My final layout would be like most other blogs, with the tags shown somewhere in the bottom of each entry. But again, this comes later.

Soeren

Lee Dumond February 13th, 2009 12:29 AM

Dude... I stared at this for about an hour before I finally figured out what you were trying to do and why it doesn't work.

Once I got my head around it, I was able to whip up a quickie app on my end, and it works awesome. The way I did it was to use a nested ListView -- where the list of articles is a ListView, and the lists of tags is also a ListView nested inside of the Articles list.

Is that what you are looking for?

(Hint: You don't bind the inner ListView with an ObjectDataSource, only the outer one...)

philthy February 13th, 2009 10:37 AM

Quote:

Originally Posted by Lee Dumond (Post 234776)
The way I did it was to use a nested ListView -- where the list of articles is a ListView, and the lists of tags is

also a ListView nested inside of the Articles list.

(Hint: You don't bind the inner ListView with an ObjectDataSource, only the outer one...)

Thats exactly how I did it, only difference is that I also bound the inner ListView to an ObjectDataSource. I have a class Tag, and this class has a method "GetTagsByArticle". So, I made that the select method, and then the Tag class as Type in this ObjectDataSource.

The problem I'm having is that the inner ListView doesn't seem to know which article ID to use. I have the DataKeyNames property set to "ID".

However, if I provide the Tag ObjectDataSource with a default value for the select parameter, it works (but only for that particular articleID).

I bind the outer ListView to an ObjectDataSource to get the articles, and the inner ListView to an ObjectDataSource to get the tags for each article.

So, the outer ListView uses GetArticles in the Article class to write the data for each entry in the articles list, and when it reaches the inner ListView, this uses the GetTagsByArticle(articleID) to write the tags for that particular article. I want the articleID for GetTagsByArticle to be that of the current article which is being written by the outer ListView, and this is where I'm stuck. It's like these two ListViews need to be syncronized somehow...

In my design, I decided to create a class for tags, like the ones for comments and categories. Therefore, it felt natural to have one ObjectDataSource for articles, and another one for tags, but since the tags are written in a nested ListView, apparently this is harder than I thought.
I have this many-to-many relationship between the articles and the tags, and it works fine.

I hope you understand the nonsense I'm writing, but hey, I'm Danish :-D

Again, thanks so much for all the help...

Lee Dumond February 13th, 2009 12:22 PM

Quote:

Originally Posted by philthy (Post 234814)
Thats exactly how I did it, only difference is that I also bound the inner ListView to an ObjectDataSource. I have a class Tag, and this class has a method "GetTagsByArticle". So, I made that the select method, and then the Tag class as Type in this ObjectDataSource.

I bind the outer ListView to an ObjectDataSource to get the articles, and the inner ListView to an ObjectDataSource to get the tags for each article.

Yes, this is exactly how I envisioned it, and it is exactly the first approach I tried. And (no surprise!) I had the same problem you had.

So then, I figured I would intercept the ItemDataBound event on the outer ListView, grab the inner ListView from the Controls collection, grab the articleID from the eventargs, and pass it in that way. No joy there though, because once ItemDataBound has fired on the outer list, it's too late to bind the inner list.

Then I finally figured out how to do this the right way. The key is NOT to bind the inner list to a datasource at all, but to bind the inner list to a property of the outer list item using a data expression. That way, when the outer list item is databound, it will bind the innerlist at the same time, all in one pass.

Here is the page:

Code:

<%@ Page Language="C#" %>

<!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 id="Head1" runat="server">
  <title>Articles</title>
</head>
<body>
  <form id="form1" runat="server">
      <div>
        <asp:ListView ID="lstArticles" runat="server" DataSourceID="objArticles"
            ItemPlaceholderID="itemPlaceHolder1">
            <ItemTemplate>
              <p>
                  <asp:Label ID="lblArticleTitle" runat="server" Font-Bold="true"
                    Text='<%# Eval("Title") %>' />
                  <br />
                  <asp:Label ID="lblPublishedDate" runat="server" Font-Italic="true"
                    Text='<%# Eval("PublishedDate","{0:MMM d, yyyy}") %>' />
                  <br />
                  Tags:
                  <asp:ListView ID="lstTags" runat="server" ItemPlaceholderID="itemPlaceHolder2"
                    DataSource='<%# Eval("Tags") %>'>
                      <ItemTemplate>
                        <asp:Label ID="lblTagName" runat="server" Text='<%# Eval("TagName") %>' />
                    </ItemTemplate>
                    <LayoutTemplate>
                        <asp:PlaceHolder ID="itemPlaceHolder2" runat="server" />
                    </LayoutTemplate>
                  </asp:ListView>
              </p>
            </ItemTemplate>
            <LayoutTemplate>
              <asp:PlaceHolder ID="itemPlaceHolder1" runat="server" />
            </LayoutTemplate>
        </asp:ListView>
        <asp:ObjectDataSource ID="objArticles" runat="server" SelectMethod="GetArticles"
            TypeName="LD.Blog.Article" />
      </div>
  </form>
</body>
</html>

Note that the inner list (lstTags) is not bound to a data source, but is instead bound using the following databinding expression:

Code:

DataSource='<%# Eval("Tags") %>'
Tags is a property of Article that uses the GetTagsByArticle method to get its value.

Code:

namespace LD.Blog
{
  public class Article
  {
      public int ArticleID { get; set; }

      public string Title { get; set; }

      public DateTime PublishedDate { get; set; }

      private List<Tag> tags;

      public List<Tag> Tags
      {
        get
        {
            if (tags == null)
            {
              tags = Tag.GetTagsByArticle(this.ArticleID);
            }

            return tags;
        }
      }
 

      public static List<Article> GetArticles()
      {
        // snipped out       
      }
  }
}

The "Tags" databinding expression is evaluated at the same time as "Title" and "PublishedDate" -- that is, when each Article item is fetched. The inner list then binds to Tags, which internally uses GetTagsByArticle(), just like the ObjectDataSource would have, except it does it at the right time -- when the Article data is actually available.

I tried this with some fake data and it works, so I hope that helps you out. If you need, I can zip the whole thing up and email it to ya.

Have fun. [:)]

philthy February 13th, 2009 08:58 PM

Amazing man... That works [:)]

I also tried the ItemDataBound trick, and also tried with some other events, with no luck ofcourse. I also considered trying the Tags property in the articles class, but I really felt that hooking my Tag class to the ObjectDataSource should work.

But, even if I had used the Tags property, I wouldn't have considered using DataSource='<%# Eval("Tags") %>' for the inner ListView like you suggested. I would have been close.... Close but no cigar...

This is really a great learning experience.

I want to thank you again for the excellent help, really awesome [:)]

Lee Dumond February 14th, 2009 03:21 PM

Don't forget to click the Thanks button. I need all the ego boosts I can get. ;-)


All times are GMT -4. The time now is 12:51 PM.

Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.