CascadingDropDown Missing parameter: knownCategoryValues - asp.net

I am having some trouble getting CascadingDropDown lists to work, its displaying the Method 500 error inside the list. I have tried all the common solutions to this and still no luck.
I was originally getting the following error:
System.ArgumentException: Invalid
method name 'getcategories',
method names are case sensitive. The
method name 'GetCategories'
with the same name but different
casing was found. Parameter name:
methodName
Which is odd because I am definately setting the method name in the correct case but it was sending it in lowercase (even though chrome showed the page as sending it in the correct case). Anyhow I worked around this by changing the method name itself to lowercase. This now brings up a new error:
System.InvalidOperationException:
Missing parameter:
knownCategoryValues.
If anyone could shed any light on either of these problems that would be a great help, I've spent way too long on this problem.
Thanks.
UPDATED Code:
<ajaxToolkit:ToolkitScriptManager EnablePageMethods="true" ID="ToolkitScriptManager1" runat="server">
</ajaxToolkit:ToolkitScriptManager>
<ajaxToolkit:CascadingDropDown
ID="CascadingDropDown1"
runat="server"
TargetControlID="mmCategory"
Category="Category"
PromptText="Select a category"
ServicePath="~/DropDownLists.asmx"
ServiceMethod="GetCategories" />
<ajaxToolkit:CascadingDropDown
ID="CascadingDropDown2"
runat="server"
TargetControlID="mmTemplate"
ParentControlID="mmCategory"
PromptText="Select a template"
ServiceMethod="GetTemplates"
ServicePath="~/DropDownLists.asmx"
Category="Template" />
Category: <asp:DropDownList ID="mmCategory" runat="server"/><br/>
Template: <asp:DropDownList ID="mmTemplate" runat="server"/><br/>
Web Service File:
using System;
using System.Web;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.Services;
using System.Web.Services.Protocols;
using AjaxControlToolkit;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Linq;
/// <summary>
/// Summary description for TemplateData
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService()]
public class DropDownLists : System.Web.Services.WebService
{
public DropDownLists()
{
//Uncomment the following line if using designed components
//InitializeComponent();
}
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public CascadingDropDownNameValue[] getcategories(string knownCategoryValues, string category)
{
List<CascadingDropDownNameValue> values = new List<CascadingDropDownNameValue>();
values.Add(new CascadingDropDownNameValue("test 1", "1"));
values.Add(new CascadingDropDownNameValue("test 2", "2"));
return values.ToArray();
/*using (MiscDataContext dc = new MiscDataContext())
{
var CatQuery = from D in dc.Templates
select new { D.Category }
into CatQueryResults
select CatQueryResults;
foreach (var CatResult in CatQuery)
{
string CatReturn = CatResult.Category;
values.Add(new CascadingDropDownNameValue(CatReturn, CatReturn));
}
return values.ToArray();
}*/
}
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public CascadingDropDownNameValue[] GetTemplates(string knownCategoryValues, string category)
{
StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);
string varCat;
varCat = kv["Category"];
List<CascadingDropDownNameValue> values = new List<CascadingDropDownNameValue>();
values.Add(new CascadingDropDownNameValue("test 3", "3"));
values.Add(new CascadingDropDownNameValue("test 4", "4"));
return values.ToArray();
/*using (MiscDataContext dc = new MiscDataContext())
{
var CatQuery = from D in dc.Templates
where(D.Category == varCat)
select new { D.ID, D.Name }
into CatResult
select CatResult;
foreach (var CatResult in CatQuery)
{
int ID = (int)CatResult.ID;
string Name = CatResult.Name;
values.Add(new CascadingDropDownNameValue(Name, Convert.ToString(ID)));
}
return values.ToArray();
}*/
}
}

In order to be usable with a CascadingDropDown, your web method's prototype must be:
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public CascadingDropDownNameValue[] GetCategories(
string knownCategoryValues, string category)
{
}
If you assign something to the ContextKey property of the extender, that prototype becomes:
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public CascadingDropDownNameValue[] GetCategories(
string knownCategoryValues, string category, string contextKey)
{
}
The knownCategoryValues parameter represents the current selection in the master dropdown. You should pass it to CascadingDropDown.ParseKnownCategoryValuesString() to obtain its actual value.

