Infosys Microsoft Alliance and Solutions blog

« June 2008 | Main | August 2008 »

July 14, 2008

If everything could be hosted!

Today the buzz world in IT segment is “hosting” and “SaaS” where the clients can convert their CAPEX into OPEX and can use the application on a ‘pay as you use’ basis. Every vendor and service provider is joining the bandwagon to provide these services. The market segment for hosted services is huge, as the market says and there are sufficient buyers of the same. However, the segment, the type, the service, the criticality, the business type and the long term plan should be considered before weighing this option. Though it is a quick solution to implement, the acceptance of the processes, scalability and fitment is sometimes in question. It is widely known that plain-vanilla hosting is a low-margin, commodity business and unless you are the product company, you would not do it! The concept of S+S (Software + Service) as propagated by Microsoft takes a step beyond SaaS to describe the importance of System Integrators and ISVs in this emerging (if not already emerged) ecosystem.

Typically in any business there are ‘critical’, ‘essential’ and ‘critically-essential’ aspects. Each business function can fit into one of them and in case there is any business function that is not fitting into any one of them, then it’s not the business in which the company should be. Typically the company can relinquish control over the applications that are under the ‘essential’ category. These are important for running the business, but may not be directly linked to criticality of business operations. Office Productivity applications, communication systems (email & communicator), content sharing are universal themes. Besides this certain functions around Supplier & vendor interaction, Customer relationship management, Human resources, recruitments, leave management can be on hosted applications depending on the criticality of these functions in the organization.

A logistics firm managing the cross-docking, warehousing and delivery aspects can’t have Supplier & vendor interaction in a hosted environment as it’s not essential, it’s critically essential. They can however have their HRM function on a hosted application including running the payroll. What this points out to is the fact that “One size fits all” is no longer the mantra in organizations who want a Tier-1 ERP/CRM package. The decision points are too complex to be generalized but can vary from business functions, criticality, stage in business cycle, dependencies on environment and not to forget the ‘context’.

I would like to talk about the ‘context’ aspect more. Today there should not be classification of an organization by size, number of employees, vertical and revenue alone – the added dimensions are its growth strategy, operational plan and geographical spread.

  • Growth Strategy – a company that is growing inorganically can’t afford to have on-premises installation by rolling out of the parent company ERP/CRM platform. This would be expensive, time consuming and lack sponsorship in the initial years of eth acquisition or merger as the business priorities would be towards assimilating the cultures before assimilating the systems. The true benefit of the ERP/CRM would be achieved when the organizational harmonization is complete. However, in this time organization would be looking at either a quick fix hosted solution to meet over the immediate business needs or can be looking at a leaner ERP/CRM system which can integrate with the Hub (Parent Company) in an industry standard “Hub & Spoke” Model. System Integrators can play a major role here in understanding the business realities and suggesting suitable option to such clients.
  • Operation Plan – a company’s operational plan can help in deciding the application landscape as well. In today’s world there are companies that focus only on their core competencies and outsource all their other functions. The outsourcing partners who are providing such services can look at hosted solutions for servicing their end clients. The company that is outsourcing the operations would in this case like to retain the ownership of critical and critically essential services by having in-premises installation
  • Geographical Spread - Companies are today spreading their operations across the globe and doing so they are always faced with new and even more challenging country laws, legal requirements, compliance needs, tax structures, labor laws, economic variables, best practices and reporting needs. This has led to focus on “Thinking Global and Acting Local” philosophy. The needs of the country in which the operation is being spread can’t be overlooked. The parent companies also want to have some business return before pulling the company into the corporate ERP/CRM systems. This makes the case stronger for an application which can be hosted and the company pays as per use. The other option is again to have a leaner application which can be implemented faster and then integrated back with the Hub system.

Microsoft has been investing hugely in the hosting space with CRM and business productivity applications already being rolled out and communicated to the partners through its annual partner event. I had a chance to look at an article which was an extract taken from Ovum's Straight Talk service at - http://www.ovum.com/news/euronews.asp?id=7155

There were 2 paragraphs which were very relevant with above discussions.

One of the new enterprise subscription suites that Microsoft announced this week is aimed at “deskless” workers that have only sporadic computer access. The Deskless Worker Suite has two components. One, called Exchange Online Deskless Worker, is based on Exchange Server and provides email (via the Outlook Web Access online email client), calendar, global address lists and malware filters. The other, called SharePoint Online Deskless Worker, is based on SharePoint Server and provides access to portal and team sites and search functionality so that employees can find information on such things as benefits, training programs and company policies. Customers can subscribe to both services for $3 per user per month, or to either one alone. The other new subscription offering, called the Business Productivity Online Suite, allows employers to provide new capabilities to information workers without paying large upfront fees for traditional software licenses. This offering includes Exchange Online, SharePoint Online, Office Communications Online (for instant messaging and presence capabilities) and Office Live Meeting for web- and video-conferencing. This suite will be priced at $15 per user per month, though Microsoft will also offer the components individually.

