Thursday, July 23, 2009

How to test the Assembly Caching feature in Silverlight 3.0?

While trying out the various new features with Silverlight 3.0, i have decided to spent more time on the Assembly caching feature as i feel it is a really cool feature which can really help us to keep the common assemblies which are referenced in various xap files in a compressed file such as zip. By doing so we can reduce the size of the various xap files being downloaded to the client cache.

I did all the steps required for Application Library Caching but could observe that these files are being downloaded every time i visit the site. I used the HTTP traffic monitor Fiddler to view HTTP requests and responses, to verify that cached files are not being downloaded.

I figured out the issue as with the test environment being the Visual Studio Development Server which does not enable caching in its HTTP response headers. The key point here is that we should either publish the site to an IIS or Configure the Web project to use IIS and enable local host monitoring from the HTTP traffic monitor

Thursday, July 9, 2009

WPF Presentation Foundation designer Missing for the visual Studio

I could notice that the Intellisense for my xaml files are lost when i  opened a Silverlight UserControl in the default editor immediately after installing the Visual studio 2008,its SP1 and the Silverlight SDK 2.0. In fact, i was missing the  WPF Presentation Foundation designer in the “Open with” dialog Box.The default editor in place now then was the xml editor.

Thanks to visual studio command line help. I could made it working with the following command

Devenv /resetSkipPkgs

This command clears all options to skip loading added to VSPackages by users wishing to avoid loading problem VSPackages, then starts Visual Studio.

Thursday, June 11, 2009

Retrieving domain users in a Silverlight application using a WCF Service

When you need to get the domain users in a Silverlight application the best option is to go behind a WCF service.Create your WCF service and expose the end points . The proxy created in the Silverlight application can get the details of the domain users using the methods exposed in the WCF.

WCF Class

[ServiceContract]
public class UserDomain
{
[OperationContract]
public List<DomainUser> getDomainUsers()
{
DirectorySearcher Search = new DirectorySearcher();
Search.SearchRoot = new DirectoryEntry("LDAP://dc=abc,dc=com");//here abc represents the domain name
Search.Filter = "(&(objectclass=user)(objectcategory=person))";
Search.SearchScope = SearchScope.Subtree;
Search.PropertiesToLoad.Add("userPrincipalName");

SearchResultCollection colQueryResults = Search.FindAll();
List<DomainUser> users = new List<DomainUser>();
foreach (SearchResult Result in colQueryResults)
{
if (Result.Properties["userPrincipalName"] != null)
{
if (Result.Properties["userPrincipalName"].Count > 0)
{
users.Add(new DomainUser() { ID = Result.Properties["userPrincipalName"][0].ToString(),
DisplayName = Result.Properties["name"][0].ToString() });
}
}
}
return users;
}
}
[DataContract]
public class DomainUser
{
[DataMember]
public string ID { get; set; }
[DataMember]
public string DisplayName { get; set; }
}


Silverlight Implementation

Create the Silverlight application and add a service reference to the above created WCF service.Create the client proxy with the added service and call the WCF method to retrieve the domain users.


Code

public partial class MainPage : UserControl
{
public MainPage()
{
try
{
InitializeComponent();
UserDomainClient Proxy = new UserDomainClient();
Proxy.getDomainUsersCompleted += new EventHandler<getDomainUsersCompletedEventArgs>(Proxy_getDomainUsersCompleted);
Proxy.getDomainUsersAsync();
}
catch (Exception ex)
{

MessageBox.Show(ex.Message);
}
}

void Proxy_getDomainUsersCompleted(object sender, getDomainUsersCompletedEventArgs e)
{
List<DirectoryServiceExt.DomainUser> lstUsers=e.Result;
}
}



Make sure that you use basicHttpbinding while deploying the WCF service

Getting Started with NSIS(Nullsoft Scriptable Install System)

NSIS (Nullsoft Scriptable Install System) is a tool that allows programmers to create such installers for Windows.It is released under an open source license and is completely free for any use.

NSIS creates installers that are capable of installing, uninstalling, setting system settings, extracting files, etc. Because it's based on script files, you can fully control every part of your installers. The script language supports variables, functions, string manipulation, just like a normal programming language - but designed for the creation of installers. Even with all these features, NSIS is still the smallest installer system available. With the default options, it has an overhead of only 34 KB. Let's now try a very simple installer with the NSIS as below

1. Download latest NSIS and install

