Passing Anonymous Types with Dynamic Lists October 1, 2013
Posted by codinglifestyle in C#, CodeProject, Javascript.Tags: anonymous types, dynamic, passing arguments
1 comment so far
Recently I was rewriting a function with a large method signature which took several arrays as parameters. As you might guess, the index across these arrays was assumed to be the same which is error-prone. I thought we should really encapsulate all this information in to a class or struct and pass in a single list instead. Then I stopped myself as there was no use for this class beyond this one-time call to another function.
Then I thought, I know, I could use an anonymous type instead.
var datum = new { a = myData.a, b = myData.b, /* c, d, ..., */ z = myData.z };
This seems like a reasonable approach and exactly what throw-away anonymous types are for. Then I tried to add this to a list. Hmm, with a little creativity I was able to overcome this… except it only worked within the scope of the same function. Well, I could have passed a list of objects, but what would I cast them to?
I really thought I’d have to cave in and just create the new class but then there was one option I hadn’t considered: dynamic. Like JavaScript, this frees you from the restriction of static typing which was inhibiting a simple notion to pass a list of anonymous types to another function. Now our list definition looks like this:
var data = new List<dynamic>();
Now this means I could really add in anything and its evaluation will be resolved at runtime. So we’re finally free to use our anonymous class however we want. We could even code access to properties which we aren’t supplying and code will compile (however you’ll get a nasty surprise at runtime).
protected void Bob() { List<dynamic> data = new List<dynamic>(); // //Assume lots of processing to build up all these arguments // data.Add(new { a = 1, b = "test" }); Fred(data); } private void Fred(List<dynamic> data) { //Fred processing logic foreach (var datum in data) { Trace.WriteLine(String.Format("{0}: {1}", datum.a, datum.b)); } }
The more evolved my client coding becomes the more restraining statically typed languages can feel. With the dynamic keyword C# is one step ahead of me allowing a future of amazing code determined by an unlimited number of factors at runtime.
ScriptArguments: An easy way to programmatically pass arguments to script from codebehind January 13, 2012
Posted by codinglifestyle in AJAX, ASP.NET, C#, CodeProject, Javascript.Tags: ajax, arguements, codebehind, function signature, Javascript, programmatic
1 comment so far
During my on-going adventures AJAXifying a crusty old business app I have been using a methodology by which most client events are setup in codebehind. The reason for this is I have easy access to my client ids, variables, and resources in codebehind. By constructing the script function calls at this stage, I can avoid messy and fragile in-line code. What I am endeavouring to do is remove all script from the markup itself. So instead of having MyPage.aspx with script mixed with markup I have MyPage.js and all functions here. Separate js files avoid fragile in-line code which only fails at runtime, can’t be refactored, and doesn’t play as nice with the debugger. Besides, separation of markup and script is good!
The downside to setting up all this script in the codebehind is it didn’t take long for the number of arguments to grow and become unruly. My script function signature looked like this:
function fnAddressChange(ddId, labelId, checkId, sameAsId, hidSelectId, hidSameAsId, onSelectEvent)
And in the codebehind I had this:
string selectArgs = string.Format("'{0}', '{1}', '{2}', '{3}', '{4}', '{5}'", _DropDownAddress.ClientID, _LabelAddress.ClientID, _RowSameAs.ChildClientID, (SameAs && _SameAsAddress != null) ? _SameAsAddress.LabelControl.ClientID : "-1", _HiddenSelectedID.ClientID, _HiddenSameAs.ClientID); string selectScript = string.Format("fnAddressSelect({0}); ", selectArgs); string changeScript = string.Format("fnAddressChange({0}, '{1}'); ", selectArgs, OnClientSelect);
We can see selectArgs is getting out of control. Not only is it getting ridiculous to add more to it, the function signature in script is getting huge and the ordering is easier to mess up. So I came up with this solution:
ScriptArguments args = new ScriptArguments (); args.Add("ddId", _DropDownAddress.ClientID); args.Add("labelId", _LabelAddress.ClientID); args.Add("checkId", _RowSameAs.ChildClientID); args.Add("sameAsId", (SameAs && _SameAsAddress != null) ? _SameAsAddress.LabelControl.ClientID : "-1"); args.Add("hidSelectId", _HiddenSelectedID.ClientID); args.Add("hidSameAsId", _HiddenSameAs.ClientID);
Not only is the codebehind cleaner but I don’t have to worry about string.Format or the order in which I add arguments in. The resulting script generated is:
args.ToString() "{ ddId : 'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__DropDownAddress', labelId : 'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__LabelAddress', checkId : 'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__RowSameAs_FormField_CheckBox', sameAsId : '-1', hidSelectId : 'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__HiddenSelectedID', hidSameAsId : 'ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__HiddenSameAs' }"
This is a javascript Object with a property per key set to the corresponding value. So in script I only need to take in one argument, the argument object. I can then access every piece of information inserted in to ScriptArguments via the correct key:
function fnAddressIsReadOnly(args) { alert(args.ddId); alert(args.labelId); }
Will alert me with “ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__DropDownAddress” and “ctl00__ContentMain__ControlOrderSoldTo__AddressSoldTo__LabelAddress”.
The great thing is how simple this was to implement:
public class ScriptArguments : Dictionary<string, string> { public override string ToString() { StringBuilder script = new StringBuilder("{ "); this.Keys.ToList().ForEach(key => script.AppendFormat("{0} : '{1}', ", key, this[key])); script.Remove(script.Length - 2, 2); script.Append(" }"); return script.ToString(); } }
This simple class solves a simple problem. I hope you find it useful.
Pass a Name Value Pair Collection to JavaScript August 8, 2011
Posted by codinglifestyle in ASP.NET, CodeProject, Javascript.Tags: ASP.NET, Javascript, jQuery
1 comment so far
In my crusade against in-line code I am endevouring to clean up the script hell in my current project. My javascript is littered these types of statements:
var hid = <%=hidSelectedItems.ClientId%>; var msg = <%=GetResourceString('lblTooManyItems')%>;
Part of the cleanup is to minimize script on the page and instead use a separate .js file. This encourages me to write static functions which take in ids and resources as parameters, allows for easier script debugging, and removes all in-line code making maintenance or future refactoring easier.
While moving code to a proper .js file is nice there are times we might miss the in-line goodness. Never fear, we can build a JavaScript object containing properties for anything we might need with ease. This equates to passing a name/value pair collection to the JavaScript from the code behind. Take a look at this example:
ScriptOptions options = new ScriptOptions(); options.Add("ok", GetResourceString("btnOK")); options.Add("oksave", GetResourceString("btnOkSave")); options.Add("cancel", GetResourceString("btnCancel")); options.Add("viewTitle", GetResourceString("lblAddressEditorView")); options.Add("editTitle", GetResourceString("lblAddressEditorEdit")); options.Add("createTitle", GetResourceString("lblAddressEditorCreate")); options.RegisterOptionsScript(this, "_OptionsAddressEditorResources");
Here we’re using the ScriptOptions class to create an object called _OptionsAddressEditorResources we can access in our script. Now let’s see these options in use:
function fnAddressEditDialog(address, args) { //Define the buttons and events var buttonList = {}; buttonList[_OptionsAddressEditorResources.ok] = function() { return fnAddressEditOnOk(jQuery(this), args); }; buttonList[_OptionsAddressEditorResources.oksave] = function() { return fnAddressEditOnOkSave(jQuery(this), args); }; buttonList[_OptionsAddressEditorResources.cancel] = function() { jQuery(this).dialog("close"); }; //Display the dialog jQuery("#addressEditorDialog").dialog({ title: _OptionsAddressEditorResources.editTitle, modal: true, width: 535, resizable: false, buttons: buttonList }); }
Above we see the jQuery dialog using the resources contained within the _OptionsAddressEditorResources object.
So this seems simple but pretty powerful. Below is the ScriptOptions class which simply extends a Dictionary and writes out the script creating a named global object. Good luck cleaning up your script hell. Hopefully this will help.
/// <summary> /// Class for generating javascript option arrays /// </summary> public class ScriptOptions : Dictionary<string, string> { /// <summary> /// Adds the control id to the options script /// </summary> /// <param name="control">The control.</param> public void AddControlId(WebControl control) { this.Add(control.ID, control.ClientID); } /// <summary> /// Registers all the key/values as an options script for access in the client. /// </summary> /// <param name="page">The page</param> /// <param name="optionsName">Name of the options object</param> public void RegisterOptionsScript(Page page, string optionsName) { if (!page.ClientScript.IsStartupScriptRegistered(page.GetType(), optionsName)) { StringBuilder script = new StringBuilder(string.Format("var {0} = new Object();", optionsName)); this.Keys.ToList().ForEach(key => script.Append(string.Format("{0}.{1}='{2}';", optionsName, key, this[key]))); page.ClientScript.RegisterStartupScript(page.GetType(), optionsName, script.ToString(), true); } } }
OnClientClick Breaks Validation August 20, 2009
Posted by codinglifestyle in ASP.NET, Javascript.1 comment so far
It’s a horrible sinking feeling when you make a sizable change and everything goes tits up. I was updating an ASP.NET form the other day which had a lot of HTML controls on it. I decided to update these to ASP.NET controls and replaced a number of buttons. While doing this I cleaned up the onclick code, which I placed in OnClientClick. Unwittingly I managed to break validation for the entire page, as just about every button used this attribute. I won’t bore you with the details, but suffice it to say I had a few red herrings and couldn’t understand why my page’s validators suddenly stopped working. I spent all night fretting about it, but this morning the first thing I did was drop a new button on the page, load it up, and click it. Presto, validation worked for that button but not the other buttons on the page. What’s going on?
<asp:Button runat=”server” ID=”Save” OnClientClick=”return confirm(‘Are you sure?’);” />
It becomes crystal clear when you view the source of the page. We will see something like this:
onclick=”return confirm(‘Are you sure?’);WebForm_DoPostBackWithOptions(…)”
It is now clear that we are returning before the validator’s script has a chance to run. I will pause now for an, “Ohhhhhhh…. <slap to head>”.
Typically, we want to stop execution if our called function returns false but continue if it returns true. Solving this problem requires just a small change to our script. Take a look below:
onclick=”if (!confirm(‘Are you sure?’)) return false; WebForm_DoPostBackWithOptions(…)”
Now we will only return false if our script returns false. If our script returns true, the browser will continue to call WebForm_DoPostBackWithOptions(…) which will execute our validators.
ref: http://vaultofthoughts.net/OnClientClickBreaksValidation.aspx
Currency TextBox with Javascript April 24, 2009
Posted by codinglifestyle in Javascript.Tags: currency, Javascript, regular expression, textbox, validator
1 comment so far
This took me a long time so here it is for prosperity. I started by looking at Ajax’s masked edit field in order to enforce a simply currency field. This was a waste of time and not up for the job. I accomplished it with javascript instead. Very simple, no symbols, just #####.## with the cents being optional.
Here is the script:
/*
** Returns the caret (cursor) position of the specified text field.
** Return value range is 0-oField.length.
*/
function doGetCaretPosition(oField) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
oField.focus();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange();
// Move selection start to 0 position
oSel.moveStart(‘character’, -oField.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (oField.selectionStart || oField.selectionStart == ‘0’)
iCaretPos = oField.selectionStart;
// Return results
return (iCaretPos);
}
function fnCurrencyOnly(o) {
var sValue = o.value;
var sKey = String.fromCharCode(window.event.keyCode);
var range = document.selection.createRange();
var pos = doGetCaretPosition(o);
if (range.text == sValue) {
sValue = sKey;
} else {
sValue = sValue.substr(0, pos) + sKey + sValue.substr(pos);
}
var re = new RegExp(“^\\d+(?:(\\.|\\,)\\d{0,2})?$”);
if (!sValue.match(re))
window.event.returnValue = false;
}
<div>
<input type=”text” onkeypress=”fnCurrencyOnly(this);” />
</div>
I’m sure sure who the original author is, but I found the script for doGetCaretPosition() here: http://blog.vishalon.net/index.php/javascript-getting-and-setting-caret-position-in-textarea/
Enjoy!
Numeric input only for a HtmlInputField January 12, 2006
Posted by codinglifestyle in ASP.NET, Javascript.Tags: Javascript, regular expression, validator
1 comment so far
Sometimes a validator control is overkill, especially when you are dynamically creating all your web controls and just want a simple restriction. Below is a little javascript to require numeric input only:
HtmlInputField myField = new HtmlInputField();
myField.Attributes.Add(“onkeyup”, “this.value=this.value.replace(/[^\\d]*/gi,\”\”);”);
Exposing C# controls as Active-X and the effects on developing with the download cache January 5, 2006
Posted by codinglifestyle in C#, Javascript, Winform.Tags: active-x, control, GAC, Javascript, Winform
add a comment
A C# assembly can be easily exposed as an Active-X control using the object tag like so:
<OBJECT id=”Bob” classid=”url to assembly#full name of control></OBJECT>
So for example my assembly is located in a virtual directory on server VM2003S2:88 called MyObject. MyObject has a namespace of Chris.ActiveX.Controls and the class is MyControl. My object tag would be: http://vm2003s2:88/myobject.dll#chris.activex.controls.mycontrol
This complete I can now use javascript to talk to “Bob” via MyControl’s public methods. This is all well and good however you may experience frustration in seeing your updates during development.
The assembly is automatically pulled down to the download cache which is located in c:\windows\assembly\downloads on Win2003. Unfortunately, its not smart enough to read version strings and realize a newer copy is available on the server. Therefore you must clear this cache using:
gacutil /cdl
But that’s not all! A copy is also made in your temporary internet files. You won’t be able to simply delete it using del from the post-build event as Window’s treats the directory as special. So either write a small program utilizing the API to delete your assembly from the cache or use one of the miriad of privacy utilities to clean this for you. I found CleanUp! which can be quietly executed from the command line and added to my post build event. The result is the assembly is pulled every time (on the development machine) so you see your changes with each build.
Here is a good example explaining Embedded Windows User Controls into Internet Explorer:
http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=187