Microsoft says it is committed to helping partners succeed; after all, it depends on them for some 96% of its revenues. To that end, it describes a number of ways in which partners can leverage the new model: they can address new customers with large populations of deskless workers (such as nurses, flight attendants and factory workers); they can sell new subscription services to existing customers; and they can increase sales velocity by leveraging the fact that online solutions can be deployed instantly, avoiding the weeks or months it could take to build and run a pilot solution Key to partners' success, however, will be their ability to provide some additional value on top of the plain-vanilla hosted solution - perhaps by helping customers migrate from other platforms or, often, by customizing the subscription services for the particular industries they serve

The need of the day is that the partners in the ecosystem take this up as an opportunity to use the experience in their on-premise installations and gain from the service revenues that can come in with this new paradigm. Although with this strategy Microsoft themselves are treading into Partner’s territory, I am sure it would still ensure benefit in the long run if the partners see the opportunity across the ‘critical’, ‘essential’ and ‘critically-essential’ aspects of any business and where they can have a play.

July 10, 2008

Silverlight - Preventing direct editing in DatePicker control

In my earlier blog I mentioned about the custom DatePicker control. Towards the end where I mentioned about making the textbox read only, I also mentioned about not being able to edit this template in Expression Blend 2.5 June CTP. On the forums, someone clarified that since this control doesn't resides in System.Windows.dll, its template cannot be edited in current version of Blend.

One can however include the template as mentioned in MSDN and include that in the project and modify suitably. When I included that in a test project, I ended up with System.Stack.OverflowException. That can however be fixed easily as I mentioned here.

Not only this, using this template, causes many other warnings/errors in VS and Expression also no longer shows the design time view of the control. Though, surprisingly, after fixing the stack overflow exception, I was able to run the code inspite of the many issues shown by VS.

Going back to my custom control, I first thought to add the template to the control and then make the textbox (which is actually DatePickerTextBox) as read only. However, I continued to face more issues in this.

Lutz Roeder's Reflector, as always, came to the rescue and I got an idea after looking at the implementation of OnApplyTemplate in the DatePicker control. The idea was to extract the DatePickerTextBox and then set it's property in code. To do this, I first added another property to my control (see the code so far in the previous blog)

        private bool _directEdit;

        public bool IsDirectEditingAllowed

        {

            get { return _directEdit; }

            set

            {

                _directEdit = value;

                if (_box != null)

                    _box.IsReadOnly = !value;

            }

        }

The _box variable is the DatePickerTextBox control that is set as part of the template and I obtain it as follows.

        public override void OnApplyTemplate()

        {

            base.OnApplyTemplate();

            _box = base.GetTemplateChild("TextBox") as DatePickerTextBox;

            if (_box != null)

                _box.IsReadOnly = !IsDirectEditingAllowed;

        }

I need to handle the setting of the IsReadOnly property on the DatePickerTextBox both when applying the template and when changing the IsDirectEditingAllowed property. With this, I can now set the property to false and thus make date selection possible only by using the calendar control. This addresses the issue of user making changes to the control directly by typing into it and thus impacting the values set using DisplayStartDate property.

For your reference, find the complete code for the custom DatePicker control below.

using System;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Ink;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.IO;

using System.Windows.Markup;

using System.Diagnostics;

using System.Globalization;

 

namespace Atul.Utilities

{

    public class StartDatePicker : DatePicker

    {

        DateTime _prevStartDate, _prevEndDate;

        DatePickerTextBox _box = null;

 

        public StartDatePicker()

        {

            MinimumDifferenceWithEndDate = 1; // default to 1 day

            IsInitializedToToday = true;

            RetainDifferenceOnDateChange = true;

            IsDirectEditingAllowed = true;

            this.Loaded += new RoutedEventHandler(StartDatePicker_Loaded);

            this.SelectedDateChanged += new EventHandler<SelectionChangedEventArgs>(StartDatePicker_SelectedDateChanged);

        }

 

        /// <summary>

        /// Use this to get the DatePickerTextBox control and set its IsReadOny property. Needless to say

        /// that this will not work if the template is modified completely to not use DatePickerTextBox or

        /// it is used but with a different name

        /// </summary>

        public override void OnApplyTemplate()

        {

            base.OnApplyTemplate();

            _box = base.GetTemplateChild("TextBox") as DatePickerTextBox;

            if (_box != null)

                _box.IsReadOnly = !IsDirectEditingAllowed;

        }

 