Related

converting query to list (not working) asp.net mvc

I am trying to create a query whose results will be stored in a ViewModel. When I try to assign the query variable to the ViewModel's method, I get the following error: "cannot implicitly convert type 'System.Linq.Iqueryable' to 'System.Collections.Generic.List'. An explicit-conversion exists (are you missing a cast?)".
I tried changing my ViewModel's methods to be of type Iqueryable instead of List which worked but then I couldn't use a foreach loop in my view to loop through my model so I changed it back to List. I tried doing ToList() after my query but that didn't work either. Any suggestions/hints/tips are greatly appreciated. Below is my controller code and my ViewModel code.
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using KU_PLAN_DEV.Models;
namespace KU_PLAN_DEV.ViewModels
{
public class TrackViewModel
{
public List<string> TRACK_INFO { get; set; }
public List<string> GEN_ED_HEAD { get; set; }
}
}
Controller method:
public ActionResult DisplayTrackSheet(string trackButton)
{
var db = new KuPlanEntities();
var trackProgNum = (from info in db.TRACK_INFO
where info.degreeName == trackButton
select info.progNum).ToString();
var trackVerNum = (from info in db.TRACK_INFO
where info.degreeName == trackButton
select info.versionNum).ToString();
/*var queryTrack = (from tracks in db.GEN_ED_HEAD
where tracks.)*/
var trackData = (from trackInfo in db.TRACK_INFO
where trackInfo.progNum == trackProgNum
&& trackInfo.versionNum == trackVerNum
select trackInfo);
var trackDisplayMod = new TrackViewModel
{
TRACK_INFO = trackData
};
return View(trackDisplayMod);
}
var trackDisplayMod = new TrackViewModel
{
TRACK_INFO = trackData.ToList()
};
What error do you get when you make that change?

set selected value based off parent value

