You could compare the current session ID to the last page that was loaded and then compare the IsPostBack command.
If IsPostBack is true you know the user has clicked something on that page to post the page back.
If the last page that was retrieved for the current session ID was not the same as the page you are currently loading then they arrived at this page from another page.
If the last page that was retrieved is the same for the current session ID as the current page you are processing then this was likely a refresh (F5).
The only problem would be that you would detect F5 the same as someone putting their cursor in the address bar and hitting the Enter key once the page had finished loading, but I doubt this would be a problem for you.
EDIT:
There seems to be some confusion on the comments about how this system would work so let me explain further. As was pointed out to me IsPostBack is not available in MVC so you have to test for post backs as shown here:
ASP.NET MVC - Is IsPostBack still here?
Let us consider the three ways in which you can end up at a page, any page. For our examples let us assume we want to detect refreshes on page X.
You can get to Page X these ways:
1. User presses a button on page A which takes you to page X.
2. User presses a button on Page B which posts you back to page B (post back).
3. User presses F5 or reloads the page some other way. - this is the one we want to detect..
There is scenario 4 which is 'user comes to page X from another site' but this would start a new session so let us not consider this.
Everytime a user loads a page you store that page somewhere along with the SessionID. The SessionID is constant for any one user for the duration of the session time out. There are some caveats to this such as accessing from different browsers on a single machine but I do not want to confuse matters.
Scenario 1:
User loads page A, we look in our memory and there are no records at present. We store 'Page A' and the sessionID in memory.
User clicks button on Page A.
User is redirected, posts or transferred to Page B.
Page B loads, we check the 'IsPostBack' flag, it may or may not be true at this point. If it is we know it is not a refresh, if it is false we need to continue to test as follows. we look in our memory and there is a record for 'Page A' for the current Session ID (remember the session ID does not change between requests for any given user).
because the previous page was 'Page A' and we are on Page B we know this is NOT a refresh.
We store 'Page B; and the sessionID in memory (in practice we either erase or update the previous record pointing to Page A).
Scenario 2:
User loads page B, we store 'Page B' and the sessionID in memory.
User clicks a button on page B.
Page B loads, we check 'IsPostBack' flag. It is true so we know this is not a refresh.
Scenario 3:
User loads Page B, we store 'Page B' and the sessionID in memory.
User refreshes the page or reloads it by putting their cursor in the address bar and hitting enter.
Page B loads, we check the 'IsPostBack' flag, it is false so we need to continue to test as follows. we look in our memory and there is a record for 'Page B' for the current Session ID. Because the previous page was 'Page B' and we are on Page B we know this IS a refresh.
By using this approach you can detect refreshes. If you are using MVC you can test Request.HttpMethod=="POST"
The only problem you get is if the user does a POST, you do a redirection, then the user goes back one page and refreshes from there are is will resubmit the form, sending the POST again. This will be detected as a fresh submission when it is actually a refresh. This can be eliminated using a Nonce approach or something similar.