        /// <summary>

        /// If set to True, control will default to today's date. If set to False, it will remain blank and use the

        /// DatePicker's default value The default value for this control is True

        /// </summary>

        public bool IsInitializedToToday { get; set; }

 

        /// <summary>

        /// This is a bit tricky to explain :-). As the start date is changed, the difference between it and end

        /// date changes. Now this should always be at a minimum of the value set using MinimumDifferenceWithEndDate.

        /// However take a case that the user has set the start date as today and explicitly end date as 20

        /// days from today (and minimum is 1). Now the user comes back and changes the start date to

        /// today + 30 days. This causes the end date to be invalid. So if this property is set, we will automatically

        /// reset the end date to today + 30 + 20, thus retaining the earlier difference set by the user. An

        /// interesting point here is that this reset will trigger only if the difference is lower than mini days

        /// set using the MinimumDifferenceWithEndDate property since otherwise the end date isn't invalid.

        /// So If the user had reset to today + 15, the end date would have remained as is

        /// </summary>

        public bool RetainDifferenceOnDateChange { get; set; }

 

        private bool _directEdit;

        /// <summary>

        /// Set this property appropriately to allow or not allow user to be able to directly type into the

        /// text box of DatePicker control

        /// </summary>

        public bool IsDirectEditingAllowed

        {

            get { return _directEdit; }

            set

            {

                _directEdit = value;

                if (_box != null)

                    _box.IsReadOnly = !value;

            }

        }

 

        private int _minDiff;

        /// <summary>

        /// Get or Set # days difference that should be maintained between Start and End dates

        /// </summary>

        public int MinimumDifferenceWithEndDate

        {

            get { return _minDiff; }

            set

            {

                if (value < 0)

                    return; //should possibly throw an exception like out of range here

 

                _minDiff = value;

            }

        }

 

        private DatePicker _endDtControl = null;

        public DatePicker EndDatePicker

        {

            get { return _endDtControl; }

            set

            {

                if (value != null)

                {

                    _endDtControl = value;

                    _endDtControl.Loaded += new RoutedEventHandler(_endDtControl_Loaded);

                    _endDtControl.SelectedDateChanged += new EventHandler<SelectionChangedEventArgs>(_endDtControl_SelectedDateChanged);

                }

            }

        }

 

        private void StartDatePicker_Loaded(object sender, RoutedEventArgs e)

        {

            if (IsInitializedToToday)

            {

                DateTime today = DateTime.Today;

                _prevStartDate = today;

                this.DisplayDateStart = this.SelectedDate = today;

            }

        }

 

        void StartDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e)

        {

            if (_endDtControl != null && (_endDtControl.SelectedDate.HasValue))

            {

                DateTime dt = this.SelectedDate.Value;

                if (_endDtControl.SelectedDate.Value.Subtract(dt).Days < MinimumDifferenceWithEndDate)

                {

                    if (RetainDifferenceOnDateChange)

                    {

                        //reset the End date based on earlier date difference

                        TimeSpan diff = _prevEndDate.Subtract(_prevStartDate);

                        _endDtControl.SelectedDate = dt.AddDays(diff.Days);

                    }

                    else

                    {

                        _endDtControl.SelectedDate = dt.AddDays(MinimumDifferenceWithEndDate);

                    }

                }

                //the display start date for the end date control should be altered based on current selected start date

                //and should always be more than it by the factor of MinimumDifferenceWithEndDate

                _endDtControl.DisplayDateStart = dt.AddDays(MinimumDifferenceWithEndDate);

            }

            _prevStartDate = this.SelectedDate.Value;

        }

 

        void _endDtControl_Loaded(object sender, RoutedEventArgs e)

        {

            //initialize various values, based on today's date and mini difference

            _endDtControl.DisplayDateStart = _endDtControl.SelectedDate = _prevEndDate = DateTime.Today.AddDays(MinimumDifferenceWithEndDate);

        }

 

        /// <summary>

        /// Preview Selection changed would have been better, but since it isn't supported, we will work with

        /// Selected Date Changed event itself. The event fires twice for some reason i can't currently trace !

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        void _endDtControl_SelectedDateChanged(object sender, SelectionChangedEventArgs e)

        {

            //selection has changed, update the stored date. however ensure that is respects

            //MinimumDifferenceWithEndDate value

            TimeSpan diff = _endDtControl.SelectedDate.Value.Subtract(this.SelectedDate.Value);

            if (diff.Days < MinimumDifferenceWithEndDate)

            {

                //reject change and reset to previous date. We have previous date stored in _prevEndDate, but it

                //is also available as part of the event argument

                _endDtControl.SelectedDate = (DateTime)e.RemovedItems[0]; // this will cause this event to fire again !

            }

            else

            {

                _prevEndDate = _endDtControl.SelectedDate.Value;

            }

        }

    }

}

