Is there a bug with input type="image" in Internet Explorer - asp.net

I'm using IE9 (rtm) at the moment and I am wondering if this is an issue of my own doing or a bug in Internet Explorer 9.
I'm using ASP.NET MVC the form controller is defined as:
[HttpPost()]
[UrlRoute(Path = "Checkout/Cart")]
public ActionResult Cart(ShoppingCartModel cart, string submitButton)
All browsers will cause this method to be hit on post back. The input type is detailed as:
<input type="image" src="/resources/images/removeselected.png" class="rightButton removeSelected" alt="Remove Selected" name="submitButton" value="<%= Html.Encode(Model.REMOVE_SELECTED) %>" />
And here is what is posted back with the form:
Chrome:
CartId=241&submitButton.x=83&submitButton.y=12&submitButton=removeSelected&Items%5B0%5D.Selected=true&Items%5B0%5D.Selected=false&Items%5B0%5D.OrderItemId=76&Items%5B0%5D.Product.ID=9611&Items%5B0%5D.Quantity=1
Internet Explorer 9:
CartId=244&Items%5B0%5D.Selected=true&Items%5B0%5D.Selected=false&Items%5B0%5D.OrderItemId=77&Items%5B0%5D.Product.ID=10091&Items%5B0%5D.Quantity=1&submitButton.x=27&submitButton.y=8
As you can see, Chrome is putting in the submitButton=removeSelected and IE isn't. It works fine in Firefox, also.
If I change it to <input type="submit"> it works without an issue. However, I want to use an IMAGE type

According to the specification:
When a pointing device is used to
click on the image, the form is
submitted and the click coordinates
passed to the server. The x value is
measured in pixels from the left of
the image, and the y value in pixels
from the top of the image. The
submitted data includes name.x=x-value
and name.y=y-value where "name" is the
value of the name attribute, and
x-value and y-value are the x and y
coordinate values, respectively.
You cannot expect more. IE doesn't send submitButton=removeSelected, yes, but there is nothing that obliges is to do so according to the spec. So you should not rely on this parameter. The fact that other browsers are sending it is probably just an implementation detail (on which of course you shouldn't rely).
As a workaround use a normal submit button and try styling it with CSS.

Here's how I got around this; hopefully someone else might find my solution helpful.
The message signature changes; the parameters are a list of all the various form button names. Chrome / FF will fill in these names so you won't need to parse it.
[HttpPost()]
[UrlRoute(Path = "Checkout/Cart")]
public ActionResult Cart(ShoppingCartModel cart, string removeSelected, string nextButton)
{
if (removeSelected == ShoppingCartModel.REMOVE_SELECTED)
removeOp = true;
else if (nextButton == ShoppingCartModel.NEXT_BUTTON)
nextOp = true;
else
{
PostbackButtonParser parser = new PostbackButtonParser(HttpContext.Request.InputStream, new string[] { ShoppingCartModel.NEXT_BUTTON, ShoppingCartModel.REMOVE_SELECTED });
if (parser.PostbackButtonName == ShoppingCartModel.NEXT_BUTTON)
nextOp = true;
else if (parser.PostbackButtonName == ShoppingCartModel.REMOVE_SELECTED)
removeOp = true;
}
if(removeOp) { /* do something */ }
else if (nextOp) { /* do something */ }
}
Then the code to the PostbackButtonParser is fairly straight forward:
/// <summary>
/// Implements a fallback rollover for Internet Explorer and other browsers which don't send the value with an INPUT TYPE="IMAGE" submit.
/// </summary>
/// <example>
/// PostbackButtonParser parser = new PostbackButtonParser(HttpContext.Request.InputStream, new string[] { "button1", "button2" });
/// if(parser.PostbackButtonName == "button1") {
/// // do something
/// }
/// else if (parser.PostbackButtonName == "button2" {
/// // do something else
/// }
/// </example>
/// <remarks>See http://stackoverflow.com/questions/5716260/is-there-a-bug-with-input-type-image-in-internet-explorer</remarks>
public class PostbackButtonParser
{
/// <summary>
/// Gets the name of the button which caused the postback.
/// </summary>
public string PostbackButtonName
{
get;
private set;
}
/// <summary>
/// Creates a new instance of the postback button parser
/// </summary>
/// <param name="requestStream">The stream to process</param>
/// <param name="buttonNames">An array of button names to evaluate gainst</param>
public PostbackButtonParser(Stream requestStream, string[] buttonNames)
{
byte[] stream = new byte[requestStream.Length];
requestStream.Read(stream, 0, stream.Length);
string contents = System.Text.Encoding.ASCII.GetString(stream);
for (int i = 0; i < buttonNames.Length; i++)
{
// Set first match
if (contents.Contains(buttonNames[i] + ".x") && contents.Contains(buttonNames[i] + ".y"))
{
PostbackButtonName = buttonNames[i];
break;
}
}
}
}
I really hope this helps someone; I spent a few hours on what really should have been trivial. What Darin said is very true, I could have styled a but I would rather have used the image type, just for semantics.