2. Open any text editor and copy the following snippet. Save this file as .nsi

;-------------------------------------------------------------------------
; Installer script for My Installer 1.0
;-------------------------------------------------------------------------
;--------------------------------------------
; General definitions
!define PRODUCT_NAME "My Installer"
!define PRODUCT_VERSION_MAJOR 1
!define PRODUCT_VERSION_MINOR 0
!define PRODUCT_DISPLAY_VERSION "1.0"
!define PRODUCT_PUBLISHER "XYZ, Inc."
!define PRODUCT_WEB_SITE "http://www.XYZ.com"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME} 1.0"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\XYZ\${PRODUCT_NAME} 1.0"

;--------------------------------------------
; Maximum compression
SetCompressor /SOLID lzma

;--------------------------------------------
; Modern UI (MUI 1.67 compatible) definitions
!include "MUI2.nsh"

; MUI Settings
!define MUI_ABORTWARNING
!define MUI_ICON "resources\icon.ico"
!define MUI_UNICON "resources\icon.ico"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "resources\header.bmp"
!define MUI_HEADERIMAGE_RIGHT
!define MUI_HEADER_TRANSPARENT_TEXT
!define MUI_WELCOMEFINISHPAGE_BITMAP "resources\welcome.bmp"
!define MUI_WELCOMEFINISHPAGE_BITMAP_NOSTRETCH
;!define MUI_FINISHPAGE_NOAUTOCLOSE

; Welcome page
!insertmacro MUI_PAGE_WELCOME

; License page
!define MUI_LICENSEPAGE_CHECKBOX
!insertmacro MUI_PAGE_LICENSE "resources\license.rtf"

; Instfiles page
!insertmacro MUI_PAGE_INSTFILES

; Finish page
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt"
!define MUI_FINISHPAGE_NOREBOOTSUPPORT
!insertmacro MUI_PAGE_FINISH

; Uninstaller pages
!insertmacro MUI_UNPAGE_INSTFILES

; Language files
!insertmacro MUI_LANGUAGE "English"

!include "nsDialogs.nsh"
!include "LogicLib.nsh"
!include "StrFunc.nsh"
${StrLoc}

;--------------------------------------------
; Installer Settings
Name "${PRODUCT_NAME} v1.0"
OutFile "XYZ_1.0.exe"
InstallDir "${PRODUCT_INSTALL_DIR}"
ShowInstDetails show
ShowUnInstDetails show
BrandingText "${PRODUCT_PUBLISHER}"
RequestExecutionLevel admin

;-------------------------------------------------------------------------
; Initialize Function
Function .onInit

; Determine if installed
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString"
StrCmp $R0 "" Proceed EqualMinor

EqualMinor:
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
"${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the \
previous installation or `Cancel` to cancel." \
IDOK UninstallPrevious
Abort

;--------------------------------------------
; Run the uninstaller
UninstallPrevious:
HideWindow
ClearErrors
ExecWait '$R0 _?=$INSTDIR' ;Do not copy the uninstaller to a temp file
Delete '$R0'
BringToFront
Goto Proceed

Proceed:

FunctionEnd

;-------------------------------------------------------------------------
; Main Install Section
Section "MainSection" MainSection

DetailPrint "Installing Components..."
SetOutPath "${PRODUCT_INSTALL_DIR}"
SetOverwrite ifnewer
File "/oname=abc.png" "Build\abc.png"
File "/oname=icon.ico" "resources\blendables1.ico"

SectionEnd

;-------------------------------------------------------------------------
; Installer Finished callbacks
Function .onInstSuccess
FunctionEnd

Function .onInstFailed
FunctionEnd

;-------------------------------------------------------------------------
; Post Install
Section -Post
WriteUninstaller "$INSTDIR\uninst.exe"

;--------------------------------------------
; Add/Remove registry settings
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\icon.ico"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_DISPLAY_VERSION}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMajor" "${PRODUCT_VERSION_MAJOR}"
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "VersionMinor" "${PRODUCT_VERSION_MINOR}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd

;-------------------------------------------------------------------------
; Uninstaller
Function un.onUninstSuccess
HideWindow
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."
FunctionEnd

Function un.onInit
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2
Abort
FunctionEnd

Section Uninstall

;--------------------------------------------
; Registry
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
Delete "$INSTDIR\icon.ico"
Delete "$INSTDIR\uninst.exe"
Delete "${PRODUCT_INSTALL_DIR}\abc.png"
RMDir /r "${PRODUCT_INSTALL_DIR}"
SetAutoClose True