Comments welcome !

WPF - Text clips on some Vista machines

I love mysteries. So when a project team approached me the other day with an issue with their WPF application, I immediately jumped into it. The issue they were facing was really mysterious. Their WPF application was working and looking fine on all their Vista machines, but when shared with Client, it started to have problems. Text in some controls was clipping.

After trying on multiple machines locally, they found 1 Vista machine where the problem was reproduced. The mystery was that all these machines were using same resolution (1024x768), same dpi (96) and same theme, but text would clip on that 1 machine and work fine on all others. They were about to write this off claiming some issue with Vista.

Vista may have its share of issues which has caused many people to write about the same, but when programming, I take a different route. I always suspect my own code till proven otherwise. I asked the team to share snapshots of the application from the two machines showing me where the issue was happening and on careful examination of them, I figured out that the font on the machine on which the issue was visible was wider than the one on which things were working fine.

Most controls of the application were looking fine on both machines and it was an issue with only few of them. This pointed towards possible issue in XAML and how the fonts were assigned. In WPF, the controls inherit font from parent container and hence if you don’t set the font, it will use the Vista’s default Segoe UI font. I asked for XAML of on the screens where the issue was being seen and a search in the file revealed that for some controls where they had set the font to be bold and larger in size, the font family property was also set and this was set to Segoe.

Now if you have seen both Segoe and Segoe UI, you will realize that Segoe is narrower of the two, as is also seen in the picture below. The lower controls in the pair are using Segoe font, while the upper ones are using Segoe UI.

FontIssue.jpg

With this information, when we relooked at the culprit machine, we realized that it didn’t had the Segoe font and hence the control’s were falling back on Segoe UI and this caused the text to take more space and thus was clipping. If, in code, the FontFamily property had not been set, things would have worked properly in all machines and the team would have already ensured right sizing of the controls.

Interesting, when working with Expression Blend, not all controls display this difference clearly at design time (works fine in VS design time). The application window seen on the right side in above figure is what is seen in Blend (2.5 June CTP) and you can clearly see that the TextBlock (top pair of controls) both appear to be exactly the same, though at run time (left application window) you can see the difference clearly.

July 9, 2008

Silverlight - Handling Start and End dates with Custom DatePicker Control

When working with DatePicker controls in application, very typically they get used to manage start and end dates. Like recently I was writing a tracking application in Silverlight and had the need to manage allocation and deallocation and hence start and end dates. There are typical requirements also associated with such implementations like start date cannot be in past, end date cannot be before start date.

Implementing this with Silverlight DatePicker controls was fairly trivial. If you haven't used these controls, you can find an introduction to them here. These controls also offer other interesting properties that I played with namely DisplayStartDate. I then thought that some of things I did in the logic, would be useful in multiple scenarios, so why not create a new custom DatePicker control that will have these functionalities in-built.

Creating custom controls is again pretty straightforward. Start by inheriting from the control you want to extend and then implement the necessary set of properties and methods required. Note that this is primarily the logic extension. For extending the UI, you will have to work with the templating features and Expression Blend will be a good tool for that. In my case, I am more interesting in the logic of the control and let the UI remain the same.

Some of the properties that I added to the control are as below. I added all these as regular CLR properties. If you need to support binding, these will have to be added as dependency properties.

IsInitializedToToday: The DatePicker does default's to today's date, but that is only set in the Calendar drop down. The textbox part of the control shows only the watermark (the date format) and the actual date is not displayed. To me this looks like a bug. Anyway, so I have added this property, which if set, will also show the current date in the textbox.

EndDateControl: This property points to the DatePicker control on the parent window that will be used to set the end date. This custom control itself will be acting as StartDate. Note that this property cannot be set in XAML and has to be set in code behind.

MinimumDifferenceWithEndDate: This property specifies what should be the minimum difference between start and end date. If this is say set to 5, and the start date is set to 10th, it will cause the End date to be set to dates beyond 15th. It appropriately changes the DisplayStartDate for the end date control (specified using EndDateControl property).

RetainDifferenceOnDateChange: This is a bit tricky to explain :-). As the start date is changed, the difference between it and end date changes. Now this should always be at a minimum of the value set using MinimumDifferenceWithEndDate. However take a case that the user has set the start date as today and explicitly end date as 20 days from today (and minimum difference is 1). Now the user comes back and changes the start date to today + 30 days. This causes the end date to be invalid. So if this property is set, end date will be reset to today + 30 + 20, thus retaining the earlier difference set by the user. An interesting point here is that this reset will trigger only if the difference is lower than mini days set using the MinimumDifferenceWithEndDate property since otherwise the end date isn't invalid. So If the user had reset to today + 15, the end date would have remained as is.