Related

TorbenK/TK.CustomMap Xamarin Forms PIN not showing

Did anyone experience the following issue?
The pin is nowhere to be found. there are very few samples out there and I can't find one that helps me resolve this issue.
Literally, I copied and pasted the snippet from the project sample from TK.CustomMap github
Image with working pin from the original project
Now, on mine, same snippet. code below
The pin is working because it clearly shows all the properties I added to it, such as the title. I know this by debugging. but is not getting into the view. so I believe. I have issues with the binding.
ViewModel
/// <summary>
/// Pins bound to the <see cref="TKCustomMap"/>
/// </summary>
public ObservableCollection<TKCustomMapPin> Pins
{
get { return _pins; }
set
{
if (_pins != value)
{
_pins = value;
OnPropertyChanged("Pins");
}
}
}
MapSpan _mapRegion = MapSpan.FromCenterAndRadius(new Position(37.787332, -122.410540), Distance.FromKilometers(2));
Position _mapCenter;
ObservableCollection<TKCustomMapPin> _pins;
constructor
_mapCenter = new Position(37.787332, -122.410540);
_pins = new ObservableCollection<TKCustomMapPin>();
CenterMap();
void CenterMap()
{
var stopOne = new Position(26.0769102268052, -80.2535091197863);
var pin = new TKCustomMapPin
{
Position = stopOne,
ShowCallout = true,
IsDraggable = true,
DefaultPinColor = Color.GreenYellow
};
_pins.Add(pin);
}
XAML
<tk:TKCustomMap
x:Name="mapView"
IsRegionChangeAnimated ="true"
HasZoomEnabled="True"
MapType="Satellite"
WidthRequest="500"
HeightRequest="800"
IsShowingUser="true"
IsClusteringEnabled="true"
MapRegion="{Binding MapRegion}"
Polygons="{Binding Polygons}"
CalloutClickedCommand ="{Binding CalloutClickedCommand}"
Routes="{Binding Routes}"
Pins="{Binding Pins}"/>

D365 Updating condition in method

