Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

understanding controls on a triple nesting repeater 2

Status
Not open for further replies.

NuJoizey

MIS
Aug 16, 2006
450
US
why do my values for Lines and Term get written to the screen, the words "a gridview should go here" gets written to the screen, a button that says "this is a button" on it gets written to the screen but the words "HELLO OUT THERE" do not get written to the screen?

Code:
<asp:Content ID="contPlacementList" runat="server" ContentPlaceHolderID="cphMainContent">
    <div>
        <asp:Repeater ID="Repeater1" runat="server">
            <ItemTemplate>
                <div><asp:Label ID="lblLines" style="font-weight:bolder;" runat="server" Text='<%# Eval("Lines") %>'/></div>
                    <asp:Repeater ID="Repeater2" runat="server">                    
                        <ItemTemplate>
                            <div><asp:Label ID="lblTerm" runat="server" Text='<%# Eval("Term") %>'/></div> 
                            <div>
                               <asp:Label ID="Label1" runat="server" Text="a gridview should go here"/>
                               <asp:Button ID="Button1" runat="server" Text="this is a button" />
                            </div>    
                            <asp:Repeater ID="Repeater3" runat="server"> 
                                <ItemTemplate>
                                    <%Response.Write("HELLO OUT THERE")%>HELLO OUT THERE
                                </ItemTemplate>
                            </asp:Repeater>                                                    
                        </ItemTemplate> 
                    </asp:Repeater>                
            </ItemTemplate>
        </asp:Repeater>
    </div>
</asp:Content>
 
Beucase you can't use Response. Write. Just put "HELLO OUT THERE" there and nothing more. ie.e Eliminate your <%Response.Write%>
 
tperri,

I tried that. no joy. it's like the third level isn't even there at all. Any other suggestions? Like most of my issues, this must be something simple and obvious that my lack of experience with .NET components makes me blind to.
 
where is this code located? and is it executed?
Code:
Repeater3.DataSource = TheData;
Repeater3.DataBind();

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
jmeckley, i think you're on the right track - the answer to that question is there isn't any - but there should be right? - and I think that's something I've just figured out, but please tell me if my reasoning is right.

Repeater3 can't display unless something is bound to it, ie. you can't just put in a value....is that correct?

Assuming this is the case, here is what I can't seem to figure out - In my codebehind I can't access any of the events of repeater3, like ItemDataBound for example from which to trigger the databinding like I can for Repeater1.

so then where do I do:


Code:
Repeater3.DataSource = TheData;
Repeater3.DataBind();

I just don't get it
 
Repeater3 can't display unless something is bound to it, ie. you can't just put in a value....is that correct?
correct.

there are a couple different ways to handle this.
1. assign the event handler using declarative syntax
Code:
<asp:Repeater3 OnItemDataBound="DoSomething" />
Code:
protected void DoSomething(object sender, RepeaterItemEventArgs e)
{
  //code goes here
}
2. using the events of Repeaters 1 and 2 assign the event handler in code behind.
Code:
protected override void OnInit(EventArgs e)
{
   Repeater1.ItemCreated += ItemCreated;
}