Below is the custom DatePicker control code. Feel free to use this as you see fit in your work.

using System;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Ink;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace Atul.Utilities

{

    public class StartDatePicker : DatePicker

    {

        DateTime _prevStartDate, _prevEndDate;

 

        public StartDatePicker()

        {

            MinimumDifferenceWithEndDate = 1; // default to 1 day

            IsInitializedToToday = true;

            RetainDifferenceOnDateChange = true;

            this.Loaded += new RoutedEventHandler(StartDatePicker_Loaded);

            this.SelectedDateChanged += new EventHandler<SelectionChangedEventArgs>(StartDatePicker_SelectedDateChanged);

        }

 

        /// <summary>

        /// If set to True, control will default to today's date. If set to False, it will remain blank and use the

        /// DatePicker's default value The default value for this control is True

        /// </summary>

        public bool IsInitializedToToday { get; set; }

 

        /// <summary>

        /// This is a bit tricky to explain :-). As the start date is changed, the difference between it and end

        /// date changes. Now this should always be at a minimum of the value set using MinimumDifferenceWithEndDate.

        /// However take a case that the user has set the start date as today and explicitly end date as 20

        /// days from today (and minimum is 1). Now the user comes back and changes the start date to

        /// today + 30 days. This causes the end date to be invalid. So if this property is set, we will automatically

        /// reset the end date to today + 30 + 20, thus retaining the earlier difference set by the user. An

        /// interesting point here is that this reset will trigger only if the difference is lower than mini days

        /// set using the MinimumDifferenceWithEndDate property since otherwise the end date isn't invalid.

        /// So If the user had reset to today + 15, the end date would have remained as is

        /// </summary>

        public bool RetainDifferenceOnDateChange { get; set; }

 

        private int _minDiff;

        /// <summary>

        /// Get or Set # days difference that should be maintained between Start and End dates

        /// </summary>

        public int MinimumDifferenceWithEndDate

        {

            get { return _minDiff; }

            set

            {

                if (value < 0)

                    return; //should possibly throw an exception like out of range here

 

                _minDiff = value;

            }

        }

 

        private DatePicker _endDtControl = null;

        public DatePicker EndDatePicker

        {

            get { return _endDtControl; }

            set

            {

                if (value != null)

                {

                    _endDtControl = value;

                    _endDtControl.Loaded += new RoutedEventHandler(_endDtControl_Loaded);

                    _endDtControl.SelectedDateChanged += new EventHandler<SelectionChangedEventArgs>(_endDtControl_SelectedDateChanged);

                }

            }

        }

 

        private void StartDatePicker_Loaded(object sender, RoutedEventArgs e)

        {

            if (IsInitializedToToday)

            {

                DateTime today = DateTime.Today;

                _prevStartDate = today;

                this.DisplayDateStart = this.SelectedDate = today;

            }

        }

 

        void StartDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e)

        {

            if (_endDtControl != null && (_endDtControl.SelectedDate.HasValue))

            {

                DateTime dt = this.SelectedDate.Value;

                if (_endDtControl.SelectedDate.Value.Subtract(dt).Days < MinimumDifferenceWithEndDate)

                {

                    if (RetainDifferenceOnDateChange)

                    {

                        //reset the End date based on earlier date difference

                        TimeSpan diff = _prevEndDate.Subtract(_prevStartDate);

                        _endDtControl.SelectedDate = dt.AddDays(diff.Days);

                    }

                    else

                    {

                        _endDtControl.SelectedDate = dt.AddDays(MinimumDifferenceWithEndDate);

                    }

                }

                //the display start date for the end date control should be altered based on current selected start date

                //and should always be more than it by the factor of MinimumDifferenceWithEndDate

                _endDtControl.DisplayDateStart = dt.AddDays(MinimumDifferenceWithEndDate);

            }

            _prevStartDate = this.SelectedDate.Value;

        }

 

        void _endDtControl_Loaded(object sender, RoutedEventArgs e)

        {

            //initialize various values, based on today's date and mini difference

            _endDtControl.DisplayDateStart = _endDtControl.SelectedDate = _prevEndDate = DateTime.Today.AddDays(MinimumDifferenceWithEndDate);

        }

 

        /// <summary>

        /// Preview Selection changed would have been better, but since it isn't supported, we will work with

        /// Selected Date Changed event itself. The event fires twice for some reason i can't currently trace !

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        void _endDtControl_SelectedDateChanged(object sender, SelectionChangedEventArgs e)

        {

            //selection has changed, update the stored date. however ensure that is respects

            //MinimumDifferenceWithEndDate value

            TimeSpan diff = _endDtControl.SelectedDate.Value.Subtract(this.SelectedDate.Value);

            if (diff.Days < MinimumDifferenceWithEndDate)

            {

                //reject change and reset to previous date. We have previous date stored in _prevEndDate, but it

                //is also available as part of the event argument

                _endDtControl.SelectedDate = (DateTime)e.RemovedItems[0]; // this will cause this event to fire again !

            }

            else

            {

                _prevEndDate = _endDtControl.SelectedDate.Value;

            }

        }

    }

}