I have 2 cascading drop downs, 1 is a parent and the other/child populates once you select a value in the first/parent drop down.
The first one populates on page load and I can set the selected value for this one based off database value that was saved on previous page.
For the second cascading drop down it populates for me when I set the selected value for the parent ID on page load (based off the database value).
But since the second/child drop down is not set/loaded with values until the page loads I can not set the selected value (I tried on Page_Load_Complete but it does not work there either).
I need to know how once I set the selected value in the parent drop down (this works fine), to populate the second drop down based off the value in the first one.
Here is my code for the aspx page. I can set the first selected value, and it populates the second select box (but I can not set the selected value because it is not populated at the time I set the first selected value.
aspx page
<asp:Label ID="lblAffPartCat" Text="<%$ Resources:share,lblAffPartCat %>" runat="server"></asp:Label>
<asp:DropDownList ID="ddlPartCat" runat="server"></asp:DropDownList>
<ajaxToolkit:CascadingDropDown ID="CascadingDropDown2" runat="server" TargetControlID="ddlPartCat"
Category="BasePart" PromptText="<%$ Resources:share,lblSelPartCat %>" LoadingText="[Loading Part Cat...]"
ServicePath="PAIntExtPart.asmx" ServiceMethod="BindPartCat"
ContextKey="" UseContextKey="True"/>
<asp:Label ID="lblAffBasePart" Text="<%$ Resources:share,lblAffBasePart %>" runat="server"></asp:Label>
<asp:DropDownList ID="ddlBasePart" runat="server" ></asp:DropDownList>
<ajaxToolkit:CascadingDropDown ID="ddlBasePart_CascadingDropDown" runat="server" Category="BasePart"
TargetControlID="ddlBasePart" ParentControlID= "ddlPartCat" PromptText="<%$ Resources:share,lblSelBasePart %>"
LoadingText="Loading Base Parts.."
ServicePath="PAIntExtPart.asmx"
ServiceMethod="BindBasePart"
ContextKey="" UseContextKey="True" />
asmx.cs page that populates the drop downs:
using System;
using System.Collections.Generic;
using System.Web.Services;
using System.Data;
using System.Collections.Specialized;
using AjaxControlToolkit;
using Hotline.DataAccess;
/// <summary>
/// Summary description for PAIntExtPart
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService()]
public class PAIntExtPart : System.Web.Services.WebService
{
string _SiteLocation = MiscFunctions.getCurrentSiteLocation();
/// <summary>
/// WebMethod to Populate Part Category Dropdown
/// </summary>
[WebMethod]
public CascadingDropDownNameValue[] BindPartCat(string knownCategoryValues, string category, string contextKey)
{
DataTable dsPartCat = null;
// string passed for contextKey is FormType and Language split by ":"
string[] arrcontextKey = contextKey.Split(':');
string FormType = arrcontextKey[0].ToString();
int LanguageID = Int32.Parse(arrcontextKey[1].ToString());
string PartCatValue = arrcontextKey[2].ToString();
try
{
dsPartCat = HarDB.getPartCat(_SiteLocation, LanguageID, FormType);
//create list and add items in it by looping through dataset table
List<CascadingDropDownNameValue> PartCatdetails = new List<CascadingDropDownNameValue>();
foreach (DataRow dtrow in dsPartCat.Rows)
{
string PartCatID = dtrow["PartCatID"].ToString();
string PartCat = dtrow["PartCat"].ToString();
PartCatdetails.Add(new CascadingDropDownNameValue(PartCat, PartCatID));
}
if (PartCatValue.Trim() != "")
{
//SelectedValue = PartCatValue;
}
return PartCatdetails.ToArray();
}
catch (Exception ex)
{
Server.Transfer("Errorpage.aspx?function=getAttachInfo+Error=" + Server.UrlEncode(ex.Message));
return null;
}
}
/// <summary>
/// WebMethod to Populate Base Part Dropdown
/// </summary>
[WebMethod]
public CascadingDropDownNameValue[] BindBasePart(string knownCategoryValues, string category, string contextKey)
{
string PartCatID;
//int LanguageID = Int32.Parse(contextKey);
string[] arrcontextKey = contextKey.Split(':');
string FormType = arrcontextKey[0].ToString();
int LanguageID = Int32.Parse(arrcontextKey[1].ToString());
string BasePartValue = arrcontextKey[2].ToString();
//This method will return a StringDictionary containing the name/value pairs of the currently selected values
StringDictionary PartCatdetails = AjaxControlToolkit.CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);
PartCatID = PartCatdetails["BasePart"];
DataTable dsBasePart = null;
try
{
dsBasePart = HarDB.getBasePart(_SiteLocation, LanguageID, PartCatID, FormType);
//create list and add items in it by looping through dataset table
List<CascadingDropDownNameValue> BasePartdetails = new List<CascadingDropDownNameValue>();
foreach (DataRow dtrow in dsBasePart.Rows)
{
string BasePartID = dtrow["BasePartNumID"].ToString();
string BasePart = dtrow["BasePartNum"].ToString();
BasePartdetails.Add(new CascadingDropDownNameValue(BasePart, BasePartID));
}
if (BasePartValue.Trim() != "")
{
//SelectedValue = PartCatValue;
}
return BasePartdetails.ToArray();
}
catch (Exception ex)
{
Server.Transfer("Errorpage.aspx?function=getAttachInfo+Error=" + Server.UrlEncode(ex.Message));
return null;
}
}
}
I found out my issue, I was not using the correct "Selected Value" when trying to populate the second drop down.

Recursive function to going through each embedded schema field in a schema to reach a leaf data field

