D365 Updating condition in method - axapta

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');
}

Related

Is it possible to get element.args() from an extended method in Dynamics 365 for operations

In Dynamics 365 for operations I am trying to use a post-event handler of the init() form method from LedgerTransVoucher to find tableId of:
element.args().dataset()
There is a big switch statement in the method that i want to extend with one more case.
What i have done so far is just creating an extension class but i don't really know how to get the data from the extended method
[ExtensionOf(formStr(LedgerTransVoucher))]
final class LedgerTransVoucher_Extension
{
/// <summary>
///
/// </summary>
/// <param name="args"></param>
[PostHandlerFor(formStr(LedgerTransVoucher), formMethodStr (LedgerTransVoucher, init))]
public static void LedgerTransVoucher_Post_init(XppPrePostArgs args)
{
TableId sourceTable;
//sourceTable = element.args().dataset();
//if(sourceTable == tableNum(myTable))
//{
// do something here
//}
}
}
to call:
sourceTable = element.args().dataset();
of course doesn't work but i wan't to know if i can somehow retrieve the data from the extended method.
This can be done very easily with customization but i want to do everything i can to use extensions instead.
Any ideas or possible workarounds?
You can try something like this:
[PostHandlerFor(formStr(LedgerTransVoucher), formMethodStr (LedgerTransVoucher, init))]
public static void LedgerTransVoucher_Post_init(XppPrePostArgs args)
{
TableId sourceTable;
FormRun element;
element = args.getThis();
sourceTable = element.args().dataset();
if(sourceTable == tableNum(myTable))
{
do something here
}
}
or
[FormEventHandler(formStr(LedgerTransVoucher), FormEventType::Initialized)]
public static void LedgerTransVoucher_OnInitialized(xFormRun sender, FormEventArgs e)
{
if(sender.args().dataset() == tableNum(myTable))
{
do something here
}
}

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 to update Visual Studio UI when using DynamicItemStart inside a vsix package

I'm implementing a DynamicItemStart button inside a Menu Controller. I'm loading the dynamic items for this button when Visual Studio starts. Everything is loaded correctly so the initialize method is called an I see all the new items in this Dynamic button. After the package is completely loaded I want to add more items to this Dynamic button, but since the package is already loaded the initialize method is not called again and I cannot see the new items in this Dynamic button. I only see the ones that were loaded when VS started.
Is there any way that I can force the update of this Dynamic button so it shows the new items?. I want to be able to update the VS UI after I added more items but outside the Initialize method.
The implementation I did is very similar to the one showed on this msdn example:
http://msdn.microsoft.com/en-us/library/bb166492.aspx
Does anyone know if an Update of the UI can be done by demand?
Any hints are greatly appreciated.
I finally got this working. The main thing is the implementation of a derived class of OleMenuCommand that implements a new constructor with a Predicate. This predicate is used to check if a new command is a match within the DynamicItemStart button.
public class DynamicItemMenuCommand : OleMenuCommand
{
private Predicate<int> matches;
public DynamicItemMenuCommand(CommandID rootId, Predicate<int> matches, EventHandler invokeHandler, EventHandler beforeQueryStatusHandler)
: base(invokeHandler, null, beforeQueryStatusHandler, rootId)
{
if (matches == null)
{
throw new ArgumentNullException("Matches predicate cannot be null.");
}
this.matches = matches;
}
public override bool DynamicItemMatch(int cmdId)
{
if (this.matches(cmdId))
{
this.MatchedCommandId = cmdId;
return true;
}
this.MatchedCommandId = 0;
return false;
}
}
The above class should be used when adding the commands on execution time. Here's the code that creates the commands
public class ListMenu
{
private int _baselistID = (int)PkgCmdIDList.cmdidMRUList;
private List<IVsDataExplorerConnection> _connectionsList;
public ListMenu(ref OleMenuCommandService mcs)
{
InitMRUMenu(ref mcs);
}
internal void InitMRUMenu(ref OleMenuCommandService mcs)
{
if (mcs != null)
{
//_baselistID has the guid value of the DynamicStartItem
CommandID dynamicItemRootId = new CommandID(GuidList.guidIDEToolbarCmdSet, _baselistID);
DynamicItemMenuCommand dynamicMenuCommand = new DynamicItemMenuCommand(dynamicItemRootId, isValidDynamicItem, OnInvokedDynamicItem, OnBeforeQueryStatusDynamicItem);
mcs.AddCommand(dynamicMenuCommand);
}
}
private bool IsValidDynamicItem(int commandId)
{
return ((commandId - _baselistID) < connectionsCount); // here is the place to put the criteria to add a new command to the dynamic button
}
private void OnInvokedDynamicItem(object sender, EventArgs args)
{
DynamicItemMenuCommand invokedCommand = (DynamicItemMenuCommand)sender;
if (null != invokedCommand)
{
.....
}
}
private void OnBeforeQueryStatusDynamicItem(object sender, EventArgs args)
{
DynamicItemMenuCommand matchedCommand = (DynamicItemMenuCommand)sender;
bool isRootItem = (matchedCommand.MatchedCommandId == 0);
matchedCommand.Enabled = true;
matchedCommand.Visible = true;
int indexForDisplay = (isRootItem ? 0 : (matchedCommand.MatchedCommandId - _baselistID));
matchedCommand.Text = "Text for the command";
matchedCommand.MatchedCommandId = 0;
}
}
I had to review a lot of documentation since it was not very clear how the commands can be added on execution time. So I hope this save some time whoever has to implement anything similar.
The missing piece for me was figuring out how to control the addition of new items.
It took me some time to figure out that the matches predicate (the IsValidDynamicItem method in the sample) controls how many items get added - as long as it returns true, the OnBeforeQueryStatusDynamicItem gets invoked and can set the details (Enabled/Visible/Checked/Text etc.) of the match to be added to the menu.