A few caveats
1. When DisplayStartDate is set, I would ideally expect to not be able to set dates before that date. This works fine if I am setting dates via the Calendar drop down. However, I can still go ahead and type any earlier date directly in the edit box. Interesting, this also causes the Calendar to now display dates all the way to this date. To me this looks like a bug in DatePicker control.

2. DatePicker doesn't display's today's date by default in the edit box, though the Calendar does this (already mentioned above). You need to do something like control.SelectedDate = DateTime.Today in code (constructor or loaded event handler) to get this to work correctly.

3. Based on point 1 above, let's say the user has set MinimumDifferenceWithEndDate as 5. When working with Calendar drop downs, this will be enforced, but user can directly type in a new date and this can break this setting. I did try to handle this by modifying the SelectedDateChanged handler as below, but for some reason the event seems to fire 4 times (I can understand twice, one due to direct edit and one due to my invoking SelectedDate). The end result is still what I want, but the event firing so many times obviously isn't right.

        void _endDtControl_SelectedDateChanged(object sender, SelectionChangedEventArgs e)

        {

            //selection has changed, update the stored date. however ensure that is respects

            //MinimumDifferenceWithEndDate value

            TimeSpan diff = _endDtControl.SelectedDate.Value.Subtract(this.SelectedDate.Value);

            if (diff.Days < MinimumDifferenceWithEndDate)

            {

                //reject change and reset to previous date. We have previous date stored in _prevEndDate, but it

                //is also available as part of the event argument

                _endDtControl.SelectedDate = (DateTime)e.RemovedItems[0]; // this will cause this event to fire again !

            }

            else

            {

                _prevEndDate = _endDtControl.SelectedDate.Value;

            }

        }

4. To address the direct editing issue, one option would be to edit the control template and make the edit box read only. That way the only way to enter date will be via the calendar drop down. To my surprise, when I tried to do this, I found the control template for DatePicker control to be empty. The template seems to be all built in code with no XAML based template being used. So right now, I don't have a solution of how to address this issue. If you know, please write back.

Finally to wrap up, I haven't done detailed testing on this and also there could be some more useful properties added to make this more functional. Do revert back with comments and I will be happy to make changes.

July 8, 2008

ASP.NET, ASP.NET AJAX and Silverlight - Which way would you go?

Want to develop a web application using Microsoft Technologies? The choice today will revolve around the mature ASP.NET, the upcoming ASP.NET AJAX or Silverlight (Beta 2 currently available). Needless to say that all have their benefits and specific features that make them attractive options to use.

Choice will also depend very much on if the application is internet or intranet facing, so let's talk about internet facing application. Both ASP.NET and ASP.NET AJAX are pretty much server side applications in that most of their logic resides on server side. 

In case of AJAX applications, there is some of the logic handled from client side as well. In case of Silverlight, the situation is a bit different. Essentially the code gets downloaded on the client side and is run from there and this can actually cause performance issues in the initial load time of the application.

Without getting into feature comparison, I would like to run a poll and see what you are thinking? If you were to build a new internet facing web application, what technology would you prefer to use?

July 4, 2008

Silverlight - Animating Wrap Panel

Panels, as we know, are pretty much the basis of building any Silverlight application. They help arrange the other Silverlight controls in specific manner like Stack allowing you to stack controls either horizontally or vertically, Grid allowing you to position controls in rows an columns and Canvas giving you a free flow behavior. This blog however isn't however a primer on panels and you can easily find information about them on the net. Check this for information on how to layout controls using these various panels.

At Mix 2008, in one of the sessions the AnimatingStackPanel was demonstrated. I found the code for the same here. I decided to go ahead and try this. However my requirement was for a wrap panel and not a stack panel. I found one here. This would serve my purpose but there wasn't any animation in it. In my earlier work with WPF, I had looked at Kevin's bag of tricks and liked the AnimatingTilePanel.