SectionEnd



3. Create a folder named Resources and copy/create the files like .ico and .rtf as mentioned in the script. This folder should be created in the same location where the .nsi file is saved



4. Right click the ".nsi" file and select "Compile NSIS Script"



5. A compilation window will pop up and will list the errors with line numbers if the compilation failed. I would recommend using Notepad++ as the editor for nsi script as it is very easy to navigate to the line number mentioned in the compiler window (for errors in the script) . If the compilation went with out any errors the installer will be ready and available at the same location as the .nsi file.

Wednesday, June 10, 2009

Design time Experience for your WPF/Silverlight controls

It is always a good practice to ship your WPF/Silverlight controls with its design time experience. Design time experience can be extended with the help of design assemblies supplies by Microsoft

Steps :

Create your WPF/Silverlight control

Create a visual studio class library project and name it MyControls

Subclass a control of your choice and add one dependency property. I did that for a button control in my sample. I used this control to demonstrate the property Editor in design time extensibility

public class MyButton : Button
{

public double MyHeight
{
get { return (double)GetValue(MyHeightProperty); }
set { SetValue(MyHeightProperty, value); }
}

// Using a DependencyProperty as the backing store for MyHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyHeightProperty =
DependencyProperty.Register("MyHeight", typeof(double), typeof(MyButton), new UIPropertyMetadata(0d));


}



Create a second class as above to demonstrate the category Editor concept in design time Extensibility . My second class is as follows




public class MyTextBox : TextBox
{
public double MyWidth
{
get { return (double)GetValue(MyWidthProperty); }
set { SetValue(MyWidthProperty, value); }
}

// Using a DependencyProperty as the backing store for MyWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyWidthProperty =
DependencyProperty.Register("MyWidth", typeof(double), typeof(MyTextBox), new UIPropertyMetadata(20d));
}



Create the Design time project for the control



Create a class library project named MyControls.design and add reference to the following assemblies



Microsoft.Windows.Design.dll



MyControls.dll



Create a class which inherit from the IRegisterMetadata interface and write necessary code to update the metadatstore (a container of custom design-time attributes).




public class DesignMetaDataMain : IRegisterMetadata
{
#region IRegisterMetadata Members
public void Register()
{
AttributeTableBuilder builder = new AttributeTableBuilder();
new MyButtonMetadata().AddMetadata(builder);
new MyTextBoxMetadata().AddMetadata(builder);
MetadataStore.AddAttributeTable(builder.CreateTable());
}
#endregion
}




public class MyButtonMetadata
{
public void AddMetadata(AttributeTableBuilder tableBuilder)
{
//Property Editor
tableBuilder.AddCustomAttributes(
typeof(MyButton),
MyButton.MyHeightProperty,
new MyButtonCategoryAttribute(),
new EditorAttribute(typeof(TextExtendedEditor),
typeof(TextExtendedEditor)));
}
}

internal class MyButtonCategoryAttribute : CategoryAttribute
{
protected override string GetLocalizedString(string value)
{
return "MyButton";
}
}




public class MyTextBoxMetadata
{
public void AddMetadata(AttributeTableBuilder tableBuilder)
{
tableBuilder.AddCustomAttributes(typeof(MyTextBox), MyTextBox.MyWidthProperty, new MyTextBoxCategoryAttribute());
tableBuilder.AddCustomAttributes(typeof(MyTextBox), new EditorAttribute(typeof(MyTextBoxCategoryEditor), typeof(MyTextBoxCategoryEditor)));
}
}
internal class MyTextBoxCategoryAttribute : CategoryAttribute
{
protected override string GetLocalizedString(string value)
{
return "MyTextBox";
}
}



Category Editor definition




public class MyTextBoxCategoryEditor : CategoryEditor
{

public override bool ConsumesProperty(PropertyEntry property)
{
return true;
}

public override System.Windows.DataTemplate EditorTemplate
{
get
{
try
{
Resources myresourcedictionary = new Resources();
return myresourcedictionary["myTextBoxEditorTemplate"] as DataTemplate;

}
catch (Exception ex)
{

MessageBox.Show(ex.Message);
}
return null;
}
}

public override object GetImage(System.Windows.Size desiredSize)
{
return null;
}

public override string TargetCategory
{
get
{
return "MyTextBox";
}
}
}



