http://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/20795
Popularity: 1% [?]
August 5th, 2011
admin
August 4th, 2009
admin jqGrid is an Ajax-enabled JavaScript control that provides solutions for representing and manipulating tabular data on the web. Since the grid is a client-side solution loading data dynamically through Ajax callbacks, it can be integrated with any server-side technology, including PHP, ASP, Java Servlets, JSP, ColdFusion, and Perl.
Popularity: 1% [?]
March 31st, 2009
admin Someone recently requested me to send me the sample asp.net application using MVC ExtJS and LINQ.
Here is the application with our infamous northwind database and Categories table.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Script.Serialization; using Northwind; namespace Controllers { public class CategoryController : Controller { public ActionResult Index() { ViewData["Title"] = "Category Page"; ViewData["Message"] = "Welcome to Category Page!"; return View(); } public void LoadCategory() { int id = int.Parse(Request.Form["id"]); string message = string.Empty; NorthwindDataContext db = new NorthwindDataContext(); var query = from c in db.Categorys where c.CategoryID == id select new { c.CategoryID, c.CategoryName, c.Description, c.Picture }; JavaScriptSerializer serializer = new JavaScriptSerializer(); message = "{\"results\":" + serializer.Serialize(query.ToList()) + "}"; Response.Write(message); } public void ListCategory(int limit, int start, string dir, string sort) { string message = string.Empty; NorthwindDataContext db = new NorthwindDataContext(); var query = from c in db.Categorys select new { c.CategoryID, c.CategoryName, c.Description, c.Picture }; int totalRecords = query.ToList().Count; JavaScriptSerializer serializer = new JavaScriptSerializer(); var list = query.Skip(start).Take(limit); message = "{\"total\": \"" + totalRecords + "\", \"results\":" + serializer.Serialize(list.ToList()) + "}"; Response.Write(message); } public void New() { Category _Category = new Category(); string _CategoryID = Request.Form["CategoryID"]; if(_CategoryID != null && _CategoryID != string.Empty) { _Category.CategoryID = int.Parse(_CategoryID); } string _CategoryName = Request.Form["CategoryName"]; if(_CategoryName != null && _CategoryName != string.Empty) { _Category.CategoryName = _CategoryName; } string _Description = Request.Form["Description"]; if(_Description != null && _Description != string.Empty) { _Category.Description = _Description; } string _Picture = Request.Form["Picture"]; if(_Picture != null && _Picture != string.Empty) { _Category.Picture = null; } NorthwindDataContext db = new NorthwindDataContext(); try { db.Categorys.InsertOnSubmit(_Category); db.SubmitChanges(); } catch (Exception ex) { string error = ex.Message; //log the error here } } public void Edit() { int id = int.Parse(Request.Form["id"]); NorthwindDataContext db = new NorthwindDataContext(); Category obj = db.Categorys.Single<category></category>(c => c.CategoryID == id); string _CategoryName = Request.Form["CategoryName"]; if(_CategoryName != null && _CategoryName != string.Empty) { obj.CategoryName = _CategoryName; } string _Description = Request.Form["Description"]; if(_Description != null && _Description != string.Empty) { obj.Description = _Description; } string _Picture = Request.Form["Picture"]; if(_Picture != null && _Picture != string.Empty) { obj.Picture = null; } try { db.SubmitChanges(); } catch (Exception ex) { string error = ex.Message; //log the error here } } public void Delete() { NorthwindDataContext db = new NorthwindDataContext(); string data = Request.Form["data"]; foreach (object o in data.Split(',')) { int id = int.Parse(o.ToString()); Category obj = db.Categorys.Single<category></category>(c => c.CategoryID == id); db.Categorys.DeleteOnSubmit(obj); } db.SubmitChanges(); } } }
namespace Northwind { using System.Data.Linq; using System.Data.Linq.Mapping; using System.Data; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Linq.Expressions; using System.ComponentModel; using System; [System.Data.Linq.Mapping.DatabaseAttribute(Name="Northwind")] public partial class NorthwindDataContext : System.Data.Linq.DataContext { private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource(); #region Extensibility Method Definitions partial void OnCreated(); partial void InsertCategory(Category instance); partial void UpdateCategory(Category instance); partial void DeleteCategory(Category instance); #endregion public NorthwindDataContext() : base(global::System.Configuration.ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString, mappingSource) { OnCreated(); } public NorthwindDataContext(string connection) : base(connection, mappingSource) { OnCreated(); } public NorthwindDataContext(System.Data.IDbConnection connection) : base(connection, mappingSource) { OnCreated(); } public NorthwindDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) : base(connection, mappingSource) { OnCreated(); } public NorthwindDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) : base(connection, mappingSource) { OnCreated(); } public System.Data.Linq.Table<category></category> Categorys { get { return this.GetTable<category></category>(); } } } }
<asp:content contentplaceholderid="MainContent" runat="server" id="indexContent"> <h2><!--Html.Encode(ViewData["Message"])--></h2> <script type="text/javascript"> Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif'; Ext.namespace('myNameSpace'); myNameSpace.myModule = function(){ var ds; var grid; var colModel; var myRecordObj; var myReader; var primaryKey='CategoryID'; var setupDataSource = function(){ myRecordObj = Ext.data.Record.create([ {name: 'CategoryID', type: 'int'}, {name: 'CategoryName', type: 'string'}, {name: 'Description', type: 'string'}, {name: 'Picture', type: 'string'} ]); myReader = new Ext.data.JsonReader( { root: 'results', totalProperty: 'total', id: primaryKey }, myRecordObj ); ds = new Ext.data.GroupingStore({ proxy: new Ext.data.HttpProxy({ url: '/Category/ListCategory', method: 'POST' }), reader: myReader, remoteSort: true }); };//end setupDataSource var getColumnModel = function() { if(!colModel) { colModel = new Ext.grid.ColumnModel([ { header: 'CategoryID', dataIndex: 'CategoryID', sortable: true, width: 50 }, { header: 'CategoryName', dataIndex: 'CategoryName', sortable: true, width: 50 }, { header: 'Description', dataIndex: 'Description', sortable: true, width: 50 }, { header: 'Picture', dataIndex: 'Picture', sortable: true, width: 50 } ]);//end colModel }//end if colModel return colModel; }//end getColumnModel var buildGrid = function(){ function addRecord() { var c_CategoryID = new Ext.form.NumberField ({ fieldLabel: 'CategoryID', name: 'CategoryID', width: '180', allowDecimals: true, allowNegative: false, blankText: '0', maxLength: 19 }); var c_CategoryName = new Ext.form.TextField ({ fieldLabel: 'CategoryName', name: 'CategoryName', width: '180', maskRe: /([a-zA-Z0-9\s]+)$/ }); var c_Description = new Ext.form.TextArea ({ fieldLabel: 'Description', name: 'Description', width: '180', hideLabel: false }); var c_Picture = new Ext.form.TextField ({ fieldLabel: 'Picture', name: 'Picture', width: '180', maskRe: /([a-zA-Z0-9\s]+)$/ }); var newForm = new Ext.FormPanel({ bodyStyle: 'padding: 8px', url:'/Category/New', items: [ c_CategoryID, c_CategoryName, c_Description, c_Picture ] }); var newWin = new Ext.Window({ title: 'Add a new Category', width: 390, height:500, minWidth: 300, minHeight: 250, layout: 'fit', plain:true, bodyStyle:'padding:5px;', buttonAlign:'center', items: newForm, buttons: [{ text: 'Save', handler: function() { if (newForm.form.isValid()) { newForm.form.submit({ waitMsg:'In processing', failure: function(form, action) { Ext.MessageBox.alert('Error Message', action.result.errorInfo); }, success: function(form, action) { Ext.MessageBox.alert('Success:', action.response.responseText); refreshGrid(); newWin.hide(); } }); } else { Ext.MessageBox.alert('Errors', 'Please fix the errors noted.'); } } },{ text: 'Clear', handler: function(){ newForm.getForm().reset(); } }] }); newWin.on('minimize', function(){ newWin.toggleCollapse(); }); newWin.show(); };// end addRecord function deleteRecord(btn) { if(btn=='yes') { var selectedKeys = grid.selModel.selections.keys; Ext.Ajax.request({ waitMsg: 'Saving changes...', url: '/Category/Delete', params: { data: selectedKeys }, callback: function (options, success, response) { if (success) { Ext.MessageBox.alert('OK',response.responseText); var json = Ext.util.JSON.decode(response.responseText); Ext.MessageBox.alert('OK',json.del_count + ' record(s) deleted.'); } else{ Ext.MessageBox.alert('Sorry, please try again. [Q304]',response.responseText); } }, failure:function(response,options){ Ext.MessageBox.alert('Warning','Oops...'); }, success:function(response,options){ refreshGrid(); } }); } }; function handleDelete() { var selectedKeys = grid.selModel.selections.keys; if(selectedKeys.length > 0) { Ext.MessageBox.confirm('Message','Do you really want to delete selection?', deleteRecord); } else { Ext.MessageBox.alert('Message','Please select at least one item to delete'); } }; // end handleDelete function toggleDetails(btn, pressed){ var view = grid.getView(); view.showPreview = pressed; view.refresh(); } function refreshGrid() { ds.reload(); // }; grid = new Ext.grid.GridPanel({ clicksToEdit:2, colModel: getColumnModel(), height:350, //iconCls: 'icon-grid', id: 'myGridID', loadMask: true, selModel: new Ext.grid.RowSelectionModel({singleSelect:false}), store: ds, stripeRows: true, title:'Category List', width:600, bbar: new Ext.PagingToolbar({ pageSize: myNameSpace.myModule.perPage, store: ds, displayInfo: true, displayMsg: 'Displaying topics {0} - {1} of {2}', emptyMsg: "No data to display", items:[ '-', { pressed: true, enableToggle:true, text: 'Show Preview', cls: 'x-btn-text-icon details', toggleHandler: toggleDetails }] }), tbar: [ { text: 'Add', tooltip: 'Click to Add a row', //iconCls:'add', handler: addRecord }, '-', //add a separator { text: 'Delete', tooltip: 'Click to Delete selected row(s)', //function to call when user clicks on button //iconCls:'remove', handler: handleDelete }, '-', { text: 'Refresh', tooltip: 'Click to Refresh the table', //iconCls:'refresh', handler: refreshGrid } ], view: new Ext.grid.GroupingView({ forceFit:true, groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})' }) });//end grid grid.on('rowdblclick', function(grid, rowIndex, e) { var id = ds.data.items[rowIndex].id; var u_CategoryID = new Ext.form.NumberField ({ fieldLabel: 'CategoryID', name: 'CategoryID', width: '180', allowDecimals: true, allowNegative: false, blankText: '0', maxLength: 19 }); var u_CategoryName = new Ext.form.TextField ({ fieldLabel: 'CategoryName', name: 'CategoryName', width: '180', maskRe: /([a-zA-Z0-9\s]+)$/ }); var u_Description = new Ext.form.TextArea ({ fieldLabel: 'Description', name: 'Description', width: '180', hideLabel: false }); var u_Picture = new Ext.form.TextField ({ fieldLabel: 'Picture', name: 'Picture', width: '180', maskRe: /([a-zA-Z0-9\s]+)$/ }); var updateForm = new Ext.FormPanel({ bodyStyle: 'padding: 8px', url:'/Category/Edit', reader: new Ext.data.JsonReader( { root: 'results'}, [ {name: 'CategoryID', type: 'int'}, {name: 'CategoryName', type: 'string'}, {name: 'Description', type: 'string'}, {name: 'Picture', type: 'string'} ]), items: [ u_CategoryID, u_CategoryName, u_Description, u_Picture ] }); updateForm.form.load({ url:'/Category/LoadCategory', params: { id: id }, waitMsg:'Loading' }); var window = new Ext.Window({ title: 'Edit Existing Category', width: 390, height:500, minWidth: 300, minHeight: 250, layout: 'fit', plain:true, bodyStyle:'padding:5px;', buttonAlign:'center', items: updateForm, buttons: [{ text: 'Save', handler: function() { if (updateForm.form.isValid()) { updateForm.form.submit({ params:{id : id}, waitMsg:'In processing', failure: function(form, action) { Ext.MessageBox.alert('Error Message', action.result.errorInfo); }, success: function(form, action) { Ext.MessageBox.alert('Confirm', action.response.responseText); window.hide(); ds.load({params:{start:0, limit:10}}); } }); } else{ Ext.MessageBox.alert('Errors', 'Please fix the errors noted.'); } } }, { text: 'Cancel', handler: function(){window.hide();} }] }); window.show(); }); }//end function buildGrid var renderGrid = function() { grid.render('CustomersList'); }; //end function renderGrid var loadStore = function() { ds.load({ params: { start: 0, limit: myNameSpace.myModule.perPage } }); grid.getSelectionModel().selectFirstRow(); }; return { perPage: 10, init : function(){ this.getMyGrid(); }, //end of init method getMyGrid: function() { Ext.QuickTips.init(); setupDataSource(); buildGrid(); renderGrid(); loadStore(); }, getDataSource: function() { return ds; } }//end of return }(); Ext.onReady(myNameSpace.myModule.init, myNameSpace.myModule, true); </script> </asp:content>
Northwind.Category.model.cs
Northwind.Category.Controller.cs
Northwind.Category.view.aspx
Popularity: 6% [?]
January 23rd, 2009
admin I took Jörn Zaffaerer jquery plugin PHP demo and changed to ASP.NET C#.
Autocomplete an input field to enable users quickly finding and selecting some value, leveraging searching and filtering.
By giving an autocompleted field focus or entering something into it, the plugin starts searching for matching entries and displays a list of values to choose from. By entering more characters, the user can filter down the list to better matches.
This can be used to enter previous selected values, eg. for tags, to complete an address, eg. enter a city name and get the zip code, or maybe enter email addresses from an addressbook.
Current version: 1.0.2
Compressed filesize: 7596 bytes
License: MIT/GPL
Tested in: Firefox 2, IE 6 & 7, Opera 9, Safari 3
Download
Changelog
Demos
Documentation (Plugin Options)
ASPX Page:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AutoCompleteJquery.aspx.cs" Inherits="jQueryAndAspNetDemo.AutoCompleteJquery" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>Auto complete Demo</title> <link href="styles/style1.css" rel="stylesheet" type="text/css" /> <script src="js/jquery.js" type="text/javascript"></script> <script type="text/javascript"> /* * Autocomplete - jQuery plugin 1.1pre * * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Revision: $Id: jquery.autocomplete.js 5785 2008-07-12 10:37:33Z joern.zaefferer $ * */ ; (function($) { $.fn.extend({ autocomplete: function(urlOrData, options) { var isUrl = typeof urlOrData == "string"; options = $.extend({}, $.Autocompleter.defaults, { url: isUrl ? urlOrData : null, data: isUrl ? null : urlOrData, delay: isUrl ? $.Autocompleter.defaults.delay : 10, max: options && !options.scroll ? 10 : 150 }, options); // if highlight is set to false, replace it with a do-nothing function options.highlight = options.highlight || function(value) { return value; }; // if the formatMatch option is not specified, then use formatItem for backwards compatibility options.formatMatch = options.formatMatch || options.formatItem; return this.each(function() { new $.Autocompleter(this, options); }); }, result: function(handler) { return this.bind("result", handler); }, search: function(handler) { return this.trigger("search", [handler]); }, flushCache: function() { return this.trigger("flushCache"); }, setOptions: function(options) { return this.trigger("setOptions", [options]); }, unautocomplete: function() { return this.trigger("unautocomplete"); } }); $.Autocompleter = function(input, options) { var KEY = { UP: 38, DOWN: 40, DEL: 46, TAB: 9, RETURN: 13, ESC: 27, COMMA: 188, PAGEUP: 33, PAGEDOWN: 34, BACKSPACE: 8 }; // Create $ object for input element var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass); var timeout; var previousValue = ""; var cache = $.Autocompleter.Cache(options); var hasFocus = 0; var lastKeyPressCode; var config = { mouseDownOnSelect: false }; var select = $.Autocompleter.Select(options, input, selectCurrent, config); var blockSubmit; // prevent form submit in opera when selecting with return key $.browser.opera && $(input.form).bind("submit.autocomplete", function() { if (blockSubmit) { blockSubmit = false; return false; } }); // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) { // track last key pressed lastKeyPressCode = event.keyCode; switch (event.keyCode) { case KEY.UP: event.preventDefault(); if (select.visible()) { select.prev(); } else { onChange(0, true); } break; case KEY.DOWN: event.preventDefault(); if (select.visible()) { select.next(); } else { onChange(0, true); } break; case KEY.PAGEUP: event.preventDefault(); if (select.visible()) { select.pageUp(); } else { onChange(0, true); } break; case KEY.PAGEDOWN: event.preventDefault(); if (select.visible()) { select.pageDown(); } else { onChange(0, true); } break; // matches also semicolon case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA: case KEY.TAB: case KEY.RETURN: if (selectCurrent()) { // stop default to prevent a form submit, Opera needs special handling event.preventDefault(); blockSubmit = true; return false; } break; case KEY.ESC: select.hide(); break; default: clearTimeout(timeout); timeout = setTimeout(onChange, options.delay); break; } }).focus(function() { // track whether the field has focus, we shouldn't process any // results if the field no longer has focus hasFocus++; }).blur(function() { hasFocus = 0; if (!config.mouseDownOnSelect) { hideResults(); } }).click(function() { // show select when clicking in a focused field if (hasFocus++ > 1 && !select.visible()) { onChange(0, true); } }).bind("search", function() { // TODO why not just specifying both arguments? var fn = (arguments.length > 1) ? arguments[1] : null; function findValueCallback(q, data) { var result; if (data && data.length) { for (var i = 0; i < data.length; i++) { if (data[i].result.toLowerCase() == q.toLowerCase()) { result = data[i]; break; } } } if (typeof fn == "function") fn(result); else $input.trigger("result", result && [result.data, result.value]); } $.each(trimWords($input.val()), function(i, value) { request(value, findValueCallback, findValueCallback); }); }).bind("flushCache", function() { cache.flush(); }).bind("setOptions", function() { $.extend(options, arguments[1]); // if we've updated the data, repopulate if ("data" in arguments[1]) cache.populate(); }).bind("unautocomplete", function() { select.unbind(); $input.unbind(); $(input.form).unbind(".autocomplete"); }); function selectCurrent() { var selected = select.selected(); if (!selected) return false; var v = selected.result; previousValue = v; if (options.multiple) { var words = trimWords($input.val()); if (words.length > 1) { v = words.slice(0, words.length - 1).join(options.multipleSeparator) + options.multipleSeparator + v; } v += options.multipleSeparator; } $input.val(v); hideResultsNow(); $input.trigger("result", [selected.data, selected.value]); return true; } function onChange(crap, skipPrevCheck) { if (lastKeyPressCode == KEY.DEL) { select.hide(); return; } var currentValue = $input.val(); if (!skipPrevCheck && currentValue == previousValue) return; previousValue = currentValue; currentValue = lastWord(currentValue); if (currentValue.length >= options.minChars) { $input.addClass(options.loadingClass); if (!options.matchCase) currentValue = currentValue.toLowerCase(); request(currentValue, receiveData, hideResultsNow); } else { stopLoading(); select.hide(); } }; function trimWords(value) { if (!value) { return [""]; } var words = value.split(options.multipleSeparator); var result = []; $.each(words, function(i, value) { if ($.trim(value)) result[i] = $.trim(value); }); return result; } function lastWord(value) { if (!options.multiple) return value; var words = trimWords(value); return words[words.length - 1]; } // fills in the input box w/the first match (assumed to be the best match) // q: the term entered // sValue: the first matching result function autoFill(q, sValue) { // autofill in the complete box w/the first match as long as the user hasn't entered in more data // if the last user key pressed was backspace, don't autofill if (options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE) { // fill in the value (keep the case the user has typed) $input.val($input.val() + sValue.substring(lastWord(previousValue).length)); // select the portion of the value not typed by the user (so the next character will erase) $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length); } }; function hideResults() { clearTimeout(timeout); timeout = setTimeout(hideResultsNow, 200); }; function hideResultsNow() { var wasVisible = select.visible(); select.hide(); clearTimeout(timeout); stopLoading(); if (options.mustMatch) { // call search and run callback $input.search( function(result) { // if no value found, clear the input box if (!result) { if (options.multiple) { var words = trimWords($input.val()).slice(0, -1); $input.val(words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "")); } else $input.val(""); } } ); } if (wasVisible) // position cursor at end of input field $.Autocompleter.Selection(input, input.value.length, input.value.length); }; function receiveData(q, data) { if (data && data.length && hasFocus) { stopLoading(); select.display(data, q); autoFill(q, data[0].value); select.show(); } else { hideResultsNow(); } }; function request(term, success, failure) { if (!options.matchCase) term = term.toLowerCase(); var data = cache.load(term); // recieve the cached data if (data && data.length) { success(term, data); // if an AJAX url has been supplied, try loading the data now } else if ((typeof options.url == "string") && (options.url.length > 0)) { var extraParams = { timestamp: +new Date() }; $.each(options.extraParams, function(key, param) { extraParams[key] = typeof param == "function" ? param() : param; }); $.ajax({ // try to leverage ajaxQueue plugin to abort previous requests mode: "abort", // limit abortion to this input port: "autocomplete" + input.name, dataType: options.dataType, url: options.url, data: $.extend({ q: lastWord(term), limit: options.max }, extraParams), success: function(data) { var parsed = options.parse && options.parse(data) || parse(data); cache.add(term, parsed); success(term, parsed); } }); } else { // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match select.emptyList(); failure(term); } }; function parse(data) { var parsed = []; var rows = data.split("\n"); for (var i = 0; i < rows.length; i++) { var row = $.trim(rows[i]); if (row) { row = row.split("|"); parsed[parsed.length] = { data: row, value: row[0], result: options.formatResult && options.formatResult(row, row[0]) || row[0] }; } } return parsed; }; function stopLoading() { $input.removeClass(options.loadingClass); }; }; $.Autocompleter.defaults = { inputClass: "ac_input", resultsClass: "ac_results", loadingClass: "ac_loading", minChars: 1, delay: 400, matchCase: false, matchSubset: true, matchContains: false, cacheLength: 10, max: 100, mustMatch: false, extraParams: {}, selectFirst: true, formatItem: function(row) { return row[0]; }, formatMatch: null, autoFill: false, width: 0, multiple: false, multipleSeparator: ", ", highlight: function(value, term) { return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"); }, scroll: true, scrollHeight: 180 }; $.Autocompleter.Cache = function(options) { var data = {}; var length = 0; function matchSubset(s, sub) { if (!options.matchCase) s = s.toLowerCase(); var i = s.indexOf(sub); if (options.matchContains == "word") { i = s.toLowerCase().search("\\b" + sub.toLowerCase()); } if (i == -1) return false; return i == 0 || options.matchContains; }; function add(q, value) { if (length > options.cacheLength) { flush(); } if (!data[q]) { length++; } data[q] = value; } function populate() { if (!options.data) return false; // track the matches var stMatchSets = {}, nullData = 0; // no url was specified, we need to adjust the cache length to make sure it fits the local data store if (!options.url) options.cacheLength = 1; // track all options for minChars = 0 stMatchSets[""] = []; // loop through the array and create a lookup structure for (var i = 0, ol = options.data.length; i < ol; i++) { var rawValue = options.data[i]; // if rawValue is a string, make an array otherwise just reference the array rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue; var value = options.formatMatch(rawValue, i + 1, options.data.length); if (value === false) continue; var firstChar = value.charAt(0).toLowerCase(); // if no lookup array for this character exists, look it up now if (!stMatchSets[firstChar]) stMatchSets[firstChar] = []; // if the match is a string var row = { value: value, data: rawValue, result: options.formatResult && options.formatResult(rawValue) || value }; // push the current match into the set list stMatchSets[firstChar].push(row); // keep track of minChars zero items if (nullData++ < options.max) { stMatchSets[""].push(row); } }; // add the data items to the cache $.each(stMatchSets, function(i, value) { // increase the cache size options.cacheLength++; // add to the cache add(i, value); }); } // populate any existing data setTimeout(populate, 25); function flush() { data = {}; length = 0; } return { flush: flush, add: add, populate: populate, load: function(q) { if (!options.cacheLength || !length) return null; /* * if dealing w/local data and matchContains than we must make sure * to loop through all the data collections looking for matches */ if (!options.url && options.matchContains) { // track all matches var csub = []; // loop through all the data grids for matches for (var k in data) { // don't search through the stMatchSets[""] (minChars: 0) cache // this prevents duplicates if (k.length > 0) { var c = data[k]; $.each(c, function(i, x) { // if we've got a match, add it to the array if (matchSubset(x.value, q)) { csub.push(x); } }); } } return csub; } else // if the exact item exists, use it if (data[q]) { return data[q]; } else if (options.matchSubset) { for (var i = q.length - 1; i >= options.minChars; i--) { var c = data[q.substr(0, i)]; if (c) { var csub = []; $.each(c, function(i, x) { if (matchSubset(x.value, q)) { csub[csub.length] = x; } }); return csub; } } } return null; } }; }; $.Autocompleter.Select = function(options, input, select, config) { var CLASSES = { ACTIVE: "ac_over" }; var listItems, active = -1, data, term = "", needsInit = true, element, list; // Create results function init() { if (!needsInit) return; element = $("<div/>") .hide() .addClass(options.resultsClass) .css("position", "absolute") .appendTo(document.body); list = $("<ul/>").appendTo(element).mouseover(function(event) { if (target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') { active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event)); $(target(event)).addClass(CLASSES.ACTIVE); } }).click(function(event) { $(target(event)).addClass(CLASSES.ACTIVE); select(); // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus input.focus(); return false; }).mousedown(function() { config.mouseDownOnSelect = true; }).mouseup(function() { config.mouseDownOnSelect = false; }); if (options.width > 0) element.css("width", options.width); needsInit = false; } function target(event) { var element = event.target; while (element && element.tagName != "LI") element = element.parentNode; // more fun with IE, sometimes event.target is empty, just ignore it then if (!element) return []; return element; } function moveSelect(step) { listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE); movePosition(step); var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE); if (options.scroll) { var offset = 0; listItems.slice(0, active).each(function() { offset += this.offsetHeight; }); if ((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) { list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight()); } else if (offset < list.scrollTop()) { list.scrollTop(offset); } } }; function movePosition(step) { active += step; if (active < 0) { active = listItems.size() - 1; } else if (active >= listItems.size()) { active = 0; } } function limitNumberOfItems(available) { return options.max && options.max < available ? options.max : available; } function fillList() { list.empty(); var max = limitNumberOfItems(data.length); for (var i = 0; i < max; i++) { if (!data[i]) continue; var formatted = options.formatItem(data[i].data, i + 1, max, data[i].value, term); if (formatted === false) continue; var li = $("<li/>").html(options.highlight(formatted, term)).addClass(i % 2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0]; $.data(li, "ac_data", data[i]); } listItems = list.find("li"); if (options.selectFirst) { listItems.slice(0, 1).addClass(CLASSES.ACTIVE); active = 0; } // apply bgiframe if available if ($.fn.bgiframe) list.bgiframe(); } return { display: function(d, q) { init(); data = d; term = q; fillList(); }, next: function() { moveSelect(1); }, prev: function() { moveSelect(-1); }, pageUp: function() { if (active != 0 && active - 8 < 0) { moveSelect(-active); } else { moveSelect(-8); } }, pageDown: function() { if (active != listItems.size() - 1 && active + 8 > listItems.size()) { moveSelect(listItems.size() - 1 - active); } else { moveSelect(8); } }, hide: function() { element && element.hide(); listItems && listItems.removeClass(CLASSES.ACTIVE); active = -1; }, visible: function() { return element && element.is(":visible"); }, current: function() { return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]); }, show: function() { var offset = $(input).offset(); element.css({ width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(), top: offset.top + input.offsetHeight, left: offset.left }).show(); if (options.scroll) { list.scrollTop(0); list.css({ maxHeight: options.scrollHeight, overflow: 'auto' }); if ($.browser.msie && typeof document.body.style.maxHeight === "undefined") { var listHeight = 0; listItems.each(function() { listHeight += this.offsetHeight; }); var scrollbarsVisible = listHeight > options.scrollHeight; list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight); if (!scrollbarsVisible) { // IE doesn't recalculate width when scrollbar disappears listItems.width(list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right"))); } } } }, selected: function() { var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE); return selected && selected.length && $.data(selected[0], "ac_data"); }, emptyList: function() { list && list.empty(); }, unbind: function() { element && element.remove(); } }; }; $.Autocompleter.Selection = function(field, start, end) { if (field.createTextRange) { var selRange = field.createTextRange(); selRange.collapse(true); selRange.moveStart("character", start); selRange.moveEnd("character", end); selRange.select(); } else if (field.setSelectionRange) { field.setSelectionRange(start, end); } else { if (field.selectionStart) { field.selectionStart = start; field.selectionEnd = end; } } field.focus(); }; })(jQuery); </script> <style type="text/css"> .ac_input { width: 200px; } .ac_results { padding: 0px; border: 1px solid WindowFrame; background-color: Window; overflow: hidden; } .ac_results ul { width: 100%; list-style-position: outside; list-style: none; padding: 0; margin: 0; } .ac_results iframe { display:none;/*sorry for IE5*/ display/**/:block;/*sorry for IE5*/ position:absolute; top:0; left:0; z-index:-1; filter:mask(); width:3000px; height:3000px; } .ac_results li { margin: 0px; padding: 2px 5px; cursor: pointer; display: block; width: 100%; font: menu; font-size: 12px; overflow: hidden; } .ac_loading { background : url('img/indicator.gif') right center no-repeat; } .ac_odd { background-color: #eee; } .ac_over { background-color: #0A246A; color: white; } </style> </head> <body> <form id="form1" runat="server"> <div> <p><asp:TextBox ID="txtAutoComplete" runat="server"></asp:TextBox> (autocomplete box)</p> </div> <script type="text/javascript"> $(document).ready(function() { $("#txtAutoComplete").autocomplete("AutoComplete.ashx", { width: 260, selectFirst: false, scroll: false }); }); </script> </form> </body> </html>
HttpHandler:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Services; using System.IO; using System.Text.RegularExpressions; namespace jQueryAndAspNetDemo { /// <summary> /// Summary description for $codebehindclassname$ /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class AutoComplete : IHttpHandler { public void ProcessRequest(HttpContext context) { string strJSON = string.Empty; StreamReader reader = null; List<String> itemList = new List<String>(); if (context.Request.QueryString["q"] != null) { string q = context.Request.QueryString["q"]; string limit = context.Request.QueryString["limit"]; //For example purpose , i'm reading from Text file. try { string strFilePath = "~/TestJSON.txt"; reader = new StreamReader(context.Server.MapPath(strFilePath)); string strMatchText = null; while ((strMatchText = reader.ReadLine()) != null) { if (Regex.IsMatch(strMatchText, q, RegexOptions.IgnoreCase)) { itemList.Add(strMatchText); } } strJSON = String.Join(System.Environment.NewLine, itemList.Take(int.Parse(limit)).ToArray()); } catch { } finally { if (reader != null) { reader.Close(); } } } context.Response.ContentType = "text/plain"; context.Response.Write(strJSON); } public bool IsReusable { get { return false; } } } }
Popularity: 40% [?]
January 16th, 2009
admin I have been using ExtJS Javascript framework from long time and it is Intuitive, very very extensive, great DOM manipulation, solid effects. The fastest to get things done when puzzling out on the commandline. As in one of my earlier post I talked about Coolite. Coolite Toolkit is an Ext official suite of ASP.NET Web Controls built on the Ext JavaScript Framework. I would really recommend to use the above instead of using ExtJS seperately with ASP.NET Framework. But, if for any reason here is the sample. Step 1: Create aspx page Simple ASPX page which enables to search by last name or first name
<%@ Page Language="C#" MasterPageFile="~/MasterPages/MasterPage.master" AutoEventWireup="true" CodeFile="UserSearch.aspx.cs" Inherits="Webforms_UserSearch" Title="Search User" %><%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %> <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> <asp:ScriptManager runat="server" ID="scriptManagerId"> <Scripts> <asp:ScriptReference Path="~/Scripts/UserSearch.js" /> </Scripts> <Services> <asp:ServiceReference Path="~/WebServices/ExtJSWebService.asmx" /> </Services> </asp:ScriptManager> <div class="x-box-blue" style="width:500px;"> <div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div> <div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc" id="boxContent"> <asp:Label ID="lblForm" runat="Server" CssClass="FormLabel" Text="User Search"></asp:Label> <div id="thePanel" class="FormPanel"> <div id="theData"> <table align="center" > <tr> <td colspan="12" height="4px"> </td> </tr> <tr> <td align="right"> <asp:Label ID="lblLastName" runat="server" AssociatedControlID="txtLastName" CssClass="Label" >Last Name</asp:Label> </td> <td width="4px"> </td> <td> <asp:TextBox ID="txtLastName" runat="server" CssClass="TextBox" MaxLength="50" ></asp:TextBox> </td> <td width="14px"> </td> <td align="right"> <asp:Label ID="lblFirstName" runat="server" AssociatedControlID="txtFirstName" CssClass="Label" >First Name</asp:Label> </td> <td width="4px"> </td> <td> <asp:TextBox ID="txtFirstName" runat="server" CssClass="TextBox" MaxLength="50"></asp:TextBox> </td> </tr> <tr> <td colspan="12" height="4px"> </td> </tr> </table> </div> </div> </div></div></div> <div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div> </div> <div style="width:500px;"> <table align="center"> <tr> <td height="5px" colspan="12"> </td> </tr> <tr> <td colSpan="3" height="10"> <asp:label id="lblWarn" runat="server" CssClass="Warning" Visible="False"></asp:label> </td> </tr> </table> <table align="Center"> <tr> <td> <asp:Button ID="btnSearch" runat="Server" Text="Search" OnClientClick="return BindGrid();"/> </td> <td width="10px"> </td> <td> <asp:Button ID="btnAdd" runat="Server" Text="Add" OnClick="btnAdd_Click" CausesValidation="false"/> </td> </tr> <tr> <td height="5px" colspan="12"> </td> </tr> </table> </div> <div id="grid-win" class="x-hidden"> <div class="x-window-header">User Search</div> <div id="grid-user"> </div> </div> </asp:Content>
Step 2 : Creating Web Service ( If you look at aspx page, i called it ExtJSWebService.asmx
using System.Text; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Principal; using System.Data.Common; using System.IO; using System.Configuration; using System.Collections.Generic; using System.Collections.Specialized; using System.Collections; using System.Data; /// <summary> /// Summary description for WebService /// </summary> [System.Web.Services.WebService(Namespace = "MR")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class ExtJSWebService : System.Web.Services.WebService { string strResponse = string.Empty; public ExtJSWebService() { //Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true, XmlSerializeString = false)] public JSONCollection<MembershipUserCollection> GetUserCollectionJSON(int start, int limit, string i_Params, string sort, string dir) { UserDataSource objDS = new UserDataSource(); MembershipUserCollection objCollection = objDS.GetUserCollection(i_Params, start, limit, sort + " " + dir); JSONCollection<MembershipUserCollection> objJSON = new JSONCollection<MembershipUserCollection>(); objJSON.List = objCollection; objJSON.TotalCount = objDS.GetUsersCount(i_Params); return objJSON; } } public class JSONCollection<T> { private T m_value; private int intCount; public T List { get { return m_value; } set { m_value = value; } } public int TotalCount { get { return this.intCount; } set { this.intCount = value; } } } public class MembershipUserCollection : System.Collections.ObjectModel.Collection<MembershipUser> { } [Serializable] public class MembershipUser { public MembershipUser(); public string ErrorMessage { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }
Step 3: Javascript by name UserSearch.js (as reference in aspx)
var usWin; function BindGrid(){ Ext.lib.Ajax.defaultPostHeader = 'application/json'; var gridDiv = $get('grid-user'); gridDiv.innerHTML = ''; var fieldMap = new Ext.data.Record.create( [ {name : 'LastName'}, {name : 'FirstName'} ]); var usDataStore = new Ext.data.Store( { //Note that I have renamed the web service proxy class proxy: new Ext.ux.AspWebServiceProxy( { webServiceProxy: ExtJSWebService, webServiceProxyMethod: ExtJSWebService.GetUserCollectionJSON }), reader: new Ext.data.JsonReader({ root: 'List', totalProperty: 'TotalCount', id: 'LastName' },fieldMap), remoteSort: true }); usDataStore.setDefaultSort('LastName', 'desc'); // 5. Now you can bind this ExtJS based “Store” to any ExtJS based “GridPanel” or Select list or can use the store as a temporary data place holder for further manipulation later on. var usColModel = new Ext.grid.ColumnModel([ {header: "Last Name", width: 105, sortable: true, dataIndex: 'LastName'}, {header: "First Name", width: 105, sortable: true, dataIndex: 'FirstName'}, ]); var usGrid = new Ext.grid.GridPanel({ el:'grid-user', ds: usDataStore, cm: usColModel, sm: new Ext.grid.RowSelectionModel({ singleSelect: true }), stripeRows: true, bbar: new Ext.PagingToolbar({ pageSize: 10, store: usDataStore, displayInfo: true, displayMsg: 'Displaying Users {0} - {1} of {2}', emptyMsg: "No topics to display" }), viewConfig: { emptyText: '<<span class="tag">div</span><span class="attr"> style=</span><span class="attrv">"color:Red;"</span><span class="attr"> align=</span><span class="attrv">"center"</span>>No Users found...</<span class="tag">div</span>>' }, autoHeight:true, plugins:[new Ext.ux.grid.Search({ mode:'local' ,iconCls:false ,dateFormat:'m/d/Y' })] }); usGrid.render(); usGrid.on('rowclick', function (grid, rowIndex, e){ var record = grid.getStore().getAt(rowIndex); // Get the Record var userID = record.data['LastName']; window.location='ManageUser.aspx?Mode=Update&LastName='+LastName; }); var paramXML = PrepareParamXML(); usDataStore.on('beforeload', function() { usDataStore.baseParams = { i_Params: paramXML }; }); usDataStore.load({params:{start:0, limit:10}}); usDataStore.on('loadexception', function(a,conn,resp) { if (resp.status == '304') { //Ext.Msg.alert('Content has not changed'); } else if (resp.status == '401') { //Ext.Msg.alert('Authentication required - You need to Login'); } }); // create the window on the first click and reuse on subsequent clicks if(!usWin){ usWin = new Ext.Window({ el:'grid-win', layout:'fit', width:600, modal:true, autoHeight:true, closeAction:'hide', plain: true, items: [usGrid], buttons: [{ text: 'Close', handler: function(){ usWin.hide(); var button = Ext.get('ctl00_ContentPlaceHolder1_btnSearch'); button.dom.focus(); var txt = Ext.get('ctl00_ContentPlaceHolder1_txtLastName'); txt.dom.focus(); } }] }); } usWin.show(); return false; } Ext.namespace('Ext.ux'); Ext.ux.AspWebServiceProxy = function(conn) { Ext.ux.AspWebServiceProxy.superclass.constructor.call(this); Ext.apply(this, conn); }; Ext.extend(Ext.ux.AspWebServiceProxy, Ext.data.DataProxy, { load : function (params, reader, callback, scope, arg) { var userContext = { callback: callback, reader: reader, arg: arg, scope: scope }; var proxyWrapper = this; //debugger; //Handles the response we get back from the web service call var webServiceCallback = function(response, context, methodName) { proxyWrapper.loadResponse(response, userContext, methodName); } var serviceParams = []; //Convert the params into an array of values so that they can be used in the call (note assumes that the properties on the object are in the correct order) for (var property in params) { serviceParams.push(params[property]); } //Add the webservice callback handlers serviceParams.push(webServiceCallback); serviceParams.push(this.handleErrorResponse); //Make the actual ASP.Net web service call this.webServiceProxyMethod.apply(this.webServiceProxy, serviceParams); }, handleErrorResponse : function(response, userContext, methodName) { window.location.reload(); // Ext.MessageBox.show({ // title: 'Error', // msg: response.get_message(), // buttons: Ext.MessageBox.OK, // icon: Ext.MessageBox.ERROR // }); //alert("Error while calling method: " + methodName + "n" + response.get_message()); }, loadResponse : function (response, userContext, methodName) { var result = userContext.reader.readRecords(response); userContext.callback.call(userContext.scope, result, userContext.arg, true); } });
I’m assuming you have master page and it has reference to javascript
<script type="text/javascript" src="../Scripts/ext-2.0/adapter/ext/ext-base.js"></script> <!-- ENDLIBS --> <script type="text/javascript" src="../Scripts/ext-2.0/ext-all.js"></script> <script type="text/javascript" src="../Scripts/Ext.ux.AspWebServiceProxy.js"></script>
Popularity: 22% [?]
January 8th, 2009
admin
This plugin allows users to easily upload multiple files without refreshing the page.
Ajax file upload plugin allows users to easily upload multiple files without refreshing the page. In addition, you can use any element to show file selection window.
View an usage examples with various options. This is a PHP version,
Latest version – 0.6 (8 December 2008) Fixed bug in the “disable” method. Full (7KB) Minified (3KB)
Plugin requires jQuery 1.2 or above.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Demo Page</title> <script type="text/javascript" src="Scripts/jquery-1.2.6.min.js"></script> <script type="text/javascript" src="Scripts/jquery.ajax_upload.0.6.min.js"></script> <script type="text/javascript">/*<![CDATA[*/ $(document).ready(function(){ var button = $('#button1'), interval; $.ajax_upload(button,{ action: 'FileHandler.ashx', name: 'myfile', onSubmit : function(file, ext){ // change button text, when user selects file button.text('Uploading'); // If you want to allow uploading only 1 file at time, // you can disable upload button this.disable(); // Uploding -> Uploading. -> Uploading... interval = window.setInterval(function(){ var text = button.text(); if (button.text().length < 13){ button.text(button.text() + '.'); } else { button.text('Uploading'); } }, 200); }, onComplete: function(file, response){ button.text('Upload'); // Although plugins emulates hover effect automatically, // it doens't work when button is disabled button.removeClass('hover'); window.clearInterval(interval); // enable upload button this.enable(); // add file to the list $('<li></li>').appendTo('#example1 .files').text(file); } }); });/*]]>*/</script> </head> <body> <form id="form1" runat="server"> <ul> <li id="example1" class="example"> <p>You can style button as you want</p> <div class="wrapper"> <div id="button1" class="button">Upload</div> </div> <p>Uploaded files:</p> <ol class="files"></ol> </li> </ul> </form> </body> </html>
If you look at javascript, I’m posting to HttpHandler called “FileHandler.ashx”. Here is the code
using System; using System.Web; using System.IO; public class FileHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { string strResponse = "error"; try { string strFileName = Path.GetFileName(context.Request.Files[0].FileName); string strExtension = Path.GetExtension(context.Request.Files[0].FileName).ToLower(); string strSaveLocation = context.Server.MapPath("Upload") + "\\" + strFileName; context.Request.Files[0].SaveAs(strSaveLocation); strResponse = "success"; } catch { } context.Response.ContentType = "text/plain"; context.Response.Write(strResponse); } public bool IsReusable { get { return false; } } }
Popularity: 100% [?]
January 5th, 2009
admin
This looked interesting so I thought I would share it.
Please let me know what you think…..
From the CodePlex Description.
The Ajax Data Controls is a DotNetSlackers project. Developed on top of Asp.net Ajax Extension, the main goal of this project is to provide rich set of data controls for Client Centric Development Model. Since the data controls of Asp.net like GridView, DataList, Repeater etc does not have any Client Side Object Model thus it is not possible to work with these controls with Web Service / Page Methods call. The included controls exposes same API in the client side as the Asp.net version with few more enhancements. Currently the project contains the following controls:
http://www.codeplex.com/AjaxDataControls
Popularity: 4% [?]
January 5th, 2009
admin If you reference an ASP.NET page that contains a scriptmanager in your js file like below you get intellisense for the entire Microsoft AJAX Library plus any additional scripts ref’d by the scriptmanager. The easiest way to get the /// <reference/> entry in your js file is to drag n drop your .aspx page from solution explorer into the contents of your js file. VS magically adds the refJ
Since I tend to use stand-alone .js files I can just add this.
/// <reference name="MicrosoftAjax.debug.js" />
to my consuming page and intellisense is wired to my JavaScript code.
Popularity: 3% [?]
December 23rd, 2008
admin Rob Bagby is in the midst of a blog series on REST in WCF and been building a series of screencasts on the same subject (in conjunction with Ron Jacobs).
Since it’s such an interesting topic, especially to AJAX developers I thought I’d share them here.
Blog Series:
Screencast Series:
Popularity: 2% [?]
December 16th, 2008
admin With Microsoft’s .Net development platform increasing in both popularity and features, we’re receiving more inquiries than ever as to how clients can leverage the Ext framework within .Net web applications. While Ext, being a client-side framework, has always worked with ASP.Net applications, the team at Coolite has taken Ext & .Net integration a step further.
Coolite, the same team that brought you the very cool DateJS date parsing library, have really embraced the Ext framework creating a suite of ASP.Net controls name Coolite Studio that are based on Ext and integrate with Visual Studio 2008:
“The suite of web controls were built with a focus on bringing full Visual Studio Design-Time support to the Ext JavaScript Framework. A marriage of server-side and client-side frameworks.”
The suite of controls will include the following:
Coolite has setup a community forum to help get developers introduced to Coolite Studio and plans to expand their support options in the future.
Coolite Studio is immediately available for download and supports both .Net 2.0 and 3.5.
Popularity: 3% [?]