private void ItemCreated(object sender, RepeaterItemEventArgs e
{
    Repeater repeater = e.Item.FindControl("Repeater2") as Repeater;
    if(repeater != null)
    {
        repeater.Created += NestedItemCreated;
    }
}

private void NestedItemCreated(object sender, RepeaterItemEventArgs e
{
    Repeater repeater = e.Item.FindControl("Repeater3") as Repeater;
    if(repeater != null)
    {
        repeater.DataSource= GetDataFormSomewhere();
        repeater.DataBound();
     }
}
3. bind directly to the control
Code:
<asp:Repeater id="Repeater1">
   <ItemTemplate>
      <asp:Repeater id="Repeater2" DataSource='<%#(IEnumerable)Eval("SomeProperty")'>
         <ItemTemplate>
            <asp:Repeater id="Repeater3" DataSource='<%#(IEnumerable)Eval("SomeOtherProperty")'>
         </ItemTemplate>
   </ItemTemplate>
</asp:Repeater>
depending if you're using datatables, datasets or custom DTOs will require different syntax. for more information google nested repeaters. most sample use 2 repeaters. you just need to extrapolate an additional depth.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
you just need to extrapolate an additional depth.

yes, and i thought i would find it to be simpler than it has been! I think I'm having difficulty b/c I really don't understand databinding that well, and its variations of syntax, and I am having trouble finding a very simple example from which to extrapolate - however you may have just given me what I've been looking for. Let me see if i can make it work based on what you've put here.
 
well, here's what i've come up with. jmeckley, I used the declarative synatax (see red) to capture the OnItemDataBound event. Thank you for laying it out with those three choices. It's really not that difficult if you know where to look. Basically I kind of 'forgot' that you can access the events of the codebehind as inline properties in the aspx, and then the concept of then "re-writing" the event handler manually sort of eluded me. I guess after a few more years of this, it'll be elementary!
Code:
<asp:Content ID="contPlacementList" runat="server" ContentPlaceHolderID="cphMainContent">
    <div>
        <asp:Repeater ID="repLines" runat="server">
            <ItemTemplate>
                <div><asp:Label ID="lblLines" style="font-weight:bolder;" runat="server" Text='<%# Eval("Lines") %>'/></div>
                    <asp:Repeater ID="repTerm" runat="server" [COLOR=red]OnItemDataBound="repTermItemDataBound"[/color]>                    
                        <ItemTemplate>
                            <div><asp:Label ID="lblTerm" runat="server" Text='<%# Eval("Term") %>'/></div>   
                               <asp:GridView ID="gvPlacementList" runat="server"  />                                                                           
                        </ItemTemplate> 
                    </asp:Repeater>                
            </ItemTemplate>
        </asp:Repeater>
    </div>
</asp:Content>

And this is what I did in my vb codebehind in order to grab the value of lblLines, which you will notice resides in the parent this particular repeater. This gave me all kinds of trouble trying to figure out how to refer to it, but in the end it's pretty simple, although I'm not convinced that this isn't a kludge. I guess if it works, it's not a kludge, right? I then use that value to bind a gridview.
Code:
 Sub repTermItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs)

Dim strLines As String = CType(e.Item.[COLOR=red]Parent.Parent.[/color]FindControl("lblLines"), Label).Text

Dim strTerm As String = CType(e.Item.FindControl("lblTerm"), Label).Text

Call BindGridView(gvPlacementList, strTerm, strLines)

End Sub

I then bound the gridview using variables taken from the nested repeater:
Code:
    Sub BindGridView(ByVal gvPlacementList As GridView, ByVal strTerm As String, ByVal strLines As String)

        Dim cn As New SqlConnection(connstr)
        Dim da As New SqlDataAdapter("SELECT CompositeID, PlacementName, [Current Scenario], Status FROM viewPlacementList WHERE Term='" & strTerm & "' AND Lines='" & strLines & "'", cn)
        Dim dt As New DataTable
        da.Fill(dt)
        cn.Close()
        gvPlacementList.DataSource = dt
        gvPlacementList.DataBind()

    End Sub
and the combination of these things seems to deliver the overall layered effect that I desired in my initial post on this thread> thread855-1471495 , which jmeckley also graciously responded to.

Although this seems to work, I'm open to better ways to possibly do this if anyone has any suggestions.
 
now that it's working you can refactor.
first always use a parameterized query.
Code:
select * from table where column = @a_value
in your case
Code:
SELECT CompositeID, PlacementName, [Current Scenario], Status FROM viewPlacementList WHERE Term=@term AND Lines=@lines"
you will then need to define 2 parameters. one for term and one for lines.
I would also make the assumption that term and lines is defined by a PK, if so you should use these values instead of strings to select the data. that's making assumption about the db structure though.

I would also wrap your db objects in a using statement to manage resource if an exception is thrown
Code:
DataTable table = new DataTable();
using(SqlConnection cn = new SqlConnection())
{
   DataTableAdapter ta = new DataTableAdapter();
   ta.Fill(table);
}
repeater.DataSource = table;
repeater.DataBind();
this has the potential to suffer from n+1 queries beging executed because each grid view is populated by a unique query. if it's not a problem now, don't worry about it. just be aware this could be a bottle neck. for more information research n+1 sql queries.

to simplify your data extrapolation from the repeaters I would try this
Code:
<asp:Repeater ID="repLines" runat="server">
   <ItemTemplate>
      <div><%# Eval("Lines") %></div>
      <asp:Repeater ID="repTerm" runat="server" OnItemDataBound="repTermItemDataBound">                    
         <ItemTemplate>
            <div><asp:Label ID="lblTerm" runat="server" Text='<%# Eval("Term") %>'/></div>
            <asp:HiddenField id="Lines" runat="server" Value='<%#Eval("Lines")%>' />
            <asp:GridView ID="gvPlacementList" runat="server"  />                                                   </ItemTemplate> 
      </asp:Repeater>                
   </ItemTemplate>
</asp:Repeater>
Code:
protected void repTermItemDataBound(object sender, RepeaterItemEventArgs e)
   if(e.Item.ItemIndex > -1)
   {
      string strLines = ((HiddenField)e.Item.FindControl("Lines")).Value;
      string strTerm = ((Label)e.Item.FindControl("Term")).Text;
      BindGridView(gvPlacementList, strTerm, strLines);
   }
}

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
putting the hidden field where you did makes sense, but I would have thought that putting the <%#Eval("Lines)%> in the second level repeater trying to pull data from a control bound earlier to the parent repeater would have caused some sort of error. I didn't actually try this, but I trust that it would work as you say.