I hence wanted to get something like that for my Silverlight application. I did find one such animating wrap panel as part of HackingSilverlight Library. But this wasn't completely what I was looking for, for the reasons below

  1. The animation in this panel always happens from bottom of the control
  2. It happens every time i add a new control to the panel. So instead of just animating the new control (a feature that is present in Kevin's AnimatingTilePanel), it animates all the controls again.

For these two reasons, I decided to try and merge the wrap panel and animating panel code that i had found (see the links above). If you want to write you own custom panel, you can check this for a good introduction. I realized that the animating stack panel code was in VB but I always work with C#  (I don't even have VB.NET installed on my machine). I decided to convert the code to C# and used this free VB.NET to C# converter. There were a few additional issues that i had to fix in the AnimatingPanelBase c# code, like the usage of states Dictionary object, adding System.Collection.Generic and System.Windows.Threading namespaces. Apart from this class I also converted and included the Vector structure.

With these, I then changed the WrapPanel class as per my needs. Since I wanted to work with horizontally oriented panel, I did changes only to that part of the code and didnt' touch the one that handles the vertical orientation. The key changes were to change the base class to AnimatingPanelBase, add the AnimationCompleted event handler, and finally in ArrangeOverride function. I used the AnimatingStackPanel class from the original VB project as a reference to make the code changes here.

First I modified the ArrangeOverride to include the positioning of elements twice. However unlike the sample from Mix where the animation happened from bottom, I wanted it to work more like the way it happens in Kevin's AnimationTilePanel. So I modified the initial position for the child element accordingly to start from a location such that the X coordinate is minus of control's width. In the second pass, this would be set to the actual initial point.

I then modified the test program a bit so that i could dynamically add new controls and see how they would animate to their right position. With this basic change when I ran the code, the controls did animate from the top now, but every time I would add a new control, It would still cause all existing controls to reanimate. I looked at the code a bit but could not pin-point where to make changes. Running the application a few times, proposed the answer. I observed that if I would click the button quickly without letting the first animation to finish, the new control would add in the way I wanted and existing controls won't animate again. So I removed the animation completion handler and things fell in place. The modified WrapPanel class is as below

    public class WrapPanel : AnimatingPanelBase

    {

 

        public Orientation Orientation

        {

            get { return (Orientation)GetValue(OrientationProperty); }

            set { SetValue(OrientationProperty, value); }

        }

 

        public static readonly DependencyProperty OrientationProperty =

            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(WrapPanel), null);

 

        public WrapPanel()

        {

            // default orientation

            Orientation = Orientation.Horizontal;

        }

 

        protected override Size MeasureOverride(Size availableSize)

        {

            foreach (UIElement child in Children)

            {

                child.Measure(new Size(availableSize.Width, availableSize.Height));  

            }

            return availableSize;

        }

 

        protected override Size ArrangeOverride(Size finalSize)

        {

            Point point = new Point(0,0);

            int i = 0;

 

            if (Orientation == Orientation.Horizontal)

            {

                double largestHeight = 0.0;

 

                foreach (UIElement child in Children)

                {

                        SetElementLocation(child, new Rect(point, new Point(point.X + child.DesiredSize.Width, point.Y + child.DesiredSize.Height)));

 

                    if (child.DesiredSize.Height > largestHeight)

                        largestHeight = child.DesiredSize.Height;

 

                    point.X = point.X + child.DesiredSize.Width;

 

                    if ((i + 1) < Children.Count)

                    {

                        if ((point.X + Children[i + 1].DesiredSize.Width) > finalSize.Width)

                        {

                            point.X = 0;

                            point.Y = point.Y + largestHeight;

                            largestHeight = 0.0;

                        }

                    }

                    i++;

                }

            }

            else

            {

                double largestWidth = 0.0;

 

                foreach (UIElement child in Children)

                {

                    SetElementLocation(child, new Rect(point, new Point(point.X + child.DesiredSize.Width, point.Y + child.DesiredSize.Height)));

 

                    if (child.DesiredSize.Width > largestWidth)

                        largestWidth = child.DesiredSize.Width;

 

                    point.Y = point.Y + child.DesiredSize.Height;

 

                    if ((i + 1) < Children.Count)

                    {

                        if ((point.Y + Children[i + 1].DesiredSize.Height) > finalSize.Height)

                        {

                            point.Y = 0;

                            point.X = point.X + largestWidth;

                            largestWidth = 0.0;

                        }

                    }

                    i++;

                }

            }

            return finalSize;

        }

    }

