Sunday 23 December 2007

IINet vs Exetel - is it worth going naked? Maybe not...

I currently use the ISP IInet using the 10GB Off Peak/10GB On Peak (ADSL 2+ light) package. However, I have heard a lot of buzz about the so called 'naked' plans available through IInet and other ISPs like Exetel. Up till now, I grudgingly needed a phone line just for ADSL. To me that was $30 bucks down the drain.... until now. The naked plans don't require line rental at all!

On the face of it, I prefer the IInet deal over Exetel for my situation because:
  1. IInet have been a great provider so far and there are some rumours about Exetel having a less than stellar approach to customer service.
  2. I already have a Belkin router (F1PI241ENau - http://catalog.belkin.com/IWCatProductPage.process?Product_Id=247190) and have heard that they don't play well with the Exetel service. I don't want to fork out $200 for a new modem that works with the Exetel naked service.
  3. You get an incoming number as part of the IItalk service. Apparently you have to pay $10 extra to add this functionality with Exetel.
  4. Even though uploads are counted as part of your bandwidth allowance (Exetel doesn't charge for this), I don't upload that much ( about 1GB per month ).
  5. I don't really care about having a static IP (this is what Exetel provides).
  6. P2P are shaped (according to official announcements) on the Exetel network (see http://whirlpool.net.au/article.cfm?id=1734&show=replies )
  7. No excess usage charges (just shaped) - wheras Exetel charges $3 per GB.

However, after considering some of the drawbacks (e.g. measured uploads including voice), I am staying put for now to see where the new naked DSL market heads.

Thursday 20 December 2007

Golden Oldie - ASP.NET multiline doesn't enforce MaxLength property

This one is a Golden Oldie and is a problem with the Textarea HTML control (not specifically a problem with ASP.NET). Technically, the ASP.NET controls should not even provide the MaxLength property when TextMode is set to MultiLine....

But there are ways around this issue using javascript and/or inherited controls:


using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace LendLease.MRP.Web.UI.WebControls
{
//Custom TextBox - used to fix issue with the Maxlength not working in controls
//modified version of http://www.codeproject.com/KB/aspnet/Extended_ASPNET_TextBox.aspx
public class TextBox : System.Web.UI.WebControls.TextBox
{

protected override void OnPreRender(EventArgs e)
{
if (MaxLength > 0 && this.TextMode == TextBoxMode.MultiLine)
{
if (!Page.ClientScript.IsClientScriptIncludeRegistered("TextArea"))
{
Page.ClientScript.RegisterClientScriptInclude("TextArea", ResolveUrl("~/Include/TextBoxMaximumLength.js"));
}
this.Attributes.Add("onkeyup", "LimitInput(this)");
this.Attributes.Add("onbeforepaste", "doBeforePaste(this)");
this.Attributes.Add("onpaste", "doPaste(this)");
this.Attributes.Add("onmousemove", "LimitInput(this)");
this.Attributes.Add("maxLength", this.MaxLength.ToString());
}
base.OnPreRender(e);
}
}
}


JAVASCRIPT:


function doBeforePaste(control){
maxLength = control.attributes["maxLength"].value;
if(maxLength)
{
event.returnValue = false;
}
}
function doPaste(control){
maxLength = control.attributes["maxLength"].value;
value = control.value;
if(maxLength){
event.returnValue = false;
maxLength = parseInt(maxLength);
var oTR = control.document.selection.createRange();
var iInsertLength = maxLength - value.length + oTR.text.length;
var sData = window.clipboardData.getData("Text").substr(0,iInsertLength);
oTR.text = sData;
}
}
function LimitInput(control)
{
if(control.value.length > control.attributes["maxLength"].value)
{
alert("You cannot enter more than " + control.attributes["maxLength"].value + " characters into this field");
control.value = control.value.substring(0,control.attributes["maxLength"].value);
}
};

Issue with VS 2008 and the Web Client Software Factory - FIX

When attempting to add classes (e.g. via Add->New Class) in my VS 2008 projects, I have been getting this error constantly. This lead me to do a workaround by just copying classes from other projects! (NOT an ideal situation!)

==========================================================================
Could not load file or assembly 'Microsoft.VisualStudio.TemplateWizardInterface,
Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its
dependencies. The located assembly's manifest definition does not match the
assembly reference. (Exception from HRESEULT: 0x80131040)
==========================================================================

Apparently, there is a workaround to this issue. You just have to find your devenv.exe.config file (e.g. mine was in "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe.config"), and change the version number from 9.0.0.0 to 8.0.0.0

<dependentAssembly>
<assemblyIdentity name="Microsoft.VisualStudio.TemplateWizardInterface" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.9.9.9" newVersion="8.0.0.0" />
</dependentAssembly>

Wednesday 19 December 2007

Telerik RadGrid V5.0 Sorting Bug with Nullable DateTime Types - "Property [ColumnName] does not support IComparable"

It turns out the Telerik RadGrid does not support sorting for nullable types (e.g. DateTime?) out of the box. For example, if you use a LINQ datasource for your grid based on a column that is nullable in SQL Server, you will get an error when trying to sort the column "Property [BoundColumnName] does not implement IComparable".

The simplest fix for this is to just make your column non-nullable if this is possible in your business situation.

Tuesday 18 December 2007

LINQ - using LINQ as the Combined Business Logic and DAL

We have taken a few different approaches to LINQ on different projects at Lend Lease. Currently on the Bovis Lend Lease Monthly Reporting Team, we are not using the Web Client Software Factory (WCSF) and the Model View Presenter Pattern (MVP). Rather, we are using partial classes of LINQ objects (separate .cs files for each class for readability & maintainablility). This is a more rapid approach to development which I enjoy coding much more. I also just found out that one of the FrameworkTeam has just extended the WCSF ObjectContainerDatasource so that it includes ALL fields (both bound and unbound) used in a control - which avoids the problem whereby non-bound fields are nulled out from the bound objects. e.g. If I use the ObjectContainerDataSource and have a field StatusId, but don't bind it - then the object in the "Updated" Event of by datasource has a statusId of null. It would be wiped out if I updated the database with the same object - which I see as a major bug in the WCSF! (Will post about this problem and solution shortly).

Anyway back to the point - here is some very basic sample Code using LINQ as the Business Logic layer with partial classes to extend the generated SQLMetal classes (aka the classes from the generated dbml file):



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LendLease.ManagementReporting.Service.DataContract.DTO;

namespace LendLease.MRP.Service.Persistence.Entity
{

public partial class Ctl_Person_Resp
{
public string UserName
{
get { return this.Dim_User.First_Name + " " + this.Dim_User.Last_Name; }
}

/// <summary>
/// Gets list of People who have responsibility in the current level of the hierarchy.
/// </summary>
/// <param name="businessHierarchyId"></param>
/// <returns></returns>
public static List<PersonResponsibleListDTO> GetPersonResponsibleList(int businessHierarchyId)
{
MRPDataContext context = new MRPDataContext();

//Join to the the member code so we can filter the person responsible list
var query = from person in context.Ctl_Person_Resps
join hierarchy in context.Dim_Business_Hierarchy_PCs on person.Business_Hierarchy_PC_Member_Code equals hierarchy.Member_Code
where hierarchy.Business_Hierarchy_PC_SKEY == businessHierarchyId
select new PersonResponsibleListDTO { User_SKEY = person.User_SKEY, UserName = person.UserName};
return query.Distinct().ToList<PersonResponsibleListDTO>();
}

}
}

Friday 14 December 2007

Telerik RadGrid - Creating A Grouped Grid that allows sorting and editing

Today, I wanted to get the Telerik RadGrid (http://www.telerik.com/products/aspnet/controls/grid/overview.aspx) 5.0 edit functionality working in conjunction with its grouping functionality.

Background: I have been temporarily seconded from the Lend Lease Property Pipeline project onto a high-profile BI project that has several dashboards for KPIs used by management (hosted within MOSS 2007 - parameters are passed into my page via Request.Params). I have a few management-style pages that need to be created - but they have to be editable so this excludes Reporting Services from the equation.

One of the requirements of this particular page was to have automatic grouping of risks and opportunities into different sections of the grid. However, when I set up the grid my code triggered the edit event, I get the following error:

[InvalidConstraintException: Cannot have 0 columns.]

Google only returned 2 results on this error - and they didn't give me a direct solution. After looking through the Telerik site, I found a few clues which pointed to the fact I had to have both the "Select Fields" and "GroupByFields" Set in the grid. Here is my current (unfinished) version of the page) which show that magic combination of code hacks and declarative settings to get the grid to work in all its Databound AJAX-enabled editable groupable glory!


Code:





<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="RiskOpportunity.aspx.cs"
Inherits="ddkonline.MRP.Client.RiskOpportunity" %>


<%@ Register Assembly="Microsoft.Practices.Web.UI.WebControls" Namespace="Microsoft.Practices.Web.UI.WebControls"
TagPrefix="pp" %>

<%@ Register Assembly="RadGrid.Net2" Namespace="Telerik.WebControls" TagPrefix="radG" %>
<%@ Register Assembly="RadCalendar.Net2" Namespace="Telerik.WebControls" TagPrefix="radCln" %>
<!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>Risks and Opportunities</title>
</head>
<body>
<form id="form1" runat="server">
<pp:ObjectContainerDataSource ID="OdsRiskOpportunityDataSource" runat="server" DataObjectTypeName="ddkonline.MRP.Service.Persistence.Entity.ODS_Risk_Opportunity"
OnInserted="OdsRiskOpportunityDataSource_Inserted" OnUpdated="OdsRiskOpportunityDataSource_Updated"
OnSelecting="OdsRiskOpportunityDataSource_Selecting" />
<asp:LinqDataSource ID="BusinessUnitDataSource" runat="server" ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="Sort_Order" TableName="Dim_Business_Hierarchy_PCs" Where="ETL_Region == @ETL_Region &amp;&amp; Member_Level == @Member_Level"
OnSelecting="BusinessUnitDataSource_Selecting">
<WhereParameters>
<asp:Parameter Name="ETL_Region" Type="String" />
<asp:Parameter DefaultValue="&quot;3&quot;" Name="Member_Level" Type="Int32" />
</WhereParameters>
</asp:LinqDataSource>
<asp:LinqDataSource ID="ReportingCurrencyDataSource" runat="server" ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="Currency_Name" Select="new (Currency_Name, Currency_Code, Reporting_Currency_SKEY)"
TableName="Dim_Reporting_Currencies">
</asp:LinqDataSource>
<asp:LinqDataSource ID="RiskConsequenceDataSource" runat="server" ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="Sort_Order" Select="new (Lookup_SKEY, Lookup_Value)" TableName="Dim_Lookups"
Where="Type == @Type">
<WhereParameters>
<asp:Parameter DefaultValue="RiskConsequence" Name="Type" Type="String" />
</WhereParameters>
</asp:LinqDataSource>
<asp:LinqDataSource ID="StatusDataSource" runat="server" ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="Sort_Order" Select="new (Lookup_SKEY, Lookup_Value)" TableName="Dim_Lookups"
Where="Type == @Type">
<WhereParameters>
<asp:Parameter DefaultValue="Status" Name="Type" Type="String" />
</WhereParameters>
</asp:LinqDataSource>
<%--<asp:LinqDataSource ID="peopleDataSource" runat="server"
ContextTypeName="ddkonline.MRP.Service.Persistence.Entity.MRPDataContext"
OrderBy="ETL_Extract_User" Select="new (People_SKEY, ETL_Extract_User)"
TableName="Dim_People">
</asp:LinqDataSource>--%>
<div>
<radG:RadGrid ID="BusinessRiskGrid" ShowGroupPanel="False" runat="server" AutoGenerateColumns="False"
DataSourceID="OdsRiskOpportunityDataSource" GridLines="None" OnItemCommand="BusinessRiskGrid_ItemCommand"
Skin="Windows" AllowSorting="True" OnItemDataBound="BusinessRiskGrid_ItemDataBound"
GroupingEnabled="true" EnableAJAX="true" EnableAJAXLoadingTemplate="true" LoadingTemplateTransparency="25">
<ExportSettings>
<Pdf PageWidth="8.5in" PageHeight="11in" PageTopMargin="" PageBottomMargin="" PageLeftMargin=""
PageRightMargin="" PageHeaderMargin="" PageFooterMargin=""></Pdf>
</ExportSettings>
<MasterTableView AllowAutomaticInserts="True" AllowAutomaticUpdates="True" CommandItemDisplay="Bottom"
DataSourceID="OdsRiskOpportunityDataSource" EditMode="InPlace" DataKeyNames="Id">
<GroupByExpressions>
<radG:GridGroupByExpression>
<SelectFields>
<radG:GridGroupByField FieldAlias="IsRisk" FieldName="IsRisk"></radG:GridGroupByField>
</SelectFields>
<GroupByFields>
<radG:GridGroupByField FieldName="IsRisk"></radG:GridGroupByField>
</GroupByFields>
</radG:GridGroupByExpression>
</GroupByExpressions>
<CommandItemTemplate>
<table width="100%">
<tr>
<td width="50%">
<asp:LinkButton ID="AddNewLink" runat="server" CommandName="InitInsert">
<img style="border:0px" alt="" src="Image/Insert.gif" /> Add new Record</asp:LinkButton>
</td>
<td width="50%" align="right">
<asp:HyperLink ID="PrintLink" runat="server" NavigateUrl="http://172.24.27.157/ReportserverDEV?%2fBLL+MRP%2fBusiness+Plan+Status&amp;period=20071101&amp;hierarchy=838&amp;businessArea=6">
<img style="border:0px" alt="" src="Image/Insert.gif"/> Print
</asp:HyperLink>
</td>
</tr>
</table>
</CommandItemTemplate>
<Columns>
<%--Issue Detail --%>
<radG:GridTemplateColumn DataField="IssueDetail" HeaderText="Issue Details" SortExpression="IssueDetail"
UniqueName="IssueDetail" ItemStyle-Width="5pc">
<EditItemTemplate>
<asp:TextBox ID="IssueDetailTextBox" runat="server" Text='<%# Bind("IssueDetail")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="IssueDetailRequiredFieldValidator" ControlToValidate="IssueDetailTextBox"
Display="Dynamic" ErrorMessage="* This field is required" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="IssueDetailLabel" runat="server"><%# Eval("IssueDetail")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--Business Unit--%>
<%--
<radG:GridDropDownColumn DataField="BusinessUnitId" DataSourceID="BusinessUnitDataSource"
HeaderText="Business Unit" ListTextField="Lookup_Value" ListValueField="BusinessUnitId"
UniqueName="BusinessUnitId">
</radG:GridDropDownColumn>
--%>
<%--Reporting Currency --%>
<radG:GridDropDownColumn DataField="Reporting_Currency_SKEY" DataSourceID="ReportingCurrencyDataSource"
ItemStyle-Width="5pc" HeaderText="Reporting Currency" ListTextField="Currency_Name"
ListValueField="Reporting_Currency_SKEY" UniqueName="Reporting_Currency_SKEY"
Groupable="True" GroupByExpression="Reporting_Currency_SKEY Group By Reporting_Currency_SKEY">
</radG:GridDropDownColumn>
<%--PBT--%>
<radG:GridTemplateColumn DataField="PBT" HeaderText="PBT" UniqueName="PBT" SortExpression="PBT"
ItemStyle-Width="1pc">
<EditItemTemplate>
<asp:TextBox ID="PBTTextBox" runat="server" Text='<%# Bind("PBT", "{0:N1}")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="PBTRequiredFieldValidator" ControlToValidate="PBTTextBox"
ErrorMessage="* This field is required" runat="server" Display="Dynamic" />
<asp:RegularExpressionValidator ID="PBTRegularExpressionValidator" ControlToValidate="PBTTextBox"
ValidationExpression="-{0,1}\d*\.{0,1}\d{0,1}" ErrorMessage="* You must enter a valid value (1 decimal place)"
runat="server" Display="Dynamic" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="PBTLabel" runat="server"><%# Eval("PBT", "{0:N1}")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--PAT--%>
<radG:GridTemplateColumn DataField="PAT" HeaderText="PAT" UniqueName="PAT" SortExpression="PAT"
ItemStyle-Width="1pc">
<EditItemTemplate>
<asp:TextBox ID="PATTextBox" runat="server" Text='<%# Bind("PAT", "{0:N1}")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="PATRequiredFieldValidator" ControlToValidate="PATTextBox"
ErrorMessage="* This field is required" runat="server" Display="Dynamic" />
<asp:RegularExpressionValidator ID="PATRegularExpressionValidator" ControlToValidate="PATTextBox"
ValidationExpression="-{0,1}\d*\.{0,1}\d{0,1}" ErrorMessage="* You must enter a valid value (1 decimal place)"
runat="server" Display="Dynamic" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="PATLabel" runat="server"><%# Eval("PAT","{0:N1}")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--Probability--%>
<radG:GridTemplateColumn DataField="Probability" HeaderText="% Probability" UniqueName="Probability"
SortExpression="Probability" ItemStyle-Width="5pc">
<EditItemTemplate>
<asp:TextBox ID="ProbabilityTextBox" runat="server" Text='<%# Bind("Probability")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="ProbabilityRequiredFieldValidator" ControlToValidate="ProbabilityTextBox"
ErrorMessage="* This field is required" runat="server" Display="Dynamic" />
<asp:RegularExpressionValidator ID="ProbabilityRegularExpressionValidator" ControlToValidate="ProbabilityTextBox"
ValidationExpression="-{0,1}\d*\.{0,1}\d{0,1}" ErrorMessage="* You must enter a numeric value" runat="server"
Display="Dynamic" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="ProbabilityLabel" runat="server"><%# Eval("Probability", "{0}%")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--Commentary--%>
<radG:GridTemplateColumn DataField="Commentary" HeaderText="Commentary" SortExpression="Commentary"
UniqueName="Commentary" ItemStyle-Width="5pc">
<EditItemTemplate>
<asp:TextBox ID="CommentaryTextBox" runat="server" Text='<%# Bind("Commentary")%>' />
<span style="color: Red"></span>
<asp:RequiredFieldValidator ID="CommentaryRequiredFieldValidator" ControlToValidate="CommentaryTextBox"
Display="Dynamic" ErrorMessage="* This field is required" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="CommentaryLabel" runat="server"><%# Eval("Commentary")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<%--Person Responsible --%>
<radG:GridTemplateColumn DataField="Person_Responsible_Id" UniqueName="PersonResponsible"
HeaderText="Person Responsible" SortExpression="Person_Responsible_Id">
<EditItemTemplate>
<asp:DropDownList ID="PersonResponsible" runat="server" SelectedValue='<%# Bind("Person_Responsible_Id") %>'>
<asp:ListItem Value="0" Text="" />
<asp:ListItem Value="1" Text="David Klein" />
<asp:ListItem Value="2" Text="Andrew Muller" />
<asp:ListItem Value="3" Text="Damien Herslet" />
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="dtLabel1" runat="server" Text='<%# Eval("PersonName") %>' />
</ItemTemplate>
</radG:GridTemplateColumn>
<radG:GridTemplateColumn DataField="ResolutionDate" DataType="System.DateTime" HeaderText="Resolution Date"
SortExpression="ResolutionDate" UniqueName="ResolutionDate" ForceExtractValue="Always">
<EditItemTemplate>
<radCln:RadDatePicker ID="ResolutionDateDatePicker" runat="server" DbSelectedDate='<%# Bind("ResolutionDate") %>'>
</radCln:RadDatePicker>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="ResolutionDateLabel" runat="server"><%# Eval("ResolutionDate", "{0:d}")%></asp:Label>
</ItemTemplate>
</radG:GridTemplateColumn>
<radG:GridTemplateColumn DataField="Status_Lookup_SKEY" UniqueName="Status" HeaderText="Status"
SortExpression="Status_Lookup_SKEY">
<EditItemTemplate>
<asp:DropDownList ID="Status" runat="server" DataSourceID="StatusDataSource" DataTextField="Lookup_Value"
DataValueField="Lookup_SKEY" SelectedValue='<%# Bind("Status_Lookup_SKEY") %>'>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Image ID="Image1" runat="server" ImageAlign="Middle" ImageUrl='<%# Eval("StatusImageURL") %>' />
</ItemTemplate>
</radG:GridTemplateColumn>
<radG:GridTemplateColumn DataField="Period_Date_SKEY" HeaderText="Period_Date_SKEY"
UniqueName="Period_Date_SKEY" Visible="false">
<EditItemTemplate>
<asp:Label ID="PeriodDateLabel" runat="server" Text='<%# Bind("Period_Date_SKEY")%>' />
</EditItemTemplate>
</radG:GridTemplateColumn>
<radG:GridTemplateColumn DataField="IsRisk" HeaderText="IsRisk" UniqueName="IsRisk"
Groupable="True" GroupByExpression="IsRisk Group By IsRisk" Visible="False">
<ItemTemplate>
<asp:Label ID="IsRiskLabel" runat="server" Text='<%# Eval("IsRisk")%>' />
</ItemTemplate>
<EditItemTemplate>
<asp:Label ID="IsRiskLabel" runat="server" Text='<%# Eval("IsRisk")%>' />
</EditItemTemplate>
</radG:GridTemplateColumn>
<radG:GridEditCommandColumn UniqueName="Edit" ButtonType="ImageButton">
</radG:GridEditCommandColumn>
</Columns>
</MasterTableView>
<ClientSettings AllowDragToGroup="True">
<Resizing AllowColumnResize="True" EnableRealTimeResize="True" />
</ClientSettings>
</radG:RadGrid>
</div>
</form>
</body>
</html>




using System;
using System.Collections.Specialized;
using ddkonline.MRP.Service;
using ddkonline.MRP.Service.Persistence.Entity;
using Microsoft.Practices.Web.UI.WebControls;
using Telerik.WebControls;
using ddkonline.MRP.Global;

namespace ddkonline.MRP.Client
{
/// <summary>
/// Risk Management page
/// </summary>
public partial class RiskOpportunity : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
}

/// <summary>
/// Defaults the newly inserted items
/// </summary>
/// <param name="sender">Default event sender</param>
/// <param name="e">Grid command event arguments</param>
protected void BusinessRiskGrid_ItemCommand(object sender, GridCommandEventArgs e)
{
//// Default values for the items to insert in grid
//// http://www.telerik.com/community/forums/thread/b311D-emgdc.aspx
if (e.CommandName == RadGrid.InitInsertCommandName)
{
e.Canceled = true;
ListDictionary newValues = new ListDictionary();
newValues["IssueDetail"] = string.Empty;
newValues["Commentary"] = string.Empty;
newValues["BusinessUnitId"] = 871;
newValues["Reporting_Currency_SKEY"] = 0;
newValues["PBT"] = 0;
newValues["PAT"] = 0;
newValues["Probability"] = 0;
newValues["CreatedOn"] = DateTime.Now;
newValues["ModifiedOn"] = DateTime.Now;
newValues["ResolutionDate"] = null;
newValues["Person_Responsible_Id"] = 0;
newValues["Period_Date_SKEY"] = Controller.Current_Period;
newValues["Status_Lookup_SKEY"] = Constant.ON_TRACK;
e.Item.OwnerTableView.InsertItem(newValues);
}
}
/// <summary>
/// Handles the insert of an Item and Saves via partial method in the LINQ Entity (via a Service wrapper class)
/// </summary>
/// <param name="sender">Default event sender</param>
/// <param name="e">Object container event arguments</param>
protected void OdsRiskOpportunityDataSource_Inserted(
object sender, ObjectContainerDataSourceStatusEventArgs e)
{
ODS_Risk_Opportunity RiskOpportunity = (ODS_Risk_Opportunity)e.Instance;

// Set audit attributes
RiskOpportunity.CreatedOn = DateTime.Now;
RiskOpportunity.CreatedBy = Context.User.Identity.Name;
RiskOpportunity.ModifiedOn = DateTime.Now;
RiskOpportunity.ModifiedBy = Context.User.Identity.Name;
RiskOpportunity.Original_Risk_Opportunity_Id = 0;
//RiskOpportunity.Business_Area_Lookup_SKEY = GetBusinessAreaId(Controller.Current_BusinessArea);
RiskOpportunity.Business_Hierarchy_PC_SKEY = Controller.Current_BusinessHierarchy;
RiskOpportunityService.Save(RiskOpportunity);
}

/// <summary>
/// Handles the update of an Item
/// </summary>
/// <param name="sender">Default event sender</param>
/// <param name="e">Object container event arguments</param>
protected void OdsRiskOpportunityDataSource_Updated(
object sender, ObjectContainerDataSourceStatusEventArgs e)
{
ODS_Risk_Opportunity RiskOpportunity = (ODS_Risk_Opportunity)e.Instance;
// Set audit attributes
RiskOpportunity.ModifiedOn = DateTime.Now;
RiskOpportunity.ModifiedBy = Context.User.Identity.Name;
//RiskOpportunity.Business_Area_Lookup_SKEY = GetBusinessAreaId(Controller.Current_BusinessArea);
RiskOpportunity.Business_Hierarchy_PC_SKEY = Controller.Current_BusinessHierarchy;
RiskOpportunityService.Save(RiskOpportunity); ;
}

protected void OdsRiskOpportunityDataSource_Selecting(object sender, ObjectContainerDataSourceSelectingEventArgs e)
{
OdsRiskOpportunityDataSource.DataSource = RiskOpportunityService.GetAllFiltered(Controller.Current_BusinessHierarchy, Controller.Current_BusinessArea, Controller.Current_Period);
}

protected void BusinessUnitDataSource_Selecting(object sender, System.Web.UI.WebControls.LinqDataSourceSelectEventArgs e)
{
e.WhereParameters["ETL_Region"] = Controller.Current_BusinessHierarchy;
//e.SelectParameters. ["ETL_Region"]
//BusinessUnitDataSource.SelectParameters. = Controller.Current_BusinessHierarchy;
}

protected void BusinessRiskGrid_ItemDataBound(object sender, GridItemEventArgs e)
{
//Render Correct Header (RISK/OPPORTUNITY) on ItemDataBound of Telerik Grid.
if (e.Item is GridGroupHeaderItem)
{
GridGroupHeaderItem item = (GridGroupHeaderItem)e.Item;
System.Data.DataRowView groupDataRow = (System.Data.DataRowView)e.Item.DataItem;
item.DataCell.Text = Boolean.Parse(groupDataRow["IsRisk"].ToString()) ? "RISKS (enter -ve)" : "OPPORTUNITIES (enter +ve)";

//Calculations
//item.DataCell.Text += ((System.Decimal)groupDataRow["total"] / (int.Parse(groupDataRow["count"].ToString()))).ToString();
}
}
}
}

Thursday 13 December 2007

Problems Using Telerik Controls for inserts

I had an issue today using the Telerik RadGrid control (Version 5.0) to do inserts (edits work fine). If you don't initialize the fields in your control properly, you will get the following error:

DataBinding: 'Telerik.WebControls.GridInsertionObject' does not contain a property with the name 'Person_Responsible_Id'.

I don't think this is an ideal situation - the control should be smart enough to initialize its own fields - but the way around this is described here on the Telerik site:

http://www.telerik.com/help/aspnet/grid/?grdInsertingValuesUserControlFormTemplate.html



   1:  protected void RadGrid1_InsertCommand(object source, GridCommandEventArgs e)

   2:  {

   3:             GridEditableItem editedItem = e.Item as GridEditableItem;

   4:             UserControl userControl = (UserControl)e.Item.FindControl(GridEditFormItem.EditFormUserControlID);

   5:   

   6:             //Create new row in the DataSource

   7:             DataRow newRow = this.Employees.NewRow();

   8:   

   9:             //Insert new values

  10:             Hashtable newValues = new Hashtable();

  11:   

  12:             newValues["Country"] = (userControl.FindControl("TextBox7") as TextBox).Text;

  13:             newValues["City"] = (userControl.FindControl("TextBox8") as TextBox).Text;

  14:             newValues["Region"] = (userControl.FindControl("TextBox9") as TextBox).Text;

  15:             newValues["HomePhone"] = (userControl.FindControl("TextBox10") as TextBox).Text;

  16:             newValues["BirthDate"] = (userControl.FindControl("TextBox11") as TextBox).Text;

  17:             newValues["TitleOfCourtesy"] = (userControl.FindControl("ddlTOC") as DropDownList).SelectedItem.Value;

  18:   

  19:             newValues["Notes"] = (userControl.FindControl("TextBox1") as TextBox).Text;

  20:             newValues["Address"] = (userControl.FindControl("TextBox6") as TextBox).Text;

  21:             newValues["FirstName"] = (userControl.FindControl("TextBox2") as TextBox).Text;

  22:             newValues["LastName"] = (userControl.FindControl("TextBox3") as TextBox).Text;

  23:             newValues["HireDate"] = (userControl.FindControl("Textbox5") as TextBox).Text;

  24:             newValues["Title"] = (userControl.FindControl("TextBox4") as TextBox).Text;

  25:   

  26:             //make sure that unique primary key value is generated for the inserted row

  27:             newValues["EmployeeID"] = (int)this.Employees.Rows[this.Employees.Rows.Count - 1]["EmployeeID"] + 1;

  28:             try

  29:             {

  30:                 foreach (DictionaryEntry entry in newValues)

  31:                 {

  32:                     newRow[(string)entry.Key] = entry.Value;

  33:                 }

  34:                 this.Employees.Rows.Add(newRow);

  35:                 this.Employees.AcceptChanges();

  36:             }

  37:             catch (Exception ex)

  38:             {

  39:                 RadGrid1.Controls.Add(new LiteralControl("Unable to update/insert Employees. Reason: " + ex.Message));

  40:                 e.Canceled = true;

  41:             }

  42:  }

Tuesday 11 December 2007

Tip - Making your LINQ datasource do all the work for you

One of the important things to remember when trying to get your LINQ datasources to do 2-way binding is to set the "EnableInsert" and "EnableUpdate" attributes to true. Otherwise, nothing will be inserted/updated when you click on the Edit/Insert link in your bound control (e.g. Telerik RadGrid)



   1:      <asp:LinqDataSource ID="OdsRiskManagementDataSource" runat="server" 
   2:          ContextTypeName="LendLease.MRP.Service.Persistence.Entity.MRPDataContext" EnableUpdate="true" EnableInsert="true"    
   3:          TableName="ODS_Risk_Managements">
   4:      </asp:LinqDataSource>    

Monday 10 December 2007

Dynamic Queries in LINQ

Dynamic queries are usually used in search screens where the search criteria is optional. This illustrates how to create dynamic queries.

Dynamic Queries

The following code creates a dynamic query:
1.MyDataContext context = new MyDataContext();
2.var query = from customer in context.Customers select customer;
3.var filteredQuery = (from customer in query where customer.ID == newCustomerID select customer).ToList();

This is how it works:
1. Create a new context to query
2. Creates the first part of the query
3. Adds further criteria to the original query, paying attention to the bold part in line 3, where we extend the query variable.

Saturday 1 December 2007

Web Client Software Factory and Dependency Injection

The Web Client Software Factory is a combination of frameworks to give any .NET web app a head start using the Model View Presenter pattern and the Microsoft Enterprise Library for things such as Error handling policies and Logging. In this way you can be assured that you are starting with a bedrock that is fully testable and refactored. It also provides guidance with real-life samples to get you up and running. We have a team that have built a common framework for the Lend Lease .NET development team based on the WCSF, using LINQ as well in VS 2008.

I looked at using this for my last project at Pfizer - but the project didn't give us the luxury of learning and adapting this framework on the job. We now have the support of Lend Lease to develop this framework which is fantastic.

One issue is that the "recipes" that generate the stubs for different modules don't work with 2008 (even though the code compiles). There are hacks to get the WCSF working in 2008 - but we are just having the team leads of the different projects generating these stubs in 2005 for the other developers.

One of the techniques that the Web Client Software Factory relies upon is
dependency injection. A good description of it can be found here:
http://webclientsoftwarefactory.blogspot.com/2007/08/what-is-dependency-injection.html