ASP.NET Custom Web control

I'm experiencing some problems and right now I don't know how to solve it. The web control simply updates a clock represented by a label every second. My issue is that the web control exposes a property called 'Formato' where the user can select to display in format 12 or 24 hours. This is done with an enum type where in spanish Doce means 12 and Veinticuatro means 24. This is the code for the server control:
namespace Ejercicio2RelojControl
{
public enum _FormatoHora
{
Doce,
Veinticuatro
}
[DefaultProperty("FormatoHora")]
[ToolboxData("<{0}:Ejercicio2RelojControl runat=server></{0}:Ejercicio2RelojControl>")]
[ToolboxBitmap(typeof(Ejercicio2RelojControl), "Ejercicio2RelojControl.Ejercicio2RelojControl.ico")]
//[Designer("Ejercicio2RelojControl.Ejercicio2RelojControlDesigner, Ejercicio2RelojControl")]
public class Ejercicio2RelojControl : WebControl
{
public Ejercicio2RelojControl()
{
}
[
//Bindable(true),
Category("Appearance"),
//DefaultValue(_FormatoHora.Doce),
Description(""),
]
public virtual _FormatoHora FormatoHora
{
get
{
//object t = ViewState["FormatoHora"];
//return (t == null) ? _FormatoHora.Doce : (_FormatoHora)t;
object obj2 = this.ViewState["_FormatoHora"];
if (obj2 != null)
{
return (_FormatoHora)obj2;
}
return _FormatoHora.Doce;
}
set
{
ViewState["_FormatoHora"] = value;
}
}
//Create one TimerControl
Timer timer = new Timer();
private Label clockLabel = new Label();
// Declare one Updatepanel
UpdatePanel updatePanel = new UpdatePanel();
// Now override the Load event of Current Web Control
protected override void OnLoad(EventArgs e)
{
//Text = "hh:mm:ss";
// Create Ids for Control
timer.ID = ID + "_tiker";
clockLabel.ID = ID + "_l";
// get the contentTemplate Control Instance
Control controlContainer = updatePanel.ContentTemplateContainer;
// add Label and timer control in Update Panel
controlContainer.Controls.Add(clockLabel);
controlContainer.Controls.Add(timer);
// Add control Trigger in update panel on Tick Event
updatePanel.Triggers.Add(new AsyncPostBackTrigger() { ControlID = timer.ID, EventName = "Tick" });
updatePanel.ChildrenAsTriggers = true;
// Set default clock time in label
clockLabel.Text = DateTime.Now.ToString("h:mm:ss tt");
//clockLabel.Text = DateTime.Now.ToString("H:mm:ss");
// Set Interval
timer.Interval = 1000;
// Add handler to timer
timer.Tick += new EventHandler<EventArgs>(timer_Tick);
updatePanel.RenderMode = UpdatePanelRenderMode.Block;
//Add update panel to the base control collection.
base.Controls.Add(updatePanel);
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(FormatoHora);
}
void timer_Tick(object sender, EventArgs e)
{
// Set current date time in label to move current at each Tick Event
clockLabel.Text = DateTime.Now.ToString("h:mm:ss tt");
//clockLabel.Text = DateTime.Now.ToString("H:mm:ss");
}
}
}
Now it's time to test the custom control in an asp.net web application.
<cc1:Ejercicio2RelojControl ID="Ejercicio2RelojControl1" runat="server" />
Works great! BUT when I add the property "Formato" fails at compile time:
<cc1:Ejercicio2RelojControl ID="Ejercicio2RelojControl1" runat="server" Formato="Doce" />
Compiler Error Message: CS0117: 'Ejercicio2RelojControl.Ejercicio2RelojControl' does not contain a definition for 'FormatoHora'
Why is the property Formato making the web app crash at compile time?
Thanks a lot.
EDIT:
namespace Ejercicio2RelojControl
{
public enum FormatoHora
{
Doce,
Veinticuatro
}
[DefaultProperty("FormatoHora")]
[ToolboxData("<{0}:Ejercicio2RelojControl runat=server></{0}:Ejercicio2RelojControl>")]
public class Ejercicio2RelojControl : WebControl, INamingContainer
{
public FormatoHora FormatoHora
{
get
{
object obj2 = this.ViewState["FormatoHora"];
if (obj2 != null)
{
return (FormatoHora)obj2;
}
return FormatoHora.Doce;
}
set
{
ViewState["FormatoHora"] = value;
}
}
As you can see I've changed the public property. Now the error has changed. Is the following:
Compiler Error Message: CS0120: An object reference is required for the non-static field, method, or property 'Ejercicio2RelojControl.Ejercicio2RelojControl.FormatoHora.get'
Any help appreciated. Thanks
EDIT 2:
I've discovered that the problem is on the set {}. If I comment it, all is working fine but then I cannot change FormatoHora between 12 and 24 because of is read only due to only get{} is implemented. Any help with the implementation of set{} ?
I am here for giving you the solution:
You are using the same name for the namespace and for the webcontrol (Ejercicio2RelojControl) . Simply change that and your code will work fine.
Hope it helps, despite the fact some years have passed :)

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