2

Currently when i press my previous button it only returns results to my text box. I want it to loop through the results. So the first time the button is clicked it will show the first record, looping through.

protected void btnPrevious_Click1(object sender, EventArgs e)
{
    DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter eobj = new DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter();
    DataTable dt = new DataTable();
    dt = eobj.GetTicketUpdates(txtSupportRef.Text);

    txtNextStep.Text = eobj.GetTicketData(txtSupportRef.Text).Rows[0]["NextStep"].ToString();
}

I would like to know how to return all my records and then loop through each one of them based on each click?

The idea is when you select a ticket it loads the latest details into the form. But then my intention is to have a previous and next button so that i can loop through the various updates that a ticket was on...

PriceCheaperton
  • 5,071
  • 17
  • 52
  • 94
  • So basically Click 1 would show the first record. Click 2 would show the 2nd and so on? – Jason Geiger Aug 20 '15 at 18:27
  • Yep spot on............. – PriceCheaperton Aug 20 '15 at 18:30
  • How is your data sorted, is everything in one table? Or are details stored in a second table and linked to the ticket? The first thing I can see is you need to load all the data and put it in some type of control (GridView?) and use a master-details relationship. The way you have it in the Click event you are needlessly reloading the data on every click. If you have a ComboBox to select your ticket #, then a details control below that you can flip through each item (in date order if that's how you sort it). – Calvinthesneak Aug 28 '15 at 18:36

5 Answers5

1

You need keep track of the clicks. Something like this is what you want.

protected void btnPrevious_Click1(object sender, EventArgs e)
{
    if (Session["ClickCount"] == null)
        Session["ClickCount"] = 0;

    int ClickCount = Convert.ToInt32(Session["ClickCount"]) + 1;
    Session["ClickCount"] = ClickCount;

    DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter eobj = new DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter();
    DataTable dt = new DataTable();
    eobj.GetTicketUpdates(txtSupportRef.Text);

    txtNextStep.Text = eobj.GetTicketData(txtSupportRef.Text).Rows[ClickCount - 1]["NextStep"].ToString();
}
Jason Geiger
  • 1,912
  • 18
  • 32
  • Hi @Jason Geiger this didn't quite work for me. I dont think a session is a good way to do this. The idea is when you select a ticket it loads the latest details into the form. But then my intention is to have a previous and next button so that i can loop through the various updates that a ticket was on... You see if i then pick another ticket reference from the drop down, the session variable method you suggested will continue to count up and ill get a `There is no row at position ` error. What would you suggest is the best way to return data the individual updates? – PriceCheaperton Aug 23 '15 at 08:36
1

So I understand you want a sequence of collections of records with the idea of a currently selected collection of records and the possibility to advance to the next collection of records or the previous collection of records.

Looping Through:

  • If the currently selected collection of records is the first one and Previous is selected then you want the last collection of records
  • If the currently selected collection of records is the lase one and Next is selected, then you want the first collection of records

How about this:

class CollectionLooper<IEnumerable<T>>()
{
    private List<IEnumerable<T>> collections = null;
    private int selectedIndex = 0;

    public CollectionLooper(IEnumerable<IEnumerable<T> collections)
    {
        if (collections == null) throw new ArgumentNullException("collections");
        this.collections = collections.ToList().AsReadOnly;
        // postcondition: this.collection refers to a list of IEnumerable<T>
        // that might be empty
        // if the list is not empty, then this.selectedIndex refers to
        // the first element of the list
    }

    // if the list is empty: return null: no sequence selected
    // if not empty: return the selected sequence
    public IEnumerable<T> SelectedCollection {get{return this.collection.Any() ?
       return this.collections(this.selectedIndex) : null;} }