I have Areas tab which contain grid with some calculations.
That calculations depends from area which is selected.
Situation is next: One object can have several areas, and when I open Areas tab, it calculates good but, when in object I change Area from one to another, value in calculations stays from previous. On the other words: it not get updated. I am using this code:
[Control("TabPage")]
class TabLineAreaGroup
{
public void pageActivated()
{
PMCContractArea contractArea;
AmountMST sumContractArea;
super();
pmcContractLine_ds.readCommonAreas(pmcContractLine);
h1_h2.realValue(pmcContractLine_ds.h1_h2(pmcContractLine));
efa.realValue(pmcContractLine_ds.efa(pmcContractLine));
bfa.realValue(pmcContractLine_ds.bfa(pmcContractLine));
mfa.realValue(pmcContractLine_ds.mfa(pmcContractLine));
sumArea.realValue(h1_h2.realValue() + efa.realValue() + bfa.realValue() + mfa.realValue());
while select AreaSelector, sum(RentalValue)
from contractArea
group by AreaSelector
where contractArea.ContractId == pmcContract.ContractId
&& contractArea.RentalObjectId == pmcContractLine.RentalObjectId
{
sumContractArea += contractArea.RentalValue;
switch (contractArea.AreaSelector)
{
case PMEAreaSelector::CommonAreaBuilding :
contractAreaBFA.realValue(contractArea.RentalValue);
break;
case PMEAreaSelector::CommonAreaSection :
contractAreaEFA.realValue(contractArea.RentalValue);
break;
case PMEAreaSelector::PrimaryArea, PMEAreaSelector::SecondaryArea :
contractAreaH1_H2.realValue(contractArea.RentalValue);
break;
case PMEAreaSelector::CommonAreaFixed :
contractAreaMFA.realValue(contractArea.RentalValue);
break;
}
}
contractAreaSum.realValue(sumContractArea);
}
}
What I need to add in this code, so when area is changed to update the calculations in grid ?
For Dynamics 365, Microsoft sometimes deprecates methods and doesn't update documentation, or they leave methods available, but have not implemented them.
For D365, it's likely you will need to use the event handler method on the Tab control.
Below is a sample where I just created a form with a couple Tab+Grid and the datasource of CustGroup
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
[FormControlEventHandler(formControlStr(TestForm, FormTabControl1), FormControlEventType::TabChanged)]
public static void FormTabControl1_OnTabChanged(FormControl sender, FormControlEventArgs e)
{
// You can interact with FormRun
FormRun formRun = sender.formRun();
// You can interact with the actual control (from event handler)
FormTabControl formTabControl = sender is FormTabControl ? sender as FormTabControl : null;
// You can get events
FormTabControlTabChangedEventArgs formTabControlTabChangedEventArgs = e is FormTabControlTabChangedEventArgs ? e as FormTabControlTabChangedEventArgs : null;
// You can interact with the tab pages
if (formTabControl && formTabControlTabChangedEventArgs)
{
FormControl fc = formTabControl.controlNum(formTabControlTabChangedEventArgs.oldTab());
FormTabPageControl tabPageOld = formTabControl.controlNum(formTabControlTabChangedEventArgs.oldTab());
FormTabPageControl tabPageNew = formTabControl.controlNum(formTabControlTabChangedEventArgs.newTab());
info(strFmt("Tab changed from %1 to %2", tabPageOld.caption(), tabPageNew.caption()));
}
// You can interact with datasources
FormDataSource fdsCustGroup = formRun.dataHelper().FindDataSource('CustGroup');
}

Localization in EnumDropDownListFor using asp.net boilerplate

I have an enum dropdown
//control
#Html.EnumDropDownListFor(
m => m.OrderBy,
new {#class = "btn btn-default dropdown-toggle toggle", onchange = "document.getElementById('hf_Pagename').value,this.form.submit();"})
//my enum
public enum OrderByOptions
{
Default,
PriceLowToHigh,
PriceHighToLow,
MostRecent
}
Now the problem is I need to localize them. But in this case from" PriceLowToHigh" needs to change to " Price- low to high"
You can use AbpDisplayNameAttribute:
public enum OrderByOptions
{
[AbpDisplayName(MyConsts.LocalizationSourceName, "OrderByOptions.Default")]
Default,
[AbpDisplayName(MyConsts.LocalizationSourceName, "OrderByOptions.PriceLowToHigh")]
PriceLowToHigh,
[AbpDisplayName(MyConsts.LocalizationSourceName, "OrderByOptions.PriceHighToLow")]
PriceHighToLow,
[AbpDisplayName(MyConsts.LocalizationSourceName, "OrderByOptions.MostRecent")]
MostRecent
}
Define them in your localization files:
<text name="OrderByOptions.PriceLowToHigh">Price - Low to High</text>
Update
AbpDisplayName works on type class
You can define:
[AttributeUsage(AttributeTargets.Field)]
public class FieldAbpDisplayNameAttribute : AbpDisplayNameAttribute
{
// ...
}
Then use [FieldAbpDisplayNameAttribute(...)] instead.
There are many ways to achieve the issue.
Way #1
Don't use #Html.EnumDropDownListFor! Just traverse enum and create the html element like below;
(I am writing the code on the top of my head)
<select>
#foreach (var item in Enum.GetValues(typeof(OrderByOptions)))
{
<option value="#((int)item)">#(Localize(item.ToString()))</option>
}
</select>
There's no Localize method. Just localize it with your way.
Way #2
Other alternative is not using enum but create a dropdown item collection. And let an item consist of DisplayText and Value. Display Text must be localized from server.
Way #3
Follow the instructions explained here:
https://ruijarimba.wordpress.com/2012/02/17/asp-net-mvc-creating-localized-dropdownlists-for-enums/
With the information above, I solve my problem this way.
I created a custome Attribute AbpEnumDisplayNameAttribute inherited from AbpDisplayNameAttribute.
[AttributeUsage(AttributeTargets.Field)]
public class AbpEnumDisplayNameAttribute : AbpDisplayNameAttribute
{
/// <summary>
/// <see cref="AbpDisplayNameAttribute"/> for enum values.
/// </summary>
public AbpEnumDisplayNameAttribute(string sourceName, string key) : base(sourceName, key)
{
}
}
Then I created an extension for Enum display value localization.
public static class EnumLocalizationExtension
{
public static string ToLocalizedDisplayName(this Enum value)
{
var displayName = value.ToString();
var fieldInfo = value.GetType().GetField(displayName);
if (fieldInfo != null)
{
var attribute = fieldInfo.GetCustomAttributes(typeof(AbpEnumDisplayNameAttribute), true)
.Cast<AbpEnumDisplayNameAttribute>().Single();
if (attribute != null)
{
displayName = attribute.DisplayName;
}
}
return displayName;
}
}

Workflow foundation custom Assign Activity

I am defining this in my designer:
<sap:WorkflowItemPresenter>
<statements:Assign DisplayName="Assign"/>
</sap:WorkflowItemPresenter>
I thought it would simply work if i add the Assign there but i was wrong.
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete));
}
/// <summary>
/// Called from Execute when Condition evaluates to true.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="instance">The instance.</param>
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
{
//to be added
}
This is the code from the base class.
I don't need to alter the Assign activity at all, i just want to get access to the NativeActivityContext. In fact i am trying to wrap it up and do some checks on the context's properties in the OnExecuteComplete method. Is there a way to accomplish this?
EDIT 1:
DotNetHitMan suggested and shown me on WF 4 Rehosted Designer - get foreach InArgument Value how to work with those trackings and i indeed succeeded to work this out with his solution:
if (trackingEventArgs.Activity is Assign)
{
Assign ass = trackingEventArgs.Activity as Assign;
if (ass.To.Expression != null)
{
dynamic vbr = null;
if ((ass.To.Expression is VisualBasicReference<int>))
{
//vbr.ExpressionText will hold the value set in the To section of the Assign activity, one of the variables will reside here
vbr = ass.To.Expression as VisualBasicReference<int>;
}
else if ((ass.To.Expression is VisualBasicReference<string>))
{
vbr = ass.To.Expression as VisualBasicReference<string>;
}
ActivityStateRecord activityStateRecord = null;
if (trackingEventArgs.Record != null)
activityStateRecord = trackingEventArgs.Record as ActivityStateRecord;
if (activityStateRecord != null)
{
if (activityStateRecord.Arguments.Count > 0)
{
//checking if the variable defined in the To section is to be displayed in the watch window
GlobalFunctions.WatchWindowViewModel.VariableDefinition existingVariable = GlobalFunctions.WatchWindowViewModel.Instance.VariableExists(vbr.ExpressionText);
if (existingVariable != null)
{
foreach (KeyValuePair<string, object> argument in activityStateRecord.Arguments)
{
if (argument.Key.Equals("Value"))
{
Application.Current.Dispatcher.Invoke(
() =>
{
existingVariable.VariableValue.Clear();
existingVariable.VariableValue.Add(
argument.Value.ToString());
});
}
}
}
}
}
}
}
I still face something a bit ugly. When checking the arguments for the Assign activity i get the key "Value". But if i define a variable named "i" and want to see its changes as this Assign executes i have to take a look at that VisualBasicReference<> to check the name of the variable declared there just like in the code above. This way of doing it works indeed and i managed to cover ints and strings which is fine for now .. but is there any shortcut that can be used in my code ?
EDIT 2
I got a new idea today and put it to work:
Here is the library code:
public sealed class CustomAssign : NativeActivity, IActivityTemplateFactory
{
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete));
}
/// <summary>
/// Called from Execute when Condition evaluates to true.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="instance">The instance.</param>
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
{
//to be added
}
Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
return new CustomAssign
{
Body = new Assign()
};
}
}
And the designer:
<sap:ActivityDesigner x:Class="ARIASquibLibrary.Design.CustomAsignDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
xmlns:statements="http://schemas.microsoft.com/netfx/2009/xaml/activities" Collapsible="False" BorderThickness="20" BorderBrush="Transparent">
<sap:ActivityDesigner.Template>
<ControlTemplate TargetType="sap:ActivityDesigner">
<Grid>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</sap:ActivityDesigner.Template>
<DockPanel LastChildFill="True">
<sap:WorkflowItemPresenter Item="{Binding Path=ModelItem.Body, Mode=TwoWay}"/>
</DockPanel>
</sap:ActivityDesigner>
So, in a few words: i've hosted the Assign activity in my custom activity and changed the ControlTemplate in order to keep only the ContentPresenter, which in turn will be the Assign. Now, by dragging it to the designer, you will have exactly the original appearance but with the ability to write code and check the execution steps in the :
protected override void Execute(NativeActivityContext context)
or
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
Why is that? Through the context.DataContext you can get to all the variables and arguments in the scope where this activity resides in order to develop a watch window.
Rather than dealing with each variable type just convert the expression to its base interface.
ITextExpression vbr = ass.To.Expression as ITextExpression;
You can then just access the expression text property without caring about the type of variable assigned to the expression.
GlobalFunctions.WatchWindowViewModel.VariableDefinition existingVariable = GlobalFunctions.WatchWindowViewModel.Instance.VariableExists(vbr.ExpressionText);
This should cater for (I hope) all variable types that can be applied.

How can I hide weekends when using the ASP.NET Calendar control?

Sometimes when displaying a calendar it is necessary to prevent the weekend days and the weekend names in the day header from showing, is there a way to do this using the ASP.NET Calendar control?
As the control is provided, there is no way to do this without overriding the control. One way of doing this is to is to override the OnDayRender and Render methods to remove the information from the output prior to sending it back to the client.
The following is a screen shot of what the control looks like when rendered:
The following is a basic control override that demonstrates removing the weekend day columns from the control.
/*------------------------------------------------------------------------------
* Author - Rob (http://stackoverflow.com/users/1185/rob)
* -----------------------------------------------------------------------------
* Notes
* - This might not be the best way of doing things, so you should test it
* before using it in production code.
* - This control was inspired by Mike Ellison's article on The Code Project
* found here: http://www.codeproject.com/aspnet/MellDataCalendar.asp
* ---------------------------------------------------------------------------*/
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.IO;
using System.Xml;
namespace DataControls
{
/// <summary>
/// Example of a ASP.NET Calendar control that has been overriden to force
/// the weekend columns to be hidden on demand.
/// </summary>
public class DataCalendar : Calendar
{
private bool _hideWeekend;
private int _saturday;
private int _sunday;
/// <summary>Constructor</summary>
public DataCalendar()
: base()
{
// Default to showing the weekend
this._hideWeekend = false;
// Set the default values for Saturday and Sunday
this.Saturday = 6;
this.Sunday = 0;
}
/// <summary>
/// Indicate if the weekend days should be shown or not, set to true
/// if the weekend should be hidden, false otherwise. This field
/// defaults to false.
/// </summary>
public bool HideWeekend
{
get { return this._hideWeekend; }
set { this._hideWeekend = value; }
}
/// <summary>
/// Override the default index for Saturdays.
/// </summary>
/// <remarks>This option is provided for internationalization options.</remarks>
public int Saturday
{
get { return this._saturday; }
set { this._saturday = value; }
}
/// <summary>
/// Override the default index for Sundays.
/// </summary>
/// <remarks>This option is provided for internationalization options.</remarks>
public int Sunday
{
get { return this._sunday; }
set { this._sunday = value; }
}
/// <summary>
/// Render the day on the calendar with the information provided.
/// </summary>
/// <param name="cell">The cell in the table.</param>
/// <param name="day">The calendar day information</param>
protected override void OnDayRender(TableCell cell, CalendarDay day)
{
// If this is a weekend day and they should be hidden, remove
// them from the output
if (day.IsWeekend && this._hideWeekend)
{
day = null;
cell.Visible = false;
cell.Text = string.Empty;
}
// Call the base render method too
base.OnDayRender(cell, day);
}
/// <summary>
/// Render the calendar to the HTML stream provided.
/// </summary>
/// <param name="html">The output control stream to write to.</param>
protected override void Render(HtmlTextWriter html)
{
// Setup a new HtmlTextWriter that the base class will use to render
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter calendar = new HtmlTextWriter(sw);
// Call the base Calendar's Render method allowing OnDayRender()
// to be executed.
base.Render(calendar);
// Check to see if we need to remove the weekends from the header,
// if we do, then remove the fields and use the new verison for
// the output. Otherwise, just use what was previously generated.
if (this._hideWeekend && this.ShowDayHeader)
{
// Load the XHTML to a XML document for processing
XmlDocument xml = new XmlDocument();
xml.Load(new StringReader(sw.ToString()));
// The Calendar control renders as a table, so navigate to the
// second TR which has the day headers.
XmlElement root = xml.DocumentElement;
XmlNode oldNode = root.SelectNodes("/table/tr")[1];
XmlNode sundayNode = oldNode.ChildNodes[this.Sunday];
XmlNode saturdayNode = oldNode.ChildNodes[this.Saturday];
XmlNode newNode = oldNode;
newNode.RemoveChild(sundayNode);
newNode.RemoveChild(saturdayNode);
root.ReplaceChild(oldNode, newNode);
// Replace the buffer
html.WriteLine(root.OuterXml);
}
else
{
html.WriteLine(sw.ToString());
}
}
}
}
As far I know you can't, but you can experiment with WeekendDayStyle, for example by setting style with display:none. Alternatively, you can create custom control inherited from Calendar and override ether Render, OnDayRender or something else.
I believe you can handle the Day Render event and hide the cell or assign CSS properties to make it invisible or grayed out. Below is a simple example, I hope this helps.
protected void Calendar_DayRender(object sender, DayRenderEventArgs e)
{
e.Cell.Visible = False;
// or
// e.Cell.Attributes.Add("class", "Invisible");
// or
// e.Cell.Attributes.Add("style", "display: none");
}
If you are OK using a jQuery solution, it takes just a few lines of code:
<script type="text/javascript">
$(document).ready(function () {
$('._title').parent().attr('colspan', '5'); // title row initially has a colspan of seven
$('._dayheader:first, ._dayheader:last', $('#<%= Calendar1.ClientID %>')).hide(); // remove first and last cells from day header row
$('._weekendday').hide(); // remove all the cells marked weekends
});
</script>
<asp:Calendar runat="server" ID="Calendar1">
<TitleStyle CssClass="_title" />
<DayHeaderStyle CssClass="_dayheader" />
<WeekendDayStyle CssClass="_weekendday" />
</asp:Calendar>
Here are some considerations with this approach:
If JavaScript is disabled, the client will see weekends.
In older, slower browsers, the calendar kind of jumps as the jQuery executes on load.
This solution could probably be implemented in straight CSS with :first-child.
If you add another calendar to the page, you will need to duplicate the middle line of JavaScript. This is necessary because we are using :first and :last.
If you only have one calendar control on the page, you can simplify the middle line of JavaScript by removing the second argument of the jQuery selector: $('#<%= Calendar1.ClientID %>')
As zacharydl have suggested I managed to hide the weekends using jQuery. I have made a small change to the original code.
<script type="text/javascript">
HideWeekEnd();
function HideWeekEnd ()
{
$('._title').parent().attr('colspan', '7');
$('._dayheader:nth-last-child(1) , ._dayheader:nth-last-child(2) ', $('#<%= Calendar1.ClientID %>')).hide(); // remove last two cells from day header row
$('._weekendday').hide(); // remove all the cells marked weekends
}
Sys.Application.add_init(appl_init);
function appl_init() {
var pgRegMgr = Sys.WebForms.PageRequestManager.getInstance();
pgRegMgr.add_endRequest(HideWeekEnd);
}
</script>
You will have to register the HideWeekEnd() in page endRequest to ensure its called during page post back.
here is another way using CSS only to achieve that:
<style>
.hidden,
#Calendrier tr > th[abbr=Saturday],
#Calendrier tr > th[abbr=Sunday] { display:none; }
#Calendrier tr > th { text-align: center; }
</style>
<asp:Calendar ID="Calendar1" DayNameFormat="Full" runat="server"
WeekendDayStyle-CssClass="hidden" ClientIDMode="Static" >
</asp:Calendar>

Resources