Property Editor definition




public class TextExtendedEditor : ExtendedPropertyValueEditor
{
private Resources res = new Resources();

public TextExtendedEditor()
{
this.InlineEditorTemplate = res["myButtonEditorTemplate"] as DataTemplate;
}

}



Resource Dictionary code




<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design"
x:Class="MyControls.Design.Resources" >
<DataTemplate x:Key="myButtonEditorTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="{Binding StringValue}" Click="Button_Click"/>
<TextBox Text="{Binding StringValue}"
Grid.Column="1" />
<!--<PropertyEditing:EditModeSwitchButton Grid.Column="1" />-->
</Grid>
</DataTemplate>
<DataTemplate x:Key="myTextBoxEditorTemplate">
<Expander>
<ItemsControl ItemsSource="{Binding Path=Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Left"
Width="0.4*"
MinWidth="100"
MaxWidth="180" />
<ColumnDefinition SharedSizeGroup="Middle"
Width="0.6*" />
<ColumnDefinition SharedSizeGroup="Right"
Width="12" />
</Grid.ColumnDefinitions>
<PropertyEditing:PropertyContainer Grid.ColumnSpan="3"
PropertyEntry="{Binding}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
</DataTemplate>
</ResourceDictionary>



Build this project and copy the assembly to the bin\debug\design folder of the MyControls project. The design folder will not be there by default..you need to create a folder with that name. For deployment scenarios you must create a design folder on the location of the mycontrols.dll and place the design dll there. 



Consume the control in a project



Create a WPF application and use the two controls created in project MyControls




<Window x:Class="WPFHost.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyControls;assembly=MyControls"
Title="Window1" Height="300" Width="300">
<StackPanel>
<local:MyButton MyHeight="100" Content="MyButton"/>
<local:MyTextBox MyWidth="200"
Text="MyTextBox"
/>
</StackPanel>
</Window>



You are done and you should be able to see a custom property editor in case of the myTextBox control and a custom property editor for myButton as shown below(Note that the dependency property we added for the controls are shown in a separate bucket in the property pages


Design time in Cider











Design time in Blend










Wednesday, May 27, 2009

Windows authentication in Silverlight

Authenticating a windows user from a Silverlight application is pretty simple with the following steps

1.Create a WCF service with a method to Authenticate the windows user

Interface

[ServiceContract]
public interface IUser
{
[OperationContract]
bool AuthenticateUser(string UserName, string Password);
}



Class




public class User : IUser
{
public bool AuthenticateUser(string UserName, string Password)
{
return (Helper.LogOnUser(UserName.Split(new string[] { "@" }, StringSplitOptions.RemoveEmptyEntries)[0],
"microsoft.com",
Password
) != 0);
}

}



Helper class




public static class Helper
{
#region Properties
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
#endregion

#region Static

#region NativeMethods
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
private static extern int LogonUser(String UserName,
String Domain,
String Password,
int LogonType,
int LogonProvider,
ref IntPtr Token);

#endregion

#region Methods
public static int LogOnUser(String userName, String domain, String password)
{
IntPtr token = IntPtr.Zero;
return LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
}
#endregion
#endregion
}



2.Create the service proxy from the Silverlight application and call the Authentication method described in the WCF service



Silverlight Code behind




UserService.UserClient Proxy = new UserService.UserClient();
Proxy.AuthenticateUserCompleted +=
new EventHandler<UserService.AuthenticateUserCompletedEventArgs>(Proxy_AuthenticateUserCompleted);
Proxy.AuthenticateUserAsync(txtUser.Text, txtPassword.Password);




void Proxy_AuthenticateUserCompleted(object sender, UserService.AuthenticateUserCompletedEventArgs e)
{
MessageBox.Show(e.Result.Equals(true) ? "login succeeded" : "login failed");
}

Wednesday, May 20, 2009

Error 500.19 – Internal Server Error - While trying you run a WCF Service hosted on a Vista Machine

When you are deploying a WCF service on a newly set up Vista machine chances are that you get the following error






One possible option to get the service working is by resetting the registration of ServiceModel on your machine.


The ServiceModel Registration Tool will help you in accomplishing this task.


The tool can be found in the following location:


%SystemRoot%\Microsoft.Net\Framework\v3.0\Windows Communication Foundation\


Open Visual studio Command prompt and run the following command : ServiceModelReg.exe /i



Other helpful links




http://support.microsoft.com/kb/942055











Monday, February 9, 2009

When IE Zoom Feature does not zoom in the silverlight plugin Islands.

A silverlight pluggin area won't grow/shrink while zoom-IN/OUT the Internet Explorer window. This functionality can be achieved as follows



This is a straight forward approach and pretty simple



1. Register your Class



2. Create the Method to be called from IE Javascript with the ScriptableMember attribute




public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
HtmlPage.RegisterScriptableObject("page", this);

}
[ScriptableMember]
public void ResizePage(double Height, double Width)
{
LayoutRoot.Height = Height;
LayoutRoot.Width = Width;
}
}