Does this syntax have an equivalent in VB?
Code:
string strLines = [COLOR=red]((HiddenField)e[/color].Item.FindControl("Lines")).Value;
One of my problems is this:
I have a basic idea of what "e" is and that it has something to do with eventArgs, and it is something whose properties/methods can be manipulated on an particular event firing, but other than that, to me "e" is just one of those nebulous objects that I don't really understand.
Do you know of a standard definition for it, or where I could read more about it to better understand it fundamentally?
 
ItemDataBound is an event on the Repeater object. Events are an implementation of the observer pattern. Basically you can have a collection of listeners wait for notifications from the sender. in this case the sender is the Repeater control and the listener is the page. the standard naming convention of an event handler is
Code:
delegate void [NameOfEvent](object sender, [X]EventArgs e);

sender is the object making the request. e contains information related to the event. in this case RepeaterItemEventArgs has information related directly to the current RepeatItem.

if you where creating your own event you could deviate from the standard like this
Code:
delegate void MyEventHandler(int aNumber, string someText, DateTime aDate);
or to follow the standard you would create MyEventArgs and pass that instead
Code:
public class MyEventArgs : EventArgs
{
   private int number;
   private string text;
   private DateTime date;

   public MyEventArgs(int aNumber, string someText, DateTime aDate)
   {
      number = aNumber;
      text = someText;
      date = aDate;
   }

   public int Number { get { return number; } }
   public string Text { get { return text; } }
   public DateTime Date { get { return date; } }
}

delegate void MyEventHandler(object sender, MyEventArgs e);
hopefully this gives you some direction instead of confusing you more. if you have more questions just ask.

for more information on programming patterns check out Head First: Design Patterns. this is an easy fun read. the book covers around 10 patterns with enteraining examples, sample code and exercises. the book uses java examples, but java and c# are like fretenal twins. VB to java can be more challanging because the syntax is drastically different, but the concepts and functionality are the same.

forum678 is dedicated to OOP. it's also language egnostic so everyone is in there, PERL, C# VB, Java, ColdFusion, Ruby, Python, etc. it's more about ideas and concepts than syntax.


Jason Meckley
Programmer
Specialty Bakers, Inc.
 
first always use a parameterized query.

you mean do something conceptually like this: (which doesn't work, there is a syntax error but in the interest of time I'm just posting it anyway:

Code:
Dim strSQL As String = "SELECT DISTINCT Term FROM viewPlacementList InsuredID=1664 AND Lines=@lines ORDER BY Term DESC"
        Dim cn2 As New SqlConnection(connstr)
        Dim da2 As New SqlDataAdapter(strSQL, cn2)
        Dim dt2 As New DataTable
        Dim cmd As New SqlCommand(strSQL)
        cmd.Parameters.Add("@lines", SqlDbType.Char, 50).Value = strLines
        cn2.Open()
        da2.Fill(dt2)
        repTerm.DataSource = dt2
        repTerm.DataBind()
        cn2.Close()

and if so, why is that any better than:

Code:
    Sub BindGridView(ByVal gvPlacementList As GridView, ByVal strTerm As String, ByVal strLines As String)

        Dim cn As New SqlConnection(connstr)
        Dim da As New SqlDataAdapter("SELECT CompositeID, PlacementName, [Current Scenario], Status FROM viewPlacementList WHERE Term='" & strTerm & "' AND Lines='" & strLines & "'", cn)
        Dim dt As New DataTable
        da.Fill(dt)
        cn.Close()
        gvPlacementList.DataSource = dt
        gvPlacementList.DataBind()

    End Sub

are you saying that the above isn't a form of a parameterized query?

Also, another fundamental non-understanding I have is regarding data access. There seems to be a zillion 'flavors' in which to do this, each with its own pattern of code and conceptual procedures. How does one know when it is best to do data access in a certain pattern? Is there a 'cookbook' anywhere of data access patterns and when to use each?
 
he is saying that using a paramterized query is better. For one, it prevents sql injection attacks, and your code does not.

I wouldn't say there is a cook book of what to do when - I think through trial and error and experimentation you can find out which methods you like best :)
 
research sql injection attack for more information.

your syntax error is the command object is missing the connection reference. should be
Code:
Dim cmd As New SqlCommand(strSQL, cn2)
or something similar.

the best thing about coding is there is always another way to solve the problem. the worst thing about coding...

While there is no right way to write code, the goal of good design is maintainability. this includes understanding what the code does 6 weeks, days, years after it's written and reducing artifacts when a change is required.

for me there are 2 umbrella(sp?) principles I strive for:
1. DRY: don't repeat your self
2. SR: single responsibility
from these two principles there are all kinds of practices.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
thanks all. this discussion has been enlightening for me. Right now my umbrella principle seems to be GTFTW (get the f$%#@! thing to work). I hope to work on ugrading that principle. [tongue]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top