    // if the list is empty: does nothing but return null, there is no next collection
    // otherwise: select the next collection in the sequence and return it
    public IEnumerable<T> NextCollection { { get
    {
        if (this.collection.Any())
        {
            this.selectedIndex = (++this.selectedIndex) % this.collections.Count();
            return this.SelectedCollection;
        }
        else return null;
    }

    // if the list is empty: does nothing but return null,
    // there is no previous collection
    // otherwise: select the previous collection in the sequenc and return it
    public IEnumerable<T> PreviousCollection { { get
    {
        if (this.collection.Any())
        {
            this.selectedIndex = (--this.selectedIndex) % this.collections.Count();
            return this.SelectedCollection;
        }
        else return null;
    }
}

Consider adding functions to Add collections to make changes to the set of collections possible.

Consider to make the class IEnumerable> to make Linq usage possible.

It is not wise to be able to remove items from the list, because that would make the currently selected element invalid.

Final remark: having one property TransactionRef which in face contains two values is a bit dangerous: what if there is a space before or after the '|'? Better to make TransactionRef a class with Properties Number ("20150824") and Guid ("Guid1").

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
1

Change the database selection methods to get next and previos ticket updates based on current value. Expecting that txtNextStep.Tag contains reference to current ticket update code might look following:

    protected void btnNext_Click1(object sender, EventArgs e)
    {
        DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter eobj = new DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter();
        DataTable dt = new DataTable();
        if (txtNextStep.Tag == null)//Pick first update.
            dt = eobj.GetTicketFirstUpdate(txtSupportRef.Text);
        else//Getting next ticket update for the ticket based on current displaying value
            dt = eobj.GetNextTicketUpdate(txtSupportRef.Text, (string)txtNextStep.Tag);

        if (dt.Rows.Count != 0)
        {
            txtNextStep.Text = dt.Rows[0]["NextStep"].ToString();
            txtNextStep.Tag = dt.Rows[0]["Id"].ToString();
        }
    }

For performace considiration, it possibly makes sense, to read several tickets update ids, so in case of buttong press, read by id will be executed and not search for next or previous ticket update.

Timur Mannapov
  • 217
  • 2
  • 9
1

Personally I would have a count that tracks the current 'click' that the user is on, like so:

protected void btnPrevious_Click1(object sender, EventArgs e)
{
    if(stepCount == 0)
        //Ensuring that we never get into minus numbers
        stepCount = 0;

    stepCount--;

    DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter eobj = new DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter();
    DataTable dt = new DataTable();
    dt = eobj.GetTicketUpdates(txtSupportRef.Text);

    txtNextStep.Text = eobj.GetTicketData(txtSupportRef.Text).Rows[0][stepCount].ToString();
}

protected void btnNext_Click1(object sender, EventArgs e)
{
    if(stepCount == 0)
        //Ensuring that we never get into minus numbers
        stepCount = 0;

    stepCount++;

    DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter eobj = new DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter();
    DataTable dt = new DataTable();
    dt = eobj.GetTicketUpdates(txtSupportRef.Text);

    txtNextStep.Text = eobj.GetTicketData(txtSupportRef.Text).Rows[0][stepCount].ToString();
}

You could also add a check in the next button click to check if the user is currently on the last record and if they are, send them to the start of the records list again.

Chris Etheridge
  • 111
  • 1
  • 2
1

Instead of doing this in the view code, you want to cache the results of your lookup, and only display the Next button if there's another item.

To do that, make a container object for them.

Assume your data is like this

class Ticket
{
     public string SomeField{get;set;}
}

Make a container like

class TicketList
{
    private List<Ticket> _tickets;
    private int _currentPosition;
    public TicketList<IEnumerable<Ticket> tickets>
    {
        _tickets = ticket;
        _currentPosition = 0;
    }

    public Ticket GetCurrent()
    {
        return _tickets[_currentPosition];
    }

    public bool CanMoveNext{
        get{
            return _tickets.Any() && _currentTicket != _tickets.Count - 1;
        }
    }


    public Ticket GetNext()
    {
        _currentPosition++;
        return _tickets[_currentPosition];
    }
}

So now when you load your application, you load the tickets into cache

var tickets = new List<Ticket>();
var data = eobj.GetTicketData(txtSupportRef.Text);
foreach(var row in data.Rows)
{
    var ticket = new Ticket{ 
        //map over the ticket data here, or use AutoMapper
    };
    tickets.Add(ticket);
}

var ticketList = new TicketList(tickets);
Cache.Store(ticketList);  //cache can be an application var, or better solution

On the page load, you can do var ticketList = Cache.GetTicketList(); btnNext.Visible = ticketList.CanMoveNext; var ticket = ticketList.GetCurrent(); //populate your fields

Now in addition to not reloading all the tickets on every page load, your code is going to be much easier to maintain in the future.

Mathieson
  • 1,698
  • 2
  • 17
  • 19