3.Create a javascript function in the html page where in the silverlight pluggin is used




function onResize(sender, args) {
var slControl = document.getElementById("slControl");
var height, width;
height = slControl.Content.ActualHeight;
width = slControl.Content.ActualWidth;
slControl.Content.page.ResizePage(height, width);
}



4.Call this method in the onresize method of the html object tag as




<object id="slControl" data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="50%" height="50%">
<param name="source" value="ClientBin/SilverlightNet.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="2.0.31005.0" />
<param name="autoUpgrade" value="true" />
<param name="onresize" value="onResize" />
<a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
</a>
</object>



You are done. Now the Silverlight content will Grow/Shrink with the zoom in/out



Reference : http://www.microsoft.com/Web/content.aspx?id=browser-resize-zoom



Friday, February 6, 2009

Password Encryption and Decryption in SQL Server 2005

Encryption of column data in SQL 2005 is a good approach while we think of some one tampering our database through some sql injection and methods like that

Here are the steps involved

1. Create a MASTER KEY ENCRYPTION for your database

CREATE MASTER KEY ENCRYPTION BY PASSWORD = '<Give a Password Here>'





2.Create a Certificate




CREATE CERTIFICATE SampleCertificate  
WITH SUBJECT = '<Give some Description about the certificate>'





3.Create the symmetric Key (You'll use the certificate created above while creating a symmetric key)




CREATE SYMMETRIC KEY SamplePassword    
WITH ALGORITHM = AES_256 ENCRYPTION BY CERTIFICATE SampleCertificate



You can select an encryption algorithm of your choice while creating a Symmetric key.





Your keys for the Encryption and Decryption are ready now. Open your keys and do the encryption or decryption as follows



Encrypting the Password




OPEN SYMMETRIC KEY IMCPSPassword   
DECRYPTION BY CERTIFICATE IMCPSCert;

UPDATE [dbo].[Users]
SET [Password] = EncryptByKey(Key_GUID('IMCPSPassword'),Password)





Decrypting the Password




SELECT 
[UserID],
CONVERT(varchar, DecryptByKey(Password)) as Decryptedpassword
FROM [dbo].[Users]

Simple Colour Animation in Silverlight 2.0 using inline XAML

If you do not want your Silverlight pluggin to look for the xap file in its relative path ..go for the inline XAML concept. Its pretty simple and easy

A sample code which do the colour animation is as follows

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>BugRepro</title>
<SCRIPT type="text/xaml" id="xaml1">
   1:  
   2:     <Canvas
   3:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   4:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   5:     <Canvas.Triggers>
   6:       <EventTrigger  RoutedEvent="Canvas.Loaded" >
   7:       <BeginStoryboard >
   8:     <Storyboard x:Name="myAnimation" RepeatBehavior='Forever'>
   9:     <ColorAnimation    
  10:               Storyboard.TargetName="myRectangle"     
  11:               Storyboard.TargetProperty='(Shape.Fill).(SolidColorBrush.Color)'    
  12:               From="Red"    
  13:               To="Green"                  
  14:               Duration="0:0:0.5"    
  15:               AutoReverse="True"/>  
  16:     </Storyboard>
  17:       </BeginStoryboard>
  18:       </EventTrigger>
  19:     </Canvas.Triggers>
  20:     <Canvas Background="White" Width="100" Height="100">
  21:     <Rectangle x:Name="myRectangle" Fill='Red' Height='100' Width='100'/>
  22:     </Canvas>
  23:     </Canvas>
  24:     
</SCRIPT>
</head>
<body>
<div>
<object data=data:application/x-silverlight, type=application/x-silverlight-2
width="100" height="100" id="Ag1">
<param name="Source" value="#xaml1" />
</object></div>
</body>
</html>