I have a schema in Tridion which have embedded schema fields which may further have embedded fields in there.
I want to reach final leaf field so that I can assign some value to it. For that I want to write recursive function which loop through each and every field until it reaches a final field.
I am implementing using the Core Service in SDL Tridion 2011
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ServiceModel;
using System.Net;
using System.Xml;
using Tridion.ContentManager.CoreService.Client;
using System.Text;
using Tridion.ContentManager.CoreService;
using System.ServiceModel.Channels;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Data.OleDb;
using System.Data;
using System.Configuration;
namespace Loading_Utility
{
public partial class TST : System.Web.UI.Page
{
Fields obj = new Fields();
protected void Page_Load(object sender, EventArgs e)
{
using (ChannelFactory<ISessionAwareCoreService> factory =
new ChannelFactory<ISessionAwareCoreService>("wsHttp_2011"))
{
ISessionAwareCoreService client = factory.CreateChannel();
var schemaFields = client.ReadSchemaFields("tcm:202-2242-8", true, new ReadOptions());
ComponentData component = (ComponentData)client.GetDefaultData(ItemType.Component, "tcm:202-638-2");
var fields = Fields.ForContentOf(schemaFields);
component.Schema.IdRef="tcm:202-2242-8";
}
}
public void fieldRecursion(Field field)
{
//var getFields = fields;
if (field.GetType() == typeof(EmbeddedSchemaFieldDefinitionData))
{
// code for checking further if field is embedded or not
//Field newField = field.GetSubFields().GetFieldElements( new ItemFieldDefinitionData() as Field)
//fieldRecursion(recursiveField);
}
//string fieldName = recursiveField.Name;
//fields[fieldName] = "HI";
}
}
}
Whilst I don't have the solution you are looking for, I see you're using the core service, personally I prefer to get hold of the Component XML (Component.Content) and parse/manipulate it as I need. Perhaps if you can paste the XML here I can drop it into one of my sample core service projects and send you a solution back?
In the event that doesn't help you, i've had a look at the api, and this should help you get going in the right path. Perhaps once you have a solution you could paste it here?
public void RecurseEmbeddedFields(SchemaFieldsData schemaFields)
{
foreach (ItemFieldDefinitionData field in schemaFields.Fields)
{
if (field.GetType() == typeof(EmbeddedSchemaFieldDefinitionData))
{
// check if this field contains more embedded fields
// if it does recurse
}
}
}
OK, I felt a bit guilty about not helping, but I still stand by my view that this is not a Tridion-related question and that you should try getting some more experience with general development practices.
Here's an example of how to load the Component's content, then read it recursively using Xml:
Xml of the component:
<Content xmlns="uuid:02395f72-acef-44e8-9c35-ff8c9f380251">
<EmbeddedSchema1>
<SomeField>Hello</SomeField>
<EmbeddedSchema2>
<ATextField>There</ATextField>
</EmbeddedSchema2>
</EmbeddedSchema1>
</Content>
Core Service code:
static void Main(string[] args)
{
SessionAwareCoreServiceClient client = new SessionAwareCoreServiceClient("wsHttp_2011");
ReadOptions readOptions = new ReadOptions();
ComponentData component = (ComponentData)client.Read("tcm:5-3234", readOptions);
Console.WriteLine("Find fields recursively");
XmlDocument content = new XmlDocument();
content.LoadXml(component.Content);
SchemaData schema = (SchemaData)client.Read(component.Schema.IdRef, readOptions);
XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
ns.AddNamespace("content", schema.NamespaceUri);
foreach (XmlElement node in content.SelectNodes("content:*", ns))
{
ReadContentRecursively(node, ns);
}
client.Close();
}
private static void ReadContentRecursively(XmlElement node, XmlNamespaceManager ns)
{
if(!string.IsNullOrEmpty(node.InnerText))
{
foreach (XmlNode innerNode in node)
{
if(innerNode is XmlText)
{
Console.WriteLine("Node " + node.Name + " with value \"" + innerNode.Value + "\"");
}
}
}
if(node.SelectNodes("content:*", ns).Count > 0)
{
foreach (XmlElement childNode in node.SelectNodes("content:*", ns))
{
Console.WriteLine("Found Field: " + childNode.Name);
ReadContentRecursively(childNode, ns);
}
}
}
Notice how ReadContentRecursively calls itself?
Hope this helps.

Hiding a link in asp.net

Duplicate:
Hiding a link in asp.net
Hi
this is the cs file of the masterpage...
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace LevoContactManagement
{
public partial class Default : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
BasePage page = (BasePage)Page;
if (page.CurrentUser != null)
{
lblCurrentUser.Text = "<strong>" + page.CurrentUser.FullName + "</strong> - " + page.CurrentUser.CompanyName;
if ((Session["CCFUser"] != null) && (bool.Parse(Session["CCFUser"].ToString()) == true))
{
ctrlLinkBar.AddLink("Issues Management", "AllIssues.aspx");
}
else
{
if (true) ctrlLinkBar.AddLink("Home", "Default.aspx");
if (page.CurrentUser.Permissions.Issues()) ctrlLinkBar.AddLink("Issues Management", "AllIssues.aspx");
if (page.CurrentUser.Permissions.Time()) ctrlLinkBar.AddLink( "Time Management", "TimeEntryForm.aspx");
if (page.CurrentUser.Permissions.Time()) ctrlLinkBar.AddLink("Time Filter", "TimeFilter.aspx");
if (page.CurrentUser.Permissions.SVN() && !(this.Page is _Default)) ctrlLinkBar.AddLink("SVN", "SVN.aspx");
if (true) ctrlLinkBar.AddLink("Profile", "ChangePassword.aspx");
if (page.CurrentUser.Permissions.Administration()) ctrlLinkBar.AddLink( "Administration", "Administration.aspx");
}
}
else lnkLogout.Visible = false;
}
protected void lnkLogout_Click(object sender, EventArgs e)
{
Session.Abandon();
FormsAuthentication.SignOut();
Response.Redirect("Login.aspx");
}
}
}
i need to make the link Time Filter hidden.
the cs file of LinkBar is
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebControlLib
{
[ToolboxData("<{0}:LinkBar runat=server></{0}:LinkBar>")]
public class LinkBar : WebControl
{
struct Link
{
public string Title;
public string URL;
public override string ToString()
{
return "<a href='" + URL + "'>" + Title + "</a>";
}
}
private bool m_bIsVertical = false;
private List<Link> m_Links = new List<Link>();
public bool IsVertical
{
get
{
return m_bIsVertical;
}
set
{
m_bIsVertical = value;
}
}
public void Clear()
{
m_Links.Clear();
}
public void AddLink(string Title, string URL)
{
Link lnk = new Link();
lnk.Title = Title;
lnk.URL = URL;
m_Links.Add(lnk);
}
protected override void RenderContents(HtmlTextWriter output)
{
List<string> items = new List<string>();
foreach (Link lnk in m_Links)
items.Add(lnk.ToString());
string sep = IsVertical ? "</td></tr><tr><td>" : " | ";
output.Write(
#"
<table width='100%' class='linkBar'>
<tr>
<td>" + string.Join(sep, items.ToArray()) + #"</td>
</tr>
</table>
");
}
}
}
how do i go about it? i changed the master.designer.cs file as follows-->
public partial class Default {
protected System.Web.UI.HtmlControls.HtmlForm form1;
protected System.Web.UI.WebControls.Label lblCurrentUser;
protected System.Web.UI.WebControls.LinkButton lnkLogout;
public WebControlLib.LinkBar ctrlLinkBar;
public System.Web.UI.WebControls.ContentPlaceHolder LeftNav;
protected System.Web.UI.WebControls.ContentPlaceHolder ContentPlaceHolder1;
protected System.Web.UI.WebControls.ContentPlaceHolder BodyContent;
}
but the link still does not appear on the Design view of the masterpage, hence i cant find the id, therefore i cant hide it. What is an alternative to this?
I assume that you're talking about hiding the link to TimeEntryForm.aspx, and that you probably want to do this in only limited circumstances (which is why you don't want to just omit the line).
The link isn't actually in itself a control, so it won't have its own ID. It's a member of the List of links that belongs to the LinkBar control, and the LinkBar takes care of rendering them to the screen.
As you're adding these links to the LinkBar at run time, they won't display in the design view preview in Visual Studio - it will only display when you view the page in a browser.
I'd suggest that you get rid of the LinkBar, and just add the controls to the page as simple HyperLink controls. If you like, do this in the designer. Then you can set the visibility of each link in the code behind using the Visible property on those hyperlinks, like such:
hlTimeLink.Visible = page.CurrentUser.Permissions.Time();

ASP.NET MVC Search Form with Pagination

Im at a loss for words, as I must be missing something. Just finished ASP.NET MVC 1.0 (WROX) and Im trying to implement a view that performs a simple search then renders the results in a table. I would then like to be able to page thru the results.
So I have a search action from ListingsController, takes some values from FormCollection and filters the results accordingly:
//
//POST: /Listings/Search
// /Listings/Page/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Search(FormCollection collection,int? page)
{
var listings = listingRepository.GetListings();
//filter
if (collection["TypeOfHouse"] != null)
{
string[] typeList = collection["TypeOfHouse"].Split(',');
foreach (string type in typeList)
{
listings = from l in listings
where l.TypeOfHouse == type
select l;
}
}
//display the first page of results
int pageSize = 25;
var paginatedListings = new PriviledgeV1.Helpers.PaginatedList<Listing>(listings, 0, pageSize);
return View("Results", paginatedListings);
}
Initially the Results view will be rendered with the first 25 records for page 1. Then I have a Results action that handles the "pagination":
public ActionResult Results(int? page)
{
int pageSize = 25;
var listings = listingRepository.GetListings();
var paginatedListings = new PriviledgeV1.Helpers.PaginatedList<Listing>(listings, page ?? 0, pageSize);
return View(listings);
}
Trouble is because I no longer have the FormCollection, I cannot properly filter results. So if I tried to move from say page 1 to page 2 using /Listings/Results?page=2, the results action would fire and it would return ALL results instead of the filtered result set from the Search action.
I'm really confused as to what to do here, and as to why there are no blogs/tutorials explaining this, which normally flags me that I am missing something.
Thanks!
I suppose there are a few ways to try and accomplish this.
Pass the search parameters via query string instead of post. Understandably, this could be complicated and messy for advanced search parameters
Store the results of the POST to hidden elements. Have your paging control POST to the same action each time, instead of the separate Results action.
Store the query parameters in an object that is persisted in your session.
I'm sure we could get more creative from there, but that should give you a start. It seems like you only care about one field from the search form, TypeOfListing. You should be able to persist that via query string pretty easily, so that'd be method #1 above.
Update
Here's something simple I put together to maintain your search at the client. The technique involves three parts:
Maintain the form between page requests.
Manage the page state with a hidden element in the form.
Have JavaScript intercept your Paging links, update the page number hidden element, and resubmit the form.
Here's the code for all the various pieces. Note that I use jQuery, in case you prefer something else. I fudged the data source, just sub in real data. Also, I included PagedList and PaginationHelper. Substitute with your own if you wish.
\Controllers\HomeController.cs (Search is the relevant part):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication2.Controllers
{
[HandleError]
public class HomeController : Controller
{
List<String> _data;
public HomeController()
{
_data = new List<String>();
_data.Add("Merry");
_data.Add("Metal");
_data.Add("Median");
_data.Add("Medium");
_data.Add("Malfunction");
_data.Add("Mean");
_data.Add("Measure");
_data.Add("Melt");
_data.Add("Merit");
_data.Add("Metaphysical");
_data.Add("Mental");
_data.Add("Menial");
_data.Add("Mend");
_data.Add("Find");
}
public ActionResult Search()
{
Int32 pageNumber, pageSize = 5, total, first;
String typeOfListing;
PagedList<String> results;
if (Request.HttpMethod == "GET")
{
return View();
}
if (!Int32.TryParse(Request.Form["PageNumber"], out pageNumber)) pageNumber = 1;
typeOfListing = Request.Form["TypeOfListing"];
first = (pageNumber - 1) * pageSize;
total = (from s in _data
where s.Contains(typeOfListing)
select s).Count();
results = new PagedList<String>(
(from s in _data
where s.Contains(typeOfListing)
select s)
.Skip(first)
.Take(pageSize),
total, pageNumber, pageSize);
return View(results);
}
}
}
\Helpers\PaginationHelper.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Web.Routing;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace MvcApplication2.Helpers
{
public static class PaginationHelper
{
public static String Pager(this HtmlHelper helper, Int32 pageSize, Int32 pageNumber, Int32 total, String actionName, RouteValueDictionary values)
{
StringBuilder output = new StringBuilder();
Int32 totalPages = (Int32)Math.Ceiling((Double)total / pageSize);
if (values == null)
values = helper.ViewContext.RouteData.Values;
if (pageNumber > 1)
output.Append(CreatePageLink(helper, values, "< Previous ", pageNumber - 1, pageSize));
for (Int32 i = 1; i <= totalPages; i++)
{
if (i == pageNumber)
output.Append(i);
else
output.AppendFormat(CreatePageLink(helper, values, i.ToString(), i, pageSize));
if (i < totalPages)
output.Append(" | ");
}
if (pageNumber < totalPages)
output.Append(CreatePageLink(helper, values, " Next >", pageNumber + 1, pageSize));
return output.ToString();
}
private static String CreatePageLink(HtmlHelper helper, RouteValueDictionary values, String text, Int32 pageNumber, Int32 pageSize)
{
RouteValueDictionary routeDictionary = new RouteValueDictionary(values);
routeDictionary.Add("page", pageNumber);
routeDictionary.Add("pageSize", pageSize);
return helper.ActionLink(text, null, routeDictionary);
}
}
}
\PagedList.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplication2
{
public class PagedList<T> : List<T>
{
public Int32 TotalCount { get; protected set; }
public Int32 PageNumber { get; protected set; }
public Int32 PageSize { get; protected set; }
public PagedList(IEnumerable<T> items, Int32 total, Int32 pageNumber, Int32 pageSize)
: base(items)
{
TotalCount = total;
PageNumber = pageNumber;
PageSize = pageSize;
}
}
}
\Views\Home\Search.aspx:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<PagedList<String>>" %>
<%# Import Namespace="MvcApplication2" %>
<%# Import Namespace="MvcApplication2.Helpers" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Search
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript">
$(function() {
var results = $("#searchResults");
if (results && results.children().length > 2) {
$("#searchForm").hide();
$("#searchResults .pager>a").click(submitForm);
}
});
function submitForm() {
var m = this.href.match(/page=(\d+)/i);
if (m) {
$("#PageNumber").attr("value", m[1]);
$("#searchForm").submit();
}
return false;
}
</script>
<form id="searchForm" action="<%= Url.Action("Search") %>" method="post">
<input type="hidden" value="1" id="PageNumber" name="PageNumber" />
<fieldset>
<legend>Search</legend>
<label for="TypeOfListing">Type of Listing</label>
<%= Html.TextBox("TypeOfListing", Request.Form["TypeOfListing"]) %>
<input type="submit" id="btnSubmit" name="btnSubmit" value="Search" />
</fieldset>
</form>
<% if (Model != null)
{
%>
<div id="searchResults">
<div class="results-count">Displaying <%=this.Model.Count %> of <%=this.Model.TotalCount %> results. <%=Html.ActionLink("Start a new search", "Search") %>.</div>
<%
foreach (String result in Model)
{
%>
<div class="result"><%=result %></div>
<% }
%>
<div class="pager"><%= Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalCount, null, null) %></div>
</div>
<%
}
%>
</asp:Content>
Basically change your form to do an HTTP GET as suggested by others, then download PagedList with Nuget, and use Model Binding in your action method to the submit button and page number coming from the PagedList's HTML helper function (and set the route values using a RouteValuesDictionary). This way everything gets persisted in the querystring, which is what you want with a search page anyway most likely. MVC will do the coersion to and from your ViewModel class. I prefer to use a ViewModel class instead of a bunch of arguments because I think it is cleaner that way, but just my $.02.
I have an example that I blogged about here.
Also, I went ahead and posted the code on a different thread

Resources