However new controls were now appearing from top left corner and not from a position that is minus their width. I tried to make changes to the ArrangeOverride and realized that I can actually use a much simpler version. The animation still worked, but it was still happening from (0,0). I then started to dig into the AnimatingPanelBase class and finally hit upon the source of this issue. In the constructor of ElementState, the CurrentRect was being initialized to (0, 0). I modified this as below and with that finally got the wrap panel behaving in much similar manner as does Kevin's AnimatingTilePanel. Along wit this, another minor change to the constructor to handle if the animation is enabled for wrap panel or not as below and I was all set.

            public ElementState(Rect targetRect, double randomness, bool animationEnabled, )

            {

                if (animationEnabled)

                    CurrentRect = new Rect((targetRect.X - targetRect.Width), targetRect.Y, targetRect.Width, targetRect.Height);

                else

                    CurrentRect = targetRect;

 

                TargetRect = targetRect;

                LocationVelocity = new Vector(0, 0);

 

                SizeVelocity = new Vector(0, 0);

 

                AttractionMultiplier = (_Random.NextDouble() * randomness) + 0.4;

                NeedsArrange = false;

            }

The code is by no means handling all scenarios. Like I said, I haven't touched the vertical orientation part and also the code right now doesn't handle margins, padding, alignment and visibility etc. Some of that is handled in the code here.

Comments, welcome !

Silverlight - Are you missing WatermarkedTextBox?

One of controls that I had been using when working with SL 2 Beta 1 was WatermarkedTextBox and when this was taken off from SL 2 Beta 2, I had to rework our application code. It is great to see the control now posted on Kathy's blog here. The discussion seem to incidate that we won't get the updated TextBox with Watermark property in Silverlight 2 RTM.

I downloaded this, but wasn't able to use it as is since the code continues to use System.Windows.Controls.Extended assembly name. I was using other controls like Calendar and DatePicker from the released System.Windows.Controls.Extended assembly with SL2 and this caused conflict when trying to add the assembly for using WatermarkedTextBox. This was however easily fixed by changing the project properties to create the assembly with the name WatermarkedTextBox.dll. I also had to change the namespace in the WatermarkedTextBox.xaml to the following to get the control working.

   xmlns:local= "clr-namespace:System.Windows.Controls;assembly=WatermarkedTextBox" 

Till the new property is available, this will do !

July 2, 2008

Silverlight - CheckBox issue when in ListBox

Recently for an application I was building on Silverlight 2.0 Beta 2, I had a need to use CheckBox inside the ListBox. Getting the CheckBox into the ListBox item was fairly trivial via the DataTemplate. However the problem started after that.

I could click on the first CheckBox, but when I tried to click on any in the remaining rows, the click won't work. I could easily see the hover effect over the CheckBox so wasn't sure why the click had issues.

See here the code I was using (minimum code to reproduce this issue). 

Code behind

namespace SilverlightApplication1

{

    public partial class Page : UserControl

    {

        public Page()

        {

            InitializeComponent();

        }

    }

 

    public class Frameworks: List<string>

    {

        public Frameworks()

        {

            this.Add(".NET 1.1");

            this.Add(".NET 2.0");

            this.Add(".NET 3.0");

            this.Add(".NET 3.5");

        }

    }

}

XAML Code

<UserControl x:Class="SilverlightApplication1.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:local="clr-namespace:SilverlightApplication1"

   Width="400" Height="300">

    <UserControl.Resources>

        <local:Frameworks x:Key="fwks" />

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">

        <ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="51,26,192,71" ItemsSource="{StaticResource fwks}">

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <CheckBox Content="{Binding}"/>

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

    </Grid>

</UserControl>

 

The following picture shows how this simple application looked at runtime.  

Checkbox.jpg

I initially suspected if ZIndex had anything to do with it, but the hover effected worked fine. It turns out there is some issue in the way ListBox handles it focus. In this application, If I first select a ListBox item, but clicking towards the right side of the item and then click on the CheckBox it works fine.

The workaround to this issue is to change the default ClickMode behavior of CheckBox. By default it is set to Release. This means that the Click fires when the mouse button is first pressed and then released over the control. Due to ListBox taking focus in between, the click never get's completed on the CheckBox and thus the state doesn't change to Checked.

By setting the ClickMode to Press, things work fine. The modified XAML will be as below.

<DataTemplate>

    <CheckBox Content="{Binding}" ClickMode="Press" />

</DataTemplate>

I also found this solution as part of one of the questions on the Silverlight forum. 

July 1, 2008

Webinar - Modernizing from Mainframes to Next-generation IT Systems

In a flattening world, agile companies will succeed because their underlying IT systems can rapidly adapt to changing business priorities. Companies are moving toward SaaS and SOA to provide flexibility in IT systems so that IT remains relevant to business.

Join us as we discuss Infosys’ Mainframe Modernization Framework with the help of case studies of global companies, in our upcoming Webinar on July 16th

 

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter