I display 16 of 147 images in a grid. when the user presses "next", I would like the page number to increment and the next 16 images to display.
To do this, I have a "next" button at the bottom (and prev, of course). I've added the following markup to the html:
<asp:Button runat="server" ID="btnNext" Text="Next" OnClick="btnNext_Click" CommandName="btnNextCmd" oncommand="btnNext_Command" />
I've placed the two event handlers in the code behind and added a break point to each handler, as well as to the Page_Load method.
The catch is that the Page_Load is executed before either of the button event handlers. I need to determine if the "Next" button was pressed, BEFORE the Page_Load executes, since this determines which 16 images to display.
Is there a way to determine if the "Next" button was clicked, without using an event handler? I assume that calling the event handler from the Page_Load method would gum up the works, since .NET is going to call that handler after processing the Page_Load method.
CodePudding user response:
Why is page load determine this?
Move the code from the page load event that loads the pictures to the next and previous buttons.
Or, better yet, have the next/previous buttons call that routine to load the pictures. Since the dawn of time for asp.net, page load has ALWAYS fired before any other button code, and it fires each time.
Since page load has ALWAYS fired before everything else, then the goal here would not to be re-engineer the WHOLE WAY and WHOLE asp.net model, but in fact to write your code that conforms to how web forms work. I mean, it would not be fair to suggest that you are the first person in 20 years of this system to have that issue, are you?
the general code pattern is that we "often" do want some setup code, initialization code, and a boatload of code to ONLY run on the first "real" page load, and thus you write such code like this in page load:
If Not IsPostBack Then
' first time page load code goes here
' set starting image page list number
' set ending page image list number
Call ImageLoad()
End If
So, now for next button, we have
' set start/end image numbers
Call ImageLoad()
So, now, each time you click a button or ANY post-back occures on the page, the first time page load event will now not fire nor run.
In fact, for the last 200 web pages I have coded out, EVERY SINGLE one of those pages has that all important if NotPostBack then run first time code in all of those pages.
In fact, you can't really even build a operational webforms page unless you do the above.
Say for example on page load, you run code to load up a combo box (dropdown list).
if you don't use a if Not is Post back stub in page load?
Then on page load (which as I noted RUNS EVERY TIME and RUNS BEFORE your button event stub?
Well, what will occur is by re-loading and re-binding the dropdown list, you now lose your dropdown settings, and your selection will be lost!!!
in fact, even for say setting up a few text boxes with some default values?
Again, we can use page load event, but ONLY code inside that Not post back stub can be used for setting up everything on the page. If we setup some defaults, and have it run each time? Then any entry into those text box(s) will be blown out, and over written each time. (by say some code that loads up default values for the user to edit).
Same goes for loading a grid or anything else. Once again, you REALY have to make sure you place code inside of that not post back stub on page load, since then you only re-load the grid or whatever on the REAL and TRUE first page load. After that occurs, then each additional button click etc. will re-run the page load event, but of course code inside of that "not" post back stub will not run!!!
So, place your setup code, your starting list of pictures to display inside of that "not" postback stub.
Then your next/previous buttons can work, and the code to load up, setup and load the first page of pictures will only ever run one time.
So, keep the above concept in mind.
That concept?
you really cannot build a functional working asp.net webform page by ignoring the above advice - it just the way they work, and thus you use the IsPostBack flag to control if that setup and startup code is a "one time" occurring, or in some cases, we do in fact WANT some code to run each time on page load.
so, just keep in mind that page load fires each and every time for ANY button click, and even a dropdown list with autopost-back will re-trigger the page load event.
But, armed with above knowledge, you not care, since we have a real and true first page load event, and that real and true first page load event is in fact the code you place in the page load event, but inside of that if/then Not post back stub.
Edit: Working example of above
So, now, lets cobble together some working code based on above concept.
lets assume a folder with some images. (I have a junk folder of cut paste images - lets just use that for this example).
So, I want to display some images on a page - next/previous buttons.
So, we will:
on our first REAL page load, pull files from folder
send files to a in memory data table (no database)
send those files to a list view (or grid view)
So, first up, we need markup to display a image. We can use grid view, or a repeater, or my favorate is listview (I like list view, since it supports a data pager for next/previous).
So, inside of our listview, we just cook up some markup for ONE picture, and thus it will "repeat" over and over.
So, I have this markup:
<asp:ListView ID="ListView1" runat="server" Allowpaging="true" >
<ItemTemplate>
<div >
<div style="text-align:center;padding:2px 10px 2px 10px" >
<asp:Button ID="cmdMyView" runat="server" Text="View"
CssClass="btn-info" style="float:right"
/>
<br />
<h3><%# Eval("File") %></h3>
<asp:Image ID="Image2" runat="server"
ImageUrl = '<%# Eval("FileAndPath") %>' Width="150" />
<br />
</div>
</div>
</ItemTemplate>
</asp:ListView>
All I did was "create" a box and layout for one image.
In fact, the data pager markup is perhaps "more of a mess".
So, right below the above listview, I have this for the data pager:
<br />
<div style="clear:both;height:10px"></div>
<asp:DataPager ID="DataPager1" runat="server" PagedControlID="ListView1" PageSize="8" >
<Fields>
<asp:NextPreviousPagerField PreviousPageText=" <i class='fa fa-chevron-right'></i> Prev"
ShowPreviousPageButton="true"
ShowNextPageButton="false" ShowLastPageButton="false"
ButtonCssClass="btn btn-default" />
<asp:NumericPagerField ButtonType="Link"
CurrentPageLabelCssClass="btn btn-primary disabled"
NumericButtonCssClass="btn btn-default" ButtonCount="10"
NextPageText="..." NextPreviousButtonCssClass="btn btn-default" />
<asp:NextPreviousPagerField NextPageText=" Next <i class='fa fa-chevron-left'></i> "
ShowNextPageButton="true"
ShowPreviousPageButton="false" ShowFirstPageButton="false"
ButtonCssClass="btn btn-default" RenderDisabledButtonsAsLabels="false" />
</Fields>
</asp:DataPager>
(can't remember where I found above - but I use it over and over).
So, now our code. We read that folder of files, shove them into a "on the fly" table, and then send the table to the listview.
This code thus uses that VERY important real first page load (code inside of not a post back stub).
So, this:
Dim rstFiles As New DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadPictures()
LoadGrid()
ViewState("rstPics") = rstFiles
Else
rstFiles = ViewState("rstPics")
End If
End Sub
Sub LoadPictures()
rstFiles.Columns.Add("File")
rstFiles.Columns.Add("FileAndPath")
rstFiles.Columns.Add("Created", GetType(DateTime))
Dim sFolder As String = "~/Content/Pictures"
Dim MyFolder As New DirectoryInfo(Server.MapPath(sFolder))
Dim MyFileList() As FileInfo = MyFolder.GetFiles("*.*")
For Each OneFile As FileInfo In MyFileList
Dim OneRow As DataRow = rstFiles.NewRow
Debug.Print($"<{OneFile.Name}>")
OneRow("File") = OneFile.Name
OneRow("FileAndPath") = sFolder & "/" & OneFile.Name
OneRow("Created") = OneFile.CreationTime.ToString("G")
rstFiles.Rows.Add(OneRow)
Next
End Sub
Sub LoadGrid()
ListView1.DataSource = rstFiles
ListView1.DataBind()
End Sub
And for data pagaing, you need this event code:
Protected Sub ListView1_PagePropertiesChanging(sender As Object, e As PagePropertiesChangingEventArgs) Handles ListView1.PagePropertiesChanging
DataPager1.SetPageProperties(e.StartRowIndex, e.MaximumRows, False)
LoadGrid()
End Sub
So, the result is now this:
but, we could replace above with a simple grid view, and say this markup:
A gridview, and pager tends to be less markup.
so, say this gridview
<asp:GridView ID="GridView1" runat="server" Width="40%"
AutoGenerateColumns="False" CssClass="table" AllowPaging="True" PageSize="6" >
<Columns>
<asp:BoundField DataField="File" HeaderText="FirstName" ItemStyle-Width="230"/>
<asp:TemplateField HeaderText="Preview" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Image ID="Image2" runat="server"
ImageUrl = '<%# Eval("FileAndPath") %>' Width="120" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="View"
CssClass="btn-info" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<PagerStyle CssClass="GridPager" />
</asp:GridView>
the code is near idential.
So, LoadGrid is now this:
Sub LoadGrid()
GridView1.DataSource = rstFiles
GridView1.DataBind()
End Sub
And pager event code is this:
Protected Sub GridView1_PageIndexChanging(sender As Object, e As GridViewPageEventArgs) Handles GridView1.PageIndexChanging
GridView1.PageIndex = e.NewPageIndex
Me.LoadGrid()
End Sub
and now we see/get this: