Nathan
Nathan

Reputation: 919

Asp.Net repeater format item based on previous record

I have a thorny little problem where I am outputting an audit trail and need to highlight the changes to each record.

I am currently using a Linq-to-Sql data source to pull the audit data back and then displaying it in a table using a repeater which works fine.

The problem is I need to change the background colour of a cell if its value has changed from the previous record and I'm struggling to find a way to do this.

An alternative I've considered is to simply generate the whole table which will work but I just get the feeling there must be an easier way to do this.

Any thoughts?

Upvotes: 2

Views: 3287

Answers (6)

Hossein Pour
Hossein Pour

Reputation: 29

Add a hiddenfield before Repeater with a default value, compare each value with hiddenfield value for your purpose and set hiddenfield value with new value in end of repeater like this:

<asp:HiddenField ID="hf" runat="server" Value="0" />
<asp:Repeater ID="rptHistory" runat="server" DataSourceID="dsHistory">
    <ItemTemplate>
        <div class='time-label <%# Convert.ToDateTime(Eval("AddDate")).Date.ToString() == hf.Value ? "d-none" : "" %>'>
            <span class="bg-info">
                ...
            </span>
        </div>
        <div>
            ...
        </div>
        <span class="d-none"><%# hf.Value = Convert.ToDateTime(Eval("AddDate")).Date.ToString() %></span>
    </ItemTemplate>
</asp:Repeater>

Upvotes: 0

Lee Davies
Lee Davies

Reputation: 41

I know this is an old question but to contribute to the knowledge pool and because I too found this tricky.

The declarative solution is to access the previous DataListItem

((DataList)Container.Parent).Items[Container.ItemIndex-1]

However, unfortunatly the DataItem property of this seems to be null so you cannot eval properties of the previous DataItem (for instance to perform a comparision with a property of the current DataItem).

e.g this does not work:

<%# ( DataBinder.Eval((((DataList)Container.Parent).Items[Container.ItemIndex-1]).DataItem, "SomeProperty") ) == Eval("SomeProperty") ) ? "SAME" : "DIFFERENT" %>

However, you can use the ListItem.FindControl to access a control from the previous item and access the controls contents.

(Eval("SomeProperty").ToString() == ((Label)(((DataList)Container.Parent).Items[Container.ItemIndex-1].FindControl("LabelBoundToSomeProperty"))).Text) ? "SAME" : "DIFFERENT"

Finally, a gotcha - when binding the first item there is no previous item so you will get an index out of bounds exception. As such you just have to first check that you aren't in the first item.

Putting it all togetehr gives you a final purely declarative solultion:

<%# (Container.ItemIndex==0) ? "FIRST" : (Eval("SomeProperty").ToString() == ((Label)(((DataList)Container.Parent).Items[Container.ItemIndex-1].FindControl("LabelBoundToSomeProperty"))).Text) ? "SAME" : "DIFFERENT" %>

The above will write out whether we are on the first item, or on subsequent items whether the chosen property is the SAME or DIFFERENT from that property in the previous item.

(p.s. first ever SO submission - long time reader, first time writer :)

Upvotes: 4

Nathan
Nathan

Reputation: 919

After must playing about I found that it was quickest to generate the html manually.

I forgot to mention in the original question that I had to reverse the order to the records (i.e. most recent first) and therefore it became even more difficult to style the record in a repeater event e.g. add first record which has to have colour coded cells to indicate changes but at this point the next record hasn't been written so you have nothing to compare against.

The easiest way seemed to be to loop through the records in the code behind and do the comparison there property to property and then to create the html with styling based on that.

Thank you to everybody who took the time to look at the question and suggest solutions.

Upvotes: 0

Ray
Ray

Reputation: 21905

Create a field in your page class:

private int previousValue;

Then in the ItemCreated or ItemDataBound event:

int currentValue = << get current value >>;

if (previousValue != currentValue) {
  << do highlight >>;
  previousValue = currentValue;
}

Upvotes: 0

Yoenhofen
Yoenhofen

Reputation: 397

Select the collection of data items and save it to a class variable with a protected get property. The collection of data items needs to be keyed to the index. Then databind the GridView to the collection of data items at runtime.

Then you should be able to access the previous item in asp.net with a tag something like

<%# this.DataItems[Container.DataItemIndex] == this.DataItems[Container.DataItemIndex] ? "same as previous item" : "different than previous item" %>

Upvotes: 0

Shawn Steward
Shawn Steward

Reputation: 6825

You can use the ItemDataBound event to check the values of the items as they're bound. At this point you can check the value against the previous cell and if it is different add a CssClass to it that has the formatting you want.

Upvotes: 2

Related Questions