Archive of posts filed under the Silverlight category.

Silverlight 4 + COM + SQL Server = Cool!

Today is the day to talk about COM possibilities in Silverlight 4.  One would question the titles of my post.  COM and Cool in the same sentence?  Let me proof this title to you.

First, let me take a closer look at COM.  In order to access COM, you must install Silverlight application on a local machine.  The access to COM is not enabled when a Silverlight application is run in the browser.  So, first of all you have to enable this by checking “Enable running application out of browser” checkbox in project properties.  Second of all, you have to check “Require elevated trust…” checkbox in “Out-of-browser settings” area in project properties.  Now, you are ready to install you application and test COM support.  How about Word automation:

Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();
var doc = word.Documents.Add();
var paragraph = doc.Paragraphs.Add();
paragraph.Range.Text = "Some text";

Now, let’s talk about database access.  Parts of System.Data.SqlClient namespace are not exposed to COM by default.  So, to enable database access we must write an assembly that is exposed to COM that wraps database access.  To do so, check the property “Register for COM Interop” in project properties for the .NET (NOT Silverlight) based project that will fire off database queries for us.  Once the assembly is built, I can just use RegAsm to register my DLL with COM on a machine.  Of course, this would be a prerequisite to use Silverlight application for local data access.  The other prerequisite is to have .NET Runtime installed on that machine as well.  I could write an install project of course to make this process easier.

The next step is to write a Silverlight assembly that would use COM Interop similar to the one above for Word to talk to my database access .NET based assembly.

dynamic sqlDB = ComAutomationFactory.CreateObject("COMSQLClient.COMSqlDatabase");

Now the most exciting part.  I created and published the project on CodePlex that does exactly what I just talked about.  Check out the project and let me know what you think.  You can download the source code and look into the implementation details.  Here is the link to it:

http://silverlight4sqllib.codeplex.com/

Thanks.

Silverlight, MVVM and Animations

Yesterday I was asked about a way to play animations in MVVM environment.

So, I gave this some thought today, and came up with a few ideas.

First, and the easiest way is to separate ViewModel from animation by attaching an animation to a behavior.  Here is how we would write the behavior:

public class MVVMSimpleAnimationBehavior : TargetedTriggerAction<UIElement>

{

    protected override void Invoke(object parameter)

    {

        RunAnimation();

    }

 

    public Storyboard AnimationStoryBoard

    {

        get { return (Storyboard)GetValue(AnimationStoryBoardProperty); }

        set { SetValue(AnimationStoryBoardProperty, value); }

    }

 

    public static readonly DependencyProperty AnimationStoryBoardProperty =

        DependencyProperty.Register("AnimationStoryBoard", typeof(Storyboard), typeof(MVVMSimpleAnimationBehavior), new PropertyMetadata(null));

 

 

    private void RunAnimation()

    {

        if (AnimationStoryBoard != null)

        {

            AnimationStoryBoard.Begin();

        }

    }

}

 

Pretty simple approach.  Here is how would use animation in the XAML:

<Button Content="Behavior Test" Grid.Column="1">

    <i:Interaction.Triggers>

        <i:EventTrigger EventName="Click">

            <local:MVVMAnimationBehavior AnimationStoryBoard="{StaticResource TestStoryboard}"/>

        </i:EventTrigger>

    </i:Interaction.Triggers>

</Button>

Now, I want to complicate the story a little bit.  I really want to trigger an animation in the UI via an event in my model.  I am going to start with a sample ViewModel.  I want to have an event there that I will later use as a trigger for my animation.  Here is what my ViewModel would look like:

public class SampleModel: INotifyPropertyChanged

{

 

    public event EventHandler StartAnimation;

 

    protected virtual void OnStartAnimation()

    {

        if (StartAnimation != null)

        {

            StartAnimation(this, EventArgs.Empty);

        }

    }

 

    public void RaiseEvent()

    {

        OnStartAnimation();

    }

 

    #region INotifyPropertyChanged Members

 

    public event PropertyChangedEventHandler PropertyChanged;

 

    protected virtual void OnPropertyChanged(string propertyName)

    {

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

        }

    }

 

    #endregion

}

My event is called StartAnimation.  Now it is time to develop a more complicate behavior to support my event driven animation from ViewModel.  I am going to actually combine new functionality with the simple behavior about and have multi-functional useful object.  Here is what the final product looks like:

using System;

using System.Windows.Interactivity;

using System.Windows;

using System.Windows.Media.Animation;

using System.ComponentModel;

using System.Reflection;

 

 

namespace SLMVVMAnimationBehavior

{

    public class MVVMAnimationBehavior : TargetedTriggerAction<UIElement>

    {

        private EventInfo info;

        protected override void Invoke(object parameter)

        {

            RunAnimation(this, EventArgs.Empty);

        }

 

        public Storyboard AnimationStoryBoard

        {

            get { return (Storyboard)GetValue(AnimationStoryBoardProperty); }

            set { SetValue(AnimationStoryBoardProperty, value); }

        }

 

        public static readonly DependencyProperty AnimationStoryBoardProperty =

            DependencyProperty.Register("AnimationStoryBoard", typeof(Storyboard), typeof(MVVMAnimationBehavior), new PropertyMetadata(null));

 

        public string EventName

        {

            get { return (string)GetValue(EventNameProperty); }

            set { SetValue(EventNameProperty, value); }

        }

 

        public static readonly DependencyProperty EventNameProperty =

            DependencyProperty.Register("EventName", typeof(string), typeof(MVVMAnimationBehavior), new PropertyMetadata(HandlModelChanged));

 

 

        public object Model

        {

            get { return GetValue(ModelProperty); }

            set { SetValue(ModelProperty, value); }

        }

 

        public static readonly DependencyProperty ModelProperty =

            DependencyProperty.Register("Model", typeof(object), typeof(MVVMAnimationBehavior), new PropertyMetadata(HandlModelChanged));

 

        private static void HandlModelChanged(object sender, DependencyPropertyChangedEventArgs e)

        {

            MVVMAnimationBehavior behavior = sender as MVVMAnimationBehavior;

            object model = behavior.Model;

            if (behavior.info != null)

            {

                behavior.info.RemoveEventHandler(model, Delegate.CreateDelegate(typeof(EventHandler), behavior, "RunAnimation"));

            }

            if (model != null && !string.IsNullOrEmpty(behavior.EventName))

            {

                behavior.info = model.GetType().GetEvent(behavior.EventName);

                behavior.info.AddEventHandler(model, Delegate.CreateDelegate(typeof(EventHandler), behavior, "RunAnimation"));

 

            }

        }

 

        private void RunAnimation(object sender, EventArgs e)

        {

            if (AnimationStoryBoard != null)

            {

                AnimationStoryBoard.Begin();

            }

        }

    }

}

 

 

As you can see, I added two mode dependency properties – one for event name that will trigger the animation, the other one for ViewModel ( I actually called it model).  Now the tricky part is to use a bit of reflection to attach an event handler to the event on my model.  This is done in HandlModelChanged routine that is called when Model or Event name is set.  I am getting an event, and attaching a handler to it.  The actual handler is located inside the behavior itself – RunAnimation method.  Here is what my fianl XAML looks like that is testing both animation approaches:

<UserControl x:Class="SLMVVMAnimationBehavior.MainPage"

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

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

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:local="clr-namespace:SLMVVMAnimationBehavior"

    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

    <UserControl.Resources>

        <Storyboard x:Name="TestStoryboard">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="textBlock" Storyboard.TargetProperty="(TextBlock.FontSize)">

                <EasingDoubleKeyFrame KeyTime="00:00:00.1000000" Value="24"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.2000000" Value="21.333"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.3000000" Value="18.667"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.4000000" Value="16"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.5000000" Value="13.333"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.6000000" Value="16"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.7000000" Value="18.667"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.8000000" Value="21.333"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.9000000" Value="24"/>

                <EasingDoubleKeyFrame KeyTime="00:00:01" Value="26.667"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <local:SampleModel x:Key="CurrentModel" />

        <local:MVVMAnimationBehavior AnimationStoryBoard="{StaticResource TestStoryboard}" Model="{StaticResource CurrentModel}" x:Key="Animation" EventName="StartAnimation"/>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="#FFF3EEEE" DataContext="{Binding Source={StaticResource CurrentModel}}">

        <Grid>

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="Auto"/>

                <ColumnDefinition Width="Auto"/>

                <ColumnDefinition/>

            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>

                <RowDefinition Height="Auto"/>

                <RowDefinition/>

            </Grid.RowDefinitions>

            <Button x:Name="TestButton" Content="Click To Start Animation" d:LayoutOverrides="Height" HorizontalAlignment="Left" Click="TestButton_Click"/>

            <Button Content="Behavior Test" Grid.Column="1">

                <i:Interaction.Triggers>

                    <i:EventTrigger EventName="Click">

                        <local:MVVMAnimationBehavior AnimationStoryBoard="{StaticResource TestStoryboard}"/>

                    </i:EventTrigger>

                </i:Interaction.Triggers>

            </Button>

            <TextBlock x:Name="textBlock" Margin="0,0,0,6" Text="Sample Text" TextWrapping="Wrap" d:LayoutOverrides="Width, Height" Grid.Row="1" Grid.ColumnSpan="3" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="26.667"/>

        </Grid>

 

    </Grid>

</UserControl>

 

To summarize, I illustrate a couple of approaches to trigger animations in MVVM environment.  Of course, there is always code-behind, but many developers frown at this approach..

Please let me know if you have any questions.

WCF RIA Services Validation

Today I am continuing exploring WCF RIA Services.  I am going to discuss validation in RIA Services.

Any business application needs to validate user input.  I am going to start with a simple case.  In my sample application a user can enter a company information.  I would like to setup RIA Services to force the user to enter a company name before he or she can save the company.  In order to do so I am going to use Data Annotations.  First of all, I need to add a reference to System.ComponentModel.DataAnnotations DLL to all my projects.  RIA Services project should already have the reference. 

Now I need to edit my metadata file that corresponds to my data model under .NET version of RIA Services.  In my case it is RolodexDomainService.metadata.cs file in SilverlightRIAServicesLibrary.Web project.  In that file I need to find Companies class, then location company name property, then decorate the property with required attribute.  At the same time we will also put a limit on how many characters a user can enter:

[Required]

[StringLength(30)]

public string CompanyName;

 

If we want to see the results of our changes, we can run the application, then clear company name for an existing comp-any, then tab out of company name field.  Here we get visual feedback that our input was not valid:

image

Now, let’s create custom validation.  Fir example, I am going to force the date added to be no less that 1/1/2000.  To do this I will write a custom validation class like so:

public static class ValidationHelper

{

    public static ValidationResult DateAddedCheck(DateTime date)

    {

        ValidationResult result;

        if (date > new DateTime(2000, 1, 1))

        {

            result = new ValidationResult("");

        }

        else

        {

            result = new ValidationResult("Date is not valid");

        }

 

        return result;

    }

}

Validation method that I wrote is a static member.  It follows a specific signature that RIA Services requires.  For example, it returns Validation Result that contains specific information that validation infrastructure of RIA Services can parse.  Overall code is fairly simple.

In order to make this class available on the Silverlight side, I must include my validation class into Silverlight version of RIA Services library – SilverlightRIAServicesLibrary project in my case.  In order not to duplicate the code, I will include the same class as a link.  I right-click on the project, choose add existing item, navigate to my class, then click on down arrow on Add button, and select Add As Link.  Now I have the same validation on both .NET and Silverlight side.  To confirm, I just build and run the application.  Here is what my DateAdded attributes look like:

[Required]

[CustomValidation(typeof(ValidationHelper), "DateAddedCheck", ErrorMessage = "Date is not valid")]

public DateTime DateAdded;

On important thing to mention that in  order to see validation error in UI, we need to update our Binding to look as following:

<TextBox x:Name="CompanyNameTextbox" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" Margin="6,6,6,6" Text="{Binding Path=CompanyName, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}" VerticalAlignment="Center"/>

There is one important thing to notice.  If you look at Silverlight side generated code, you will notice that validation occurs before the property value is set.  As a result, you cannot rely on property value being set if a validation exception is thrown.

Now, let’s look at saving code that we had to modify in order to validate user input.  Here is what it looks like:

try

{

    Validator.ValidateObject(this.Model, new ValidationContext(this.Model, null, null), true);

    if (this.Model.HasChanges)

    {

        ShowPleaseWaitMessage();

        _context.SubmitChanges(HandleSave, null);

    }

}

catch (ValidationException ex)

{

    MessageBox.Show(ex.Message);

}

Not really the cleanest code because we have to rely on exceptions being thrown. 

I covered all key area of validation, but there is more for you to explore.  Please let me know if you have any questions.

RIA Services (Cont.)

In this post I will cover the update process.

I am going to recap where I left off in the last post on RIA Services.  The last step was to retrieved based on ID from a read only company object.  Once this object is obtained in the VIewModel, we can create a screen to edit a company.

Here is how I am getting the company by ID in the ViewModel class:

var

companyQuery = _context.GetCompanyQuery(_companyID);

 

_context.Load<Companies>(companyQuery, (o1) =>

 

{

 

    HidePleaseWaitMessage();

 

    if (o.Error != null)

 

    {

 

        ErrorHandler.HandleException(o.Error);

 

    }

 

    else

 

    {

 

        this.Model = o1.Entities.First() as Companies;

 

    }

 

}, null);

Now that I have my Model property set, I can create a user control to edit the company.  Here is the part of the XAML for the edit form that shows the binding:

<UserControl x:Class

=”Rolodex.Silverlight.Views.CompanyEditView”

 

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

 

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

 

    xmlns:controls=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data”

 

    xmlns:input=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls”

 

    xmlns:cal=”clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation”

 

    xmlns:core=”clr-namespace:Rolodex.Silverlight.Core”

 

    >

 

    <UserControl.Resources

>

 

       

 

    </UserControl.Resources

>

 

    <Grid x:Name

=”LayoutRoot”>

 

        <Grid.RowDefinitions

>

 

            <RowDefinition Height

=”*”/>

 

            <RowDefinition Height

=”Auto”/>

 

        </Grid.RowDefinitions

>

 

        <Grid x:Name=”EditGrid” DataContext=”{Binding Model

}”>

 

            <Grid.RowDefinitions

>

 

                <RowDefinition Height

=”35″/>

 

                <RowDefinition Height

=”35″/>

 

                <RowDefinition Height

=”1*”/>

 

                <RowDefinition Height

=”35″/>

 

                <RowDefinition Height

=”1*”/>

 

                <RowDefinition Height

=”35″/>

 

            </Grid.RowDefinitions

>

 

            <Grid.ColumnDefinitions

>

 

                <ColumnDefinition Width

=”Auto”/>

 

                <ColumnDefinition Width

=”200″/>

 

                <ColumnDefinition Width

=”*”/>

 

            </Grid.ColumnDefinitions

>

 

            <TextBlock Text=”Company Name:” TextAlignment=”Right” HorizontalAlignment=”Right” Grid.Column=”0″ Grid.Row=”0″ Margin=”6,6,6,6″ VerticalAlignment

=”Center”/>

 

            <TextBox x:Name=”CompanyNameTextbox” Grid.Column=”1″ Grid.Row=”0″ HorizontalAlignment=”Stretch” Margin=”6,6,6,6″ Text=”{Binding Path=CompanyName, Mode=TwoWay}” VerticalAlignment

=”Center”/>

 

            <TextBlock Text=”Date Added:” TextAlignment=”Right” HorizontalAlignment=”Right” Grid.Column=”0″ Grid.Row=”1″ Margin=”6,6,6,6″ VerticalAlignment

=”Center”/>

 

            <input:DatePicker x:Name=”DateAddedTextbox” SelectedDate=”{Binding DateAdded, Mode=TwoWay}” Grid.Column=”1″ Grid.Row=”1″ HorizontalAlignment=”Stretch” Margin=”6,6,6,6″ VerticalAlignment=”Center”/>

So far, I have an instance of a Companies object that is bound to the data context of my user control.  At this point a user can edit company name and date added fields.  Logically, the next thing a user would want to do is to save his changed – the nerve of him :-)

So, let’s take a look at the Save command in our view model object.

 

protected

override void BeginSave()

 

{

 

    ShowPleaseWaitMessage();

 

    _context.SubmitChanges(HandleSave, null);

 

}

 

 

 

private

void HandleSave(SubmitOperation operation)

 

{

 

    HidePleaseWaitMessage();

 

    if (operation.Error != null)

 

    {

 

        ErrorHandler.HandleException(operation.Error);

 

    }

 

}

Save is a two step process because all communication in Silverlight is asynchronous.  We are starting the save process in BeginSave, and we are checking for errors in HandleSave methods respectively.  The key part to this process is client side context of RIA Services that keeps track of all the changes that the user is making after the object has been initially retrieved via a call to the server.  The key work is done by the domain service object – LinqToEntitiesDomainService<RolodexEntities> in our case.  We can look at this code generated by the RIA Services wizard by looking at RolodexDomainService.cs class in my case.  There is a bug in current CTP that causes update to parent and child objects not being flushed properly.  In my case I have Companies object that contains a list of ComanyContacts objects.  Generated code has check for EntityState in UpdateCompanyContacts method that I had to remove to get the process to work.  Here is the final version of key methods of the Domain service class:

public

void UpdateCompanies(Companies currentCompanies)

 

{

 

    this.ObjectContext.AttachAsModified(currentCompanies, this.ChangeSet.GetOriginal(currentCompanies));

 

}

public

void UpdateCompanyContacts(CompanyContacts currentCompanyContacts)

 

{

 

    this.ObjectContext.AttachAsModified(currentCompanyContacts, this.ChangeSet.GetOriginal(currentCompanyContacts));

 

}

So, after this step all parts of the process are working – I can update companies and contacts.

Please email me any questions,

RIA Services (Cont.)

I am going to continue exploring the topic of RIA services and Silverlight.  I thought I was going to get into updates in this post, but there are a few topics I would like to cover first.  I am going to try to get to updates in the next post.

Today, I am going to explore two more topics.  I am going to cover extending RIA Services DomainContext with custom classes and working on including child objects when fetching a parent object using Entity Framework and RIA Services.

 

First, I am going to extend my DomainContext with a custom class.  In my case I have Company Object/Table with a number of columns.  In my Silverlight application I would like to have a list of companies that shows only company name.  When a user selected one company, I would like to fetch full company object with company contacts child object.  If I were to use the method that the wizard built for me – public IQueryable<Companies> GetCompanies(),I would get the full object with all columns.  So, I am going to build a custom class that only has company ID and name:

    public class ReadOnlyCompany

    {

        [Key]

        public int CompanyId { internal set; get; }

        public string CompanyName { internal set; get; }

    }

 

I am going to add this class to RIA Service project on .NET side (SilverlightRIAServicesLibrary.Web project in my case).  As you notice I did not have to decorate my class with DataContract attribute or decorate properties with DataMember attribute.  We do not actually need to do this, as RIA Services will take care of all that for us.  I do however need to use Key attribute or I would get a compile time error.  Each object is required to have a key (primary key) property.  Next step is to write a method in DomainService (RoldexDomainService in my case) class.  Here is what this would look like:

        public List<ReadOnlyCompany> GetReadOnlyCompanies()

        {

            return (from oneCompany in this.ObjectContext.Companies

                    orderby oneCompany.CompanyName

                    select new ReadOnlyCompany()

                    {

                        CompanyId = oneCompany.CompanyId,

                        CompanyName = oneCompany.CompanyName

                    }).ToList<ReadOnlyCompany>();

        }

 

Even though I return List object here, but RIA Services will actually return ReadOnlyObservableCollection<ReadOnlyCompany> on Silverlight side.  You have to remember that when you cast return value for RIA Services call to a specific object.  Here is what this call would look like on Silverlight side:

        private void GetCompaniesList()

        {

            ShowPleaseWaitMessage();

            var query = _context.GetReadOnlyCompaniesQuery();

 

            _context.Load<ReadOnlyCompany>(query, LoadBehavior.RefreshCurrent, (o) =>

            {

                HidePleaseWaitMessage();

                if (o.Error != null)

                    ErrorHandler.HandleException(o.Error);

                else

                {

                    this.Model = o.Entities as ReadOnlyObservableCollection<ReadOnlyCompany>;

                }

                    HidePleaseWaitMessage();

            }, null); ;

 

        }

Here I am putting up a please wait window, fire a query and interpret the results.  As I mention before, my next step is to get full Company object based on selected ID.  Again, I am adding a new method to DomainService class on .NET side:

        public Companies GetCompany(int companyID)

        {

            var returnValue = this.ObjectContext.Companies

                .Include("CompanyContacts")

                .Include("CompanyContacts.CompanyContactPhones")

                .Where(one => one.CompanyId == companyID).FirstOrDefault();

            return returnValue;

        }

Now, let’s see what this call looks like on Silverlight side.  This also demonstrates the use of parameters:

var companyQuery = _context.GetCompanyQuery(_companyID);

_context.Load<Companies>(companyQuery, (o1) =>

{

    HidePleaseWaitMessage();

    if (o.Error != null)

    {

        ErrorHandler.HandleException(o.Error);

    }

    else

    {

        this.Model = o1.Entities.First() as Companies;

    }

}, null);

As you can see, RIA services build us a query that already has the same company ID parameter for us.  Pretty cool!  However, if I look at return value (Companies object), I will notice that contacts property is actually null even though I did add .Include statement to my custom Entity Framework based method.  To get this to work, I have to modify the metadata class that RIA Services generated(RolodexDomainService.metadata.cs in my case).  I need to open this class file and look for Companies object.  I will find public EntityCollection<CompanyContactPhones> CompanyContactPhones property in it.  To get RIA Services to include child collection, I need to add Include attribute here as well:

[Include]

public EntityCollection<CompanyContactPhones> CompanyContactPhones;

I would have to take the same step to include phones collection for each contact.  If I run my code again, I will not get Company object with a list of Contacts, each containing a list of Phones.

I will try to cover update in my next post.

Thank you and do not hesitate to ask questions.

Getting Started with WCF RIA Services

I know many posts have been written on this subject by many people, but I am writing this one mostly for myself.  I find it very useful to type my thoughts on any subject and create a sample project to help me commit more information to memory.  So, here it goes.

What you need to get started.

  1. Visual Studio 2008 SP 1 (You can use 2010 as well)
  2. WCF RIA Services Beta for Visual Studio 2008 SP1 (http://www.microsoft.com/downloads/details.aspx?FamilyID=76bb3a07-3846-4564-b0c3-27972bcaabce&displaylang=en)

Here is what needs to be done next.

Create new Silverlight project.  To do so just create new project and select Silverlight.  Make sure to create a host web site as well.

image

On the next wizard screen select an option to create new host web site and enable .NET RIA Services.

image

 

Now, add new project to the solution, selecting WCF RIA Services Library under Silverlight projects.

image

Here is what your solution will look like:

image

Go ahead and delete Class1.cs from both RIAServicesLibrary projects.  What you see here are two new project.  RIAServicesClassLibrary1.Web will be server side project, the other RIA project is client side.  Now you need to establish references.  Add a project reference to SilverlightApplication1 and point it to RIASerivcesLibrary1 project.  Add a project reference to SilverlightApplication1.Web and point it to RIAServicesLirbary1.Web.

 

Now you need to create Entity Framework item inside the RIAServicesLibrary1.Web project.

image

Follow all the step of that wizard, generating a model from the database and pointing to a new or existing server connection.  You can select all or some tables from a database.

Go ahead and build your solution now.

Now add another new item to RIAServicesLirbary1.Web project and select Domain Service Class

image

Select the Entity Framework model you just created in that wizard and select tables you would like to use on the client.

image

Rebuild the solution once more to generate Silverlight side hidden classes that support RIA Services.  You can see that code if you click on Show All Files button in Solution Explorer:

image

Now, I am going to test the setup by adding the following code to MainPage.xaml.cs.  I am going to simulate the login process by getting a specific user from my Users table and checking the password:

using System.Windows.Ria;

using System.Linq;

public partial class MainPage : UserControl

    {

        DomainService1 _context = new DomainService1();

        public MainPage()

        {

            InitializeComponent();

            Login();

        }

 

        private void Login()

        {

            var query = _context.GetUsersQuery().Where(one => one.UserName == "admin");

 

            _context.Load<Users>(query, LoadBehavior.RefreshCurrent, (o) =>

            {

                if (o.Error != null)

                    MessageBox.Show(o.Error.ToString());

                else

                {

                    if ((o.AllEntities.Count() == 1) &&

                        (o.AllEntities.First() as Users).Password == "admin")

                    {

                        MessageBox.Show("Login successfull.");

                    }

 

                    else

                    {

                        MessageBox.Show("Login failed.");

                    }

                }

            }, null); ;

        }

    }

Next we need to update web.config in SilverlightApplication1.Web project using app.config from RIAServicesLirbary1.Web project as an example.  Make sure to paste all appropriate data into correct places:

<?xml version="1.0" encoding="utf-8"?>

<configuration>

    <connectionStrings>

        <add name="RolodexEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\sql2008;Initial Catalog=Rolodex;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

    </connectionStrings>

    <system.serviceModel>

        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

    </system.serviceModel>

    <system.web>

        <httpModules>

            <add name="DomainServiceModule" type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

        </httpModules>

    </system.web>

</configuration>

Run the application now to confirm that everything is working properly.  In the next post I will explore the subject of updating the data on the server.

Windows Azure Application

This is purely a bragging post :-)

I just deployed a test application to the cloud (Microsoft Azure): http://rolodex.cloudapp.net/

Here is the technology stack for it:

  1. Windows Azure
  2. SQL Azure
  3. CSLA 3.8.1
  4. Silverlight
  5. Entity Framework
  6. WCF
  7. Prism (Composite Application Guidance)
  8. Silverlight Toolkit

I promise to write a blog entry in the near future, the steps one has to follow through to create an Azure application.

Dynamically Styling Silverlight Applications

I spoke at GGMUG (Gwinnett Georgia Microsoft Users Group) on Thursday.  I was speaking about dynamically styling Silverlight applications using Implicit Style Manager from Silverlight Toolkit

Silverlight toolkit comes with about a dozen themes that anyone can use to style there applications.  In the example I am posting I use four of them,  A theme file is essentially a XAML file that contains styles for all native Silverlight controls as well as all Toolkit controls.  Implicit style manager allows developers to dynamically (or statically) load a theme and apply it to any FrameworkElement in the visual tree. 

There are only a few steps you need to do to implement this type of styling.

1.  Download and install Toolkit.

2.  Create new Silverlight application.

3.  Create new folder under applications (UserThemes in my example) and copy some or all themes from toolkit (C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Oct09\Themes is the default folder) into that folder.  Once you include all the themes into the project, set compile action to Content.

4.  Now write a few lines of code in key places to apply a chosen theme.  Here is what this code would look like:

        private void ApplyeTheme(string themeName)

        {

            Uri uri = new Uri(string.Concat("UserThemes/", themeName, ".xaml"), UriKind.Relative);

            ImplicitStyleManager.SetResourceDictionaryUri(this, uri);

            ImplicitStyleManager.SetApplyMode(this, ImplicitStylesApplyMode.OneTime);

            ImplicitStyleManager.Apply(this);

        }

5.  You can even allow application user to select a theme by creating for example a combo box loaded with available themes.

Implicit style manager does carry some overhead with it.  To minimize the overhead try to use apply mode of OneTime.  Ap0ply mode of Auto will watch for LayoutUpdated event and restyle attached element.  If you use this mode, you can apply this code to your shell (outer application frame), and any loaded control will be styled.  It sounds easy, but it will slow down your application.

As you can see, you cheaply and easily implement dynamic styling using free! software from Silverlight Toolkit.

You can download full example here.

Silverlight 3 – CollectionViewSource and Navigation

I am killing two birds with one stone in this post, covering both CollectionViewSource and Navigation framework in Silverlight 3.

To create new Silverlight application that uses Navigation framework, simply create new project in Visual Studio, and you will find Silverlight Navigation Application project template under Silverlight node.  Navigation framework in Silverlight three allows developers to create navigation structure that mimics the one of ASP.NET (or any web allocation for that matter).   In other words, this framework provide for URI driven navigation, using Uri routing feature similar to ASP.NET MVC framework.  Of course, this is really from end user perspective, not developer.  Obviously, Silverlight application cannot navigate from one to another XAML page using browser natively.  As a result, navigation framework utilizes browser bookmark feature in order to provide the user with Next/Previous navigation using actual browser buttons.  Routing engine enables the mapping between short Uri and actual XAML page that is supposed to handle the navigation event to this Uri.  Here is what this routing looks like:

            <navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}"

                             Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed">

                <navigation:Frame.UriMapper>

                    <uriMapper:UriMapper>

                        <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>

                        <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>

                        <uriMapper:UriMapping   

                           Uri="ProductDetail/{ProductId}"   

                           MappedUri="/Views/ProductDetail.xaml?ProductId={ProductId}"/>

                    </uriMapper:UriMapper>

                </navigation:Frame.UriMapper>

            </navigation:Frame>

Here is how we read this code.  The core part of navigation is Frame control.  It handles browser interaction and provide Uri mapping.  If we look at the mapper XAML, we will see that short Uri, such as “” (blank) maps to Home.Xaml.  Home.Xaml is not User Conrol, it inherits from Page control, another part of navigation framework.  Any XAML page that is supposed to handle navigation must inherit from Page.  The mapper supports tokenization as well, that is how {pageName} is mapped to /Views/{pageName}.xaml.  So, if we navigate to Uri “Home”, /Views/Home.xaml will be loaded into the frame. For example, we have HyperLinkButton as follows:

                    <HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}"

                                    NavigateUri="/About" TargetName="ContentFrame" Content="about"/>

In this case when user clicks on this button, he/she will be navigated to /Views/About.xaml that will be shown in Frame called ContentFrame.

Navigation framework also supports parameters, and incidentally it took me an hour to figure those out.  In the example above our ProductDetail mapping supports parameter called PrductId.  So, far pretty easy.  The hard part is to figure out how to set that Url.  In my case, I have a product object, and I am setting the Url in it to match my mapping.  Here is full source code for Product class and collection of products:

using System;

 

namespace SilverlightNavigationApp

{

    public class Product

    {

        public string ProductId { get; set; }

        public string ProductName { get; set; }

        public string ProductDescription { get; set; }

        public Uri Url { get; set; }

    }

}

using System;

using System.Collections.ObjectModel;

 

namespace SilverlightNavigationApp

{

    public class ProductList : ObservableCollection<Product>

    {

        public ProductList()

        {

            Add(new Product() { ProductId = "1", ProductName = "Bread", ProductDescription = "Wheat bread.", Url = new Uri("ProductDetail/1", UriKind.Relative) });

            Add(new Product() { ProductId = "2", ProductName = "Milk", ProductDescription = "Whole milk.", Url = new Uri("ProductDetail/2", UriKind.Relative) });

            Add(new Product() { ProductId = "3", ProductName = "Potatoes", ProductDescription = "Red potatoes.", Url = new Uri("ProductDetail/3", UriKind.Relative) });

            Add(new Product() { ProductId = "4", ProductName = "Water", ProductDescription = "Bottled water.", Url = new Uri("ProductDetail/4", UriKind.Relative) });

            Add(new Product() { ProductId = "5", ProductName = "Cake", ProductDescription = "Chocolate cake.", Url = new Uri("ProductDetail/5", UriKind.Relative) });

        }

    }

}

So far so good.  You can see how Url must be formatted to match product Id. I am showing product list inside a page using DataGrid.

<navigation:Page x:Class="SilverlightNavigationApp.Views.ProductList"

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

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

   xmlns:local="clr-namespace:SilverlightNavigationApp"

   xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

   xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"

   >

    <UserControl.Resources>

 

        <CollectionViewSource Source="{StaticResource ProductList}" x:Key="ViewSource" Filter="MyFilter"/>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="*"/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="Auto"/>

            <ColumnDefinition Width="*"/>

        </Grid.ColumnDefinitions>

        <TextBlock Text="Fitler:"/>

        <TextBox Grid.Column="1" TextChanged="TextBox_TextChanged" x:Name="FilterBox" Text=""/>

        <data:DataGrid

           ItemsSource="{Binding Source={StaticResource ViewSource}}"

           AutoGenerateColumns="False"

           Grid.Row="1"

           Grid.ColumnSpan="2">

            <data:DataGrid.Columns>

                <data:DataGridTextColumn Binding="{Binding ProductId}" Header="Product ID"/>

                <data:DataGridTextColumn Binding="{Binding ProductName}" Header="Product Name"/>

                <data:DataGridTextColumn Binding="{Binding ProductDescription}" Header="Description"/>

                <data:DataGridTemplateColumn>

                    <data:DataGridTemplateColumn.CellTemplate>

                        <DataTemplate>

                            <Button Content="Details" Tag="{Binding Url}" Click="Button_Click"/>

                        </DataTemplate>

                    </data:DataGridTemplateColumn.CellTemplate>

                </data:DataGridTemplateColumn>

            </data:DataGrid.Columns>

        </data:DataGrid>

    </Grid>

</navigation:Page>

You can see that I am setting the tag for the button to Url property of the Product object.  Here is how I am processing this information in click event:

        private void Button_Click(object sender, RoutedEventArgs e)

        {

            NavigationService.Navigate(((Button)sender).Tag as Uri);

        }

Here is what we can do with this in the Details page:

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

        {

            string productId = this.NavigationContext.QueryString["ProductId"].ToString();

            SilverlightNavigationApp.ProductList list = (SilverlightNavigationApp.ProductList)App.Current.Resources["ProductList"];

            Product product = (from one in list

                               where one.ProductId == productId

                               select one).FirstOrDefault();

            this.DataContext = product;

        }

Alternatively, I can use propertied of HyperLinkButton to do the same if I do not need to use dynamic parameters.  Look above for About navigation.

Now, let’s talk about ColllectionViewSource.  It suports grouping, sorting and filtering.  In the example I will use filtering technique.  The filtering is pretty easy – we just subscribe to filter event, evaluate each object, and decide whether or not show it:

    <UserControl.Resources>

        <CollectionViewSource Source="{StaticResource ProductList}" x:Key="ViewSource" Filter="MyFilter"/>

    </UserControl.Resources>

        private void MyFilter(object sender, FilterEventArgs e)

        {

            Product product = e.Item as Product;

            if (FilterBox != null)

            {

                e.Accepted = product.ProductName.ToUpper().Contains(FilterBox.Text.ToUpper()) ||

                    product.ProductDescription.ToUpper().Contains(FilterBox.Text.ToUpper());

            }

            else

                e.Accepted = true;

        }

All that is left is to call refresh when we want to response to use actions:

        <TextBox Grid.Column="1" TextChanged="TextBox_TextChanged" x:Name="FilterBox" Text=""/>

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)

        {

            CollectionViewSource source = this.Resources["ViewSource"] as CollectionViewSource;

            source.View.Refresh();

        }

Pretty simple.  You can download full example here.

Silverlight 3.0 Behaviors – Part 2

Today I am going to explore Silverlight three behaviors a little more.  In this post I am going to look at different events that can trigger an action in a behavior.  Essentially, we can specify any event on a target element to invoke a behavior. 

Again, we are going to use TargetedTriggerAction base class. This time however we are going to enable this behavior to be able to be used on a larger suite of targets.  We are going to use UIElement as the target type: TargetedTriggerAction<UIElement>.  We are only going to override one method – InvokeAction.  Here is what the class looks like:

    public class MakeLargerSmallerAction : TargetedTriggerAction<UIElement>

    {

        protected override void Invoke(object parameter)

        {

            StoryBoardHelper.PlayControlAnimation(Target, Percent);

        }

Here are a couple of things I need to explain. 

  1. This behavior is going to perform one function – change dimensions (increase or decrease the size) of the target control base on an event.  We are going to add a property that would allow our behavior to specify the factor by which the target’s size needs to increase or decrease.
  2. We are going to use animations to perform this function.  We will build animations in code.
  3. We will invoke animations based on event specified in XAML.

Here is full source code for behavior class:

using System;

using System.Windows.Interactivity;

using System.Windows;

 

namespace Behaviors

{

    public class MakeLargerSmallerAction : TargetedTriggerAction<UIElement>

    {

        protected override void Invoke(object parameter)

        {

            StoryBoardHelper.PlayControlAnimation(Target, Percent);

        }

 

        public double Percent

        {

            get { return (double)GetValue(PercentProperty); }

            set { SetValue(PercentProperty, value); }

        }

 

        public static readonly DependencyProperty PercentProperty =

            DependencyProperty.Register("Percent", typeof(double), typeof(MakeLargerSmallerAction), new PropertyMetadata((double)1));

 

 

    }

}

Here is source code for animation controller:

using System;

using System.Windows;

using System.Windows.Media;

using System.Windows.Media.Animation;

 

namespace Behaviors

{

    public static class StoryBoardHelper

    {

        public static void PlayControlAnimation(UIElement controlToAnimate, double factor)

        {

            Storyboard story = new Storyboard();

 

            //stretch horizontally

            DoubleAnimationUsingKeyFrames scaleXAnimation = new DoubleAnimationUsingKeyFrames();

            scaleXAnimation.BeginTime = TimeSpan.FromMilliseconds(0);

            scaleXAnimation.KeyFrames.Add(CreateFrame(factor, 100));

            Storyboard.SetTarget(scaleXAnimation, controlToAnimate);

            Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));

            story.Children.Add(scaleXAnimation);

 

            //stretch vertically

            DoubleAnimationUsingKeyFrames scaleYAnimation = new DoubleAnimationUsingKeyFrames();

            scaleYAnimation.BeginTime = TimeSpan.FromMilliseconds(0);

            scaleYAnimation.KeyFrames.Add(CreateFrame(factor, 100));

            Storyboard.SetTarget(scaleYAnimation, controlToAnimate);

            Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));

            story.Children.Add(scaleYAnimation);

 

            if (!(controlToAnimate.RenderTransform is TransformGroup))

            {

                TransformGroup group = new TransformGroup();

                ScaleTransform transform = new ScaleTransform();

                transform.ScaleX = 1;

                transform.ScaleY = 1;

                group.Children.Add(transform);

                controlToAnimate.RenderTransformOrigin = new Point(0.5, 0.5);

                controlToAnimate.RenderTransform = group;

            }

            story.Begin();

 

 

        }

 

        private static SplineDoubleKeyFrame CreateFrame(double value, double duration)

        {

            SplineDoubleKeyFrame frame = new SplineDoubleKeyFrame();

            frame.Value = value;

            frame.KeyTime = TimeSpan.FromMilliseconds(duration);

            return frame;

        }

    }

}

Here is how we are setting up behaviors in XAML:

        <TextBox x:Name="FirstBox" TextWrapping="Wrap" Margin="20,0,0,7" d:LayoutOverrides="Height">

            <i:Interaction.Triggers>

                <i:EventTrigger>

                    <Behaviors:SelectOnFocusAction/>

                </i:EventTrigger>

                <i:EventTrigger EventName="GotFocus">

                    <Behaviors:MakeLargerSmallerAction Percent="1.2"/>

                </i:EventTrigger>

                <i:EventTrigger EventName="LostFocus">

                    <Behaviors:MakeLargerSmallerAction Percent="1"/>

                </i:EventTrigger>

            </i:Interaction.Triggers>

        </TextBox>

In the XAML above we are setting up three different behaviors.  First one I covered in previous post.  The second trigger increases the size of the control by factor of 1.2 – 20 %.  This action is executed when GotFocus event fires.  The last trigger changes the control’s size back to original size.

You can download full sample project here.

Unable to debug Silverlight applications

I have run into this issue numerous times, but from time to time I keep forgetting what causes this issue.

The symptom is that your breakpoints inside Silverlight application cannot be hit, and the information message states that “No symbols have been loaded for this document.”  What is usually strange that I was able to debug just a little while ago.

The most common cause is that Silverlight debugging is not turned on on web site project that hosts Silverlight application.  However, I have not run into this issue.  My number one problem is that ClientBin folder stops being updated.  This can be caused by the fact that somehow the folder is checked into source control and compiler cannot overwrite the XAP file any longer.  Or, file is being held by OS, maybe because Visual Studio crashed at some point before.  To troubleshoot, just check your XAP from ClientBin folder and check source controls.

Dynamically setting initialization parameters in Silverlight application

One of the properties on object tag for Silverlight control in initParams or initialization parameters:

 

 <object name="objSilverlight" data="data:application/x-silverlight-2," type="application/x-silverlight-2"

            width="100%" height="100%">

            <param name="source" value="ClientBin/SilverlightInitParams.xap" />

            <param name="onError" value="onSilverlightError" />

            <param name="background" value="white" />

            <param name="minRuntimeVersion" value="3.0.40624.0" />

            <param name="autoUpgrade" value="true" />

            <param name="initParams" value="key=value,key1=value1"/>

            <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration: none">

                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight"

                    style="border-style: none" />

            </a>

        </object>

We can use this parameter to inform our Silverlight application about a specific piece of data it may need.  To access this data inside Silverlight application, you would need to use arguments from application startup event:

private void Application_Startup(object sender, StartupEventArgs e)

        {

            MainPage page = new MainPage();

            var paramList = e.InitParams.ToList();

Our initial parameters collection is exposed as a dictionary off Startup Event Arguments.

The next step it to dynamically set the parameter.  The problem is that the object tag / Silverlight application creation occurs on the client side, which has no access to server data.  We are going to play a trick here and modify our aspx page to delegate creation of actual parameters string to the page itself:

<param name="initParams" value="<%=GetInitParameter() %>" />

The next step is to write a method in our page that returns a string in format key=value.  Here is entire code behind for our aspx page:

    public partial class _Default : System.Web.UI.Page

    {

        private string _params = string.Empty;

 

        protected void Page_Load(object sender, EventArgs e)

        {

            // put a fake variable into session.  Ordinarily, we are just getting

            // data from somewhere on the server. 

            // could even be a database call if necessary

            Session["User"] = "Sergey Barskiy";

 

            //now set a variable

            _params = string.Concat("User=", Session["User"].ToString());

        }

 

        public string GetInitParameter()

        {

            return _params;

        }

    }

Here is what we do inside our Startup routine in Silverlight application:

 

        private void Application_Startup(object sender, StartupEventArgs e)

        {

            MainPage page = new MainPage();

            var paramList = e.InitParams.ToList();

            page.Key.Text = String.Format("{0} = ", paramList.First().Key);

            page.Value.Text = paramList.First().Value;

 

            RootVisual = page;

 

        }

You can download this sample application here.

Silverlight 3.0 Behaviors – Part 1

In this post I will start exploring behaviors in Silverlight 3.0.  This topic is very large, and it will take me a few posts to cover at least key aspects of behaviors.

A little background on the subject.  Silverlight, unlike WPF does not natively support triggers that would allow the developer to change UI based on criteria or data.  In Silverlight 3.0 we now have a facility to support similar behavior.  One key usage scenario for behaviors is to allow a designer to support UI changes based on user actions without writing any code.

To extend an existing behavior base class we need to add a reference to System.Windows.Interactivity DLL.  We will start with a simple behavior.  By default Silverlight Textbox does not select all the text when it gets focus.  This however us a desirable behavior from a user perspective in many scenarios.  So, for our first excursion into Silverlight behaviors we will write “Select All Text On Focus in Textbox” behavior.

We will start by extending an existing class in SilverlightTargetedTriggerAction<C>.  In our case we are supplying generic type for our behavior – Textbox - TargetedTriggerAction<TextBox>. 

We are specifying Textbox as the target type for our behavior.  Typically, we would specify an action and an event that would invoke the action on the behavior.  In our case we however want to make sure that they only event that invokes the behavior is GotFocus event.  So, we are leaving our Invoke method blank.  Here is the final version of the class:

using System;

using System.Windows.Controls;

using System.Windows.Interactivity;

 

namespace Behaviors

{

    public class SelectOnFocusAction : TargetedTriggerAction<TextBox>

    {

        protected override void OnAttached()

        {

            base.OnAttached();

            Target.GotFocus += Target_GotFocus;

        }

 

        void Target_GotFocus(object sender, System.Windows.RoutedEventArgs e)

        {

            Target.SelectAll();

        }

        protected override void OnDetaching()

        {

            base.OnDetaching();

            Target.GotFocus -= Target_GotFocus;

        }

 

        protected override void Invoke(object parameter)

        {

            //do nothing

            // we are handling specific event we are interested in

            // by attaching events to the target text

        }

       

    }

}

 

You can download the sample project with this behavior and text page here.

Silverlight 3.0 – Perspective 3D

I am continuing covering new features in Silverlight 3.0.  The subject of this post is Silverlight 3.0.

Perspective 3D is new type of transforms available in Silverlight 3.0.  It allows developers to create a 3D projection of a two-dimensional object.  A key power of this new feature is the fact that any UI element in Silverlight can be used as a target for this feature.  This means you can rotate a control in thee dimensional space around any axis.  In my example I am using this Plane Projection to rotate a calendar:

image

I am rotating the calendar control around X axis with center of rotation at x=0, y=0.5.  These values are set as relative values with 0.5 being the middle of the plane.  This allows us to create a rotation similar to an actual wall calendar’s page  turned by a person.  You can rotate around multiple axis in multiple planes, create nice visual effects.  Pretty cool.

 

You can download the sample project here.

Assembly caching in Silverlight 3.0

I am continuing discussing new features on Silverlight 3.0.  Current topic is assembly caching. 

In Silverlight 2.0 all assemblies that your application needed would have to be included in your XAP file(s).  In Silverlight 3 you can force browser to cache one or more assemblies that your application needs.  In case of caching your can tell Silverlight runtime to pull these cached assemblies from a predefined location.  This location can be the same folder as your Silverlight XAP file or anywhere else on the internet.  To cache assemblies, you can turn on caching option in project properties:

image

What you will notice if you do that, that Microsoft assemblies such as System.Windows.Controls.Data (contains DataGrid) will not be included in your XAP file.  Instead if you look at the manifest file inside your XAP file, you will notice that this DLL is pulled at runtime from the same folder as your application.  The information about this is incluided in assembly manafiest in your main XAP file.  Here what it would look like:

<Deployment
xmlns=http://schemas.microsoft.com/client/2007/deployment
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
EntryPointAssembly="CompanySLApp"
EntryPointType="CompanySLApp.App"
RuntimeVersion="3.0.40624.0">
  <Deployment.Parts>
    <AssemblyPart x:Name="CompanySLApp" Source="CompanySLApp.dll" />
  </Deployment.Parts>
  <Deployment.ExternalParts>
    <ExtensionPart Source="System.Windows.Controls.Data.zip" />
    <ExtensionPart Source="UtilityFunctions.zip" />
    <ExtensionPart Source="System.Windows.Controls.Data.Input.zip" />
    <ExtensionPart Source="System.Windows.Data.zip" />
    <ExtensionPart Source="System.ComponentModel.DataAnnotations.zip" />
  </Deployment.ExternalParts>
</Deployment>

If you try to do the same with your assembly (for example you have a common assembly shared between two Silverlight applications), your will notice that it is still included.  The reason for that is that compiler is looking for XXX..extmap.xml where XXX is your assembly names without DLL extension.  So, all your need to do is create one.  You can look for an example in C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client folder for any extmap files for Microsoft assemblies.  You can use a utility to generate your own too.  (http://www.devcorner.info/Sources/Emm.zip).  Once you generate extmap file for your assembly, make sure it is located in the same folder as the assembly dll.  Once you rebuild your solution, you will find XXX.zip file in ClientBin folder that contains your XXX.dll assembly file.  Now, at runtime browser will cache that assembly for you, saving download time during application start up time.  Of course, this depends on how caching is setup for virtual directory that contains your Silverlight application.  You can also pass addition parameters to emm.exe utility and force it to setup download URL for your included assembly that point to an absolute URL somewhere else.  Using this feature for example, you can host assemblies that you can include in many applications on a separate server with a predefined URL.

Please feel free to ask questions about this feature.  You can upload sample application that uses assembly caching here.

Silverlight And N-Tier Data Access using Entity Framework

As I mentioned before I talked at GGMUG last Thursday.  I talked about Entity Framework in general and specifically in N-Tier applications, such as Silverlight applications.  I think I got a few folks excited about using Entity Framework.  The key thing to remember when using EF in N-Tier applications is that EF keeps track of changes in the context object.  Unfortunately, this object does not survive the trips between client and the server.  As a result, my recommendation is to use EF in conjunction with a business layer framework, such as CSLA. You can download slides and sample project here.  Please feel free to post comments or questions.

ElementName Binding in Silverlight 3

As I mentioned before, I will be working on a series of posts on new features in Silverlight 30.  This post is all about ElementName binding.

Probably my favorite feature in Silverlight 3 that affects developers writing business applications is addition of ElementName property to Binding object.  This features existed in WPF since version 1, but was missing from Silverlight 2.0.  The basic strategy behind the feature is the ability to bind a property on one UI element to a property on another UI element.  Here is a very common scenario in a business application that this features makes much simpler to implement.  Say, you have two co-dependent combo boxes.  For example, you have a combo box  with a listing of states, and once a state is selected, second combo box is populated with a list of cities for that state.

The basic syntax for ElementName binding is as follows:

ItemsSource="{Binding ElementName=ParentCombo, Path=…

In my case, I am going to illustrate the feature by having a list of dozens, each with a list of numbers that belong to that dozen.  Here are my classes:

    public class Each

    {

        public string Name { get; set; }

        public int Id { get; set; }

 

        public static Each GetEach(int id)

        {

            Each newEach = new Each();

            newEach.Id = id;

            newEach.Name = id.ToString();

            return newEach;

        }

    }

    public class Eaches : List<Each>

    {

 

    }

    public class Dozen

    {

        public string Name { get; set; }

        public int Id { get; set; }

        public Eaches Items {get;set;}

 

        public static Dozen GetDozen(int id)

        {

            Dozen newDozen = new Dozen();

            newDozen.Id = id;

            newDozen.Name = id.ToString();

            newDozen.Items = new Eaches();

            for (int i = 1; i <= 12; i++)

            {

                newDozen.Items.Add(Each.GetEach(((id – 1) * 12) + i));

            }

            return newDozen;

        }

    }

    public class Dozens : List<Dozen>

    {

        public Dozens()

        {

            for (int i = 1; i < 10; i++)

            {

                Add(Dozen.GetDozen(i));

            }

        }

    }

Now, I am going to add my Dozens class as a resource to a xaml page:

<UserControl x:Class="SilverlightApplication7.MainPage"

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

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

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   xmlns:local="clr-namespace:SilverlightApplication7"

   mc:Ignorable="d"

   d:DesignWidth="640"

   d:DesignHeight="480"

   >

    <UserControl.Resources>

        <local:Dozens x:Key="data"/>

    </UserControl.Resources>

The last step is to tie two combo boxes together:

  <Grid x:Name="LayoutRoot">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="30"/>

            <RowDefinition Height="Auto"/>

        </Grid.RowDefinitions>

        <ComboBox x:Name="ParentCombo" Width="300" HorizontalAlignment="Left" ItemsSource="{StaticResource data}" DisplayMemberPath="Name"/>

        <ComboBox x:Name="ChildCombo" Grid.Row="2" Width="300" HorizontalAlignment="Left" ItemsSource="{Binding ElementName=ParentCombo, Path=SelectedItem.Items}" DisplayMemberPath="Name"/>

    </Grid>

Here is the summary of what we did.  We used Dozens class (the list of Dozen objects) that was populated when its constructor was invoked as part of resources collection initialization.  Then we used this object to populate ParentCombo with data.  We set DisplayMemberPath to show a desired property in combo box.  Then we used SelectedItem property from ParentCombo to be the source of items in ChildCombo.  As the user selects an item in ParentCombo, we can see that list of items inside ChildCombo is changing without any code-behind.  We also use dotted syntax (Path=SelectedItem.Items), so we can tie the eaches collection in dozens object to be the item source for another UI element.  In our case SelectedItem of ParentCombo is actually an instance of a Dozen object.  Items property of it gives us eaches collection.  Simple, yet very powerful feature.

You can download this sample project here.

I will be talking at GGMUG on Thursday, September 10th

I will be presenting at the next Gwinnett Georgia Microsoft Users Group this coming Thursday.  The topic of my presentation will be Entity Framework in general and its applications to Silverlight development.  I will be posting the zip file with slides and sample application immediately after the presentation.

I hope to see you there!

Atlanta Silverlight Fire Starter Event

Atlanta Silverlight Fire Starter event yesterday was awesome!  There were over 100 people attending.  The vast majority stayed there for the entire length of the event that lasted from 8am until 6pm.  All presenters did a great job.  All attendees were great.  They actively participated in all discussions, asking many questions.  Many thanks to all the event sponsors who helped make Fire Starter possible,  The event was truly a communal effort pulled off by many people excited about the technology and willing to share their knowledge and experience.  Please see Silverlight Atlanta site for more details about the event and its sponsors.

I posted my presentation about Deploying Silverlight Applications that I presented at the Fire Starter here.  The zip file contains sample project, database backup and PowerPoint presentation.

I was also going to chat for a couple of minutes about reporting in Silverlight and localization in Silverlight, however we of ran out of time by the end of the day.  I pushed an example in localization into the zip file above.  Just look at how title is setup on the main screen.  If you are interested in reporting in Silverlight, just find the blog entries on this topic on this blog.  There is also a sample project here on that showcases reporting in Silverlight.

I’d like to thank again to all involved in Fire Starter event, presenters, attendees and sponsors alike.

Bug Fix Release for SilverlightDatabase project

I just posted a new release for SilverlightDatabase project on CodePlex : http://silverdb.codeplex.com/

There was an issue with the latest release – you could potentially get an error when adding data to a table previously saved.  I posted a bug fix release for this that also includes unit test to verify that the issue is resolved.

Please download this release if you are using this project.

Thank you.

Webinar (Reporting in Silverlight) download

Recording of the webinar I presented is now up on Magenic web site.  Here is the address: http://www.magenic.com/Default.aspx?tabid=635

Since I am not sure if the sample project is available, I decided to post the zip file with the sample project here.

Please let me know if you have any questions. 

More on CodePlex project

I could not have been more pumped about my Silverlight database project (See my post from a week ago for details).  I searched CodePlex for “Silverlight”, and now my project is number 20 on the list sorted by relevance out of total  622 projects.  It is also listed on Silverlight MSDN main page today: http://msdn.microsoft.com/en-us/silverlight/default.aspx.  It got 68 downloads and 311 visits in just four days this week.  Awesome!

I just posted another update to this project on CodePlex.  Silverlight Database now supports encryption and compression.

A small localization gripe for Silverlight

I just installed Silverlight 3 last Friday.  One feature that I was hoping to see fixed was localization in Silverlight.  Ideally, I like to bind localized data, such as labels in XAML.  For example:

<UserControl.Resources>

<resources:ModuleResources x:Key="LanguageResource" />

then,

<TextBlock HorizontalAlignment="Center" Margin="7,0,7,0" VerticalAlignment="Center" Text="{Binding Source={StaticResource LanguageResource}, Path=SomePropertyName}"></TextBlock>

This works great, but there is one issue.  Even though I mark the resource as public, any time I add a new value or edit and existing value, ModuleResources .Designer.cs gets re-written, and its constructor is marked as internal, not public.  If I run the app, I get the dreaded unknown type exception.  At that point I have to manually edit designer file and mark constructor as public.  Not a major problem, but I would like not to have to do this.

CodePlex project

I just uploaded and published new CodePlex project I have been working on.  It is an Isolated Storage based database for Silverlight.  It supports multiple strongly typed tables, basic Linq based operations, addition and deletion of ranges of items, deletion of items based on condition.  You can also directly bind data to UI in Silverlight because base table inherits from ObservableCollection.  I am planning to put encryption and compression support into it next along with lazy loading of table.  Currently all tables are loaded into memory when database is opened.

Please take a look at http://silverdb.codeplex.com/

I would very much appreciate comments and feature requests related to this project.

Thanks in advance for the feedback.

Silverlight 3 Features

I am planning to write some posts on new features in Silverlight 3.0.

I decided to start with the easiest one – out of browser support.  Start by creating new Silverlight application in Visual Studio.  Once it is created, go to properties of the Silverlight application project.  You will see this window:

image

Check “Enable running application out of browser”, then click on Out-of-Browser Settings button.  You will see this screen.

image

Once you fill in all the settings, you are ready to go.  All settings from this screen are stored in XML file called OutOfBrowserSettings.xml.  The actual fact that a particular application is enabled for out-of-browser support is stored in .csproj file.

Once you run the application, if you right-click on the application, you will see context menu with additional option – install on desktop.  If application is already installed, the option changes to remove application.

The installed application can be now run from the computer from the shortcut.  When you run the app from the shortcut, it is not going run in the browser, instead it is run in sllauncher.exe, a special program designed to host Silverlight application.  At that point, you do not have access to browser based functionality.  So, before you reach to HtmlPage.Window, check to see if application is running in browser.  You can do this by checking App.Current.IsRunningOutOfBrowser property.

Webinar on reporting in Silverlight

I am presenting a webinar on July 28th on reporting in Silverlight.  This webinar is hosted by my employer, Magenic Technologies.  If you would like to register and watch this event, please follow this link: http://guest.cvent.com/EVENTS/Info/Invitation.aspx?e=6ca01a01-e2bd-4a77-a057-a63ab2208e81

There should be some tome allocated for questions and answers as well.

Thank you.

Status Update

I am very tired, but Silverlight application our team has been working on for 6+ months is now officially live!  We saw that someone used it over the weekend!

More reflections on the project are to come in the next few weeks.

Setup Silverlight application with WCF service to run over HTTPS/SSL

Here are the steps in achieving this task.

1. Setup WCF service.

To do this you have to alter web.config file for the web site that hosts the service.  You have to add security setting to basisHTTP binding that is used by Silverlight application to connect to the WCF service.  Here is an example of the entire server side system.serviceModel section of web.config file

<system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfPortalBehavior">
                    <serviceMetadata httpGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="true"/>
                    <compression/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings>
            <basicHttpBinding>
                <binding name="basicHttpBinding_IWcfPortal_HTTPS"
                        maxReceivedMessageSize="2147483647"
                        receiveTimeout="00:30:00"
                        sendTimeout="00:30:00"
                        openTimeout="00:10:00"
                        closeTimeout="00:5:00">
                    <readerQuotas
                        maxBytesPerRead="2147483647"
                        maxArrayLength="2147483647"
                        maxStringContentLength="2147483647"
                        maxDepth="1024"/>
            <security mode="Transport">
                <transport clientCredentialType="None"/>
            </security>

                </binding>
            </basicHttpBinding>
        </bindings>
        <services>
            <service name="RootNamespace.Library.Wcf.Host"
                     >

                <endpoint binding="basicHttpBinding"
                          contract="RootNamespace.Library.Wcf.Silverlight.IWcfPortal"
                          bindingConfiguration="basicHttpBinding_IWcfPortal_HTTPS">

                </endpoint>
            </service>
        </services>

    </system.serviceModel>

2.  Configure Silverlight application to use HHTPS.

To do this you have to alter ServiceReference.ClientConfig and add security setting.  Here is an example of the entire file

<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding    name="basicHttpBinding_IWcfPortal"
                            maxBufferSize="2147483647"
                            maxReceivedMessageSize="2147483647"
                            receiveTimeout="00:10:00"
                            sendTimeout="00:10:00"
                            openTimeout="00:2:00"
                            closeTimeout="00:2:00">
                     <security mode="Transport" />

                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint    address="https://www.examplesite.com/WcfSilverlightPortal.svc"
                        binding="basicHttpBinding"
                        bindingConfiguration="basicHttpBinding_IWcfPortal"
                        contract="RootNamespace.Library.Wcf.Silverlight.IWcfPortal"
                        name="BasicHttpBinding_IWcfPortal" />
        </client>
    </system.serviceModel>
</configuration>

3.  Setup client access policy for the web site.

This is done by editing file at the root of your domain.  For example, if you are hosting everything in a virtual directory called Portal, your clientaccesspolicy.xml still needs to reside at the root of the domain, not in that virtual directory.  You can locate the physical path to that in properties of the root web site in IIS.  Here is an example of the entire file that enables HTTP access

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from http-request-headers="*">
                <domain uri="http://*"/>
                <domain uri="https://*"/>
            </allow-from>
            <grant-to>
                <resource path="/" include-subpaths="true"/>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

You can further restrict access by updating resource node or allow-from node.

You can verify the correctness of clientaccesspolicy.xml location in SilverlightSpy.  Go to Tools->Cross-domain access policy valuator an enter your domain there, for example http://www.examplesite.com

You can also hit your service directly.  If you follow the example in step 2, you can type in the following into your browser:https://www.examplesite.com/WcfSilverlightPortal.svc

Downloading Silverlight application over HTTPS

I encountered an interesting problems today.  I was trying to setup a Silverlight application to run over https.  I was able to successfully run it over HTTP prior to this task.  However, when I switched URL to https://www.mysite.com, I got the error 2104 “Could not download the Silverlight application”.  The solution that I had to experiment with to discover (Google was not help) was setting expiration time to 1 minute.  It worked perfectly fine with expire immediately setting for http protocol, but not https.

Customizing look of a Silverlight button

During my Introduction to Silverlight presentation at the Atlanta .NET users group, someone suggested that I show how make a button with rounded corners in Silverlight.  I was a bit short on time, and it was getting late, so I decided to write a blog post on the subject matter instead.  So, here it goes.

Goal – make Silverlight button that has rounded corners using Blend

Step by step how to:

  1. Create new Silverlight application
  2. Save it
  3. Now you should have Page.xaml open in Visual Studio
  4. Open the same application in Blend
  5. Open Page.xaml
  6. Add a button to it.  If Button control is not visible, click on Assets(>>) button, select button
  7. Now double-click on button in toolbar to add it to Page.xaml
  8. Right-click on the button, select Edit Control Parts (Template), then Edit a Copy.  This way we will retain preloaded template, but will only change small parts of it
  9. Type is key for newly create style, such as RoundedButtonStyle
  10. Select application for Define In option.  This way you can use this style for any button in application
  11. Now, you should have app.xaml open with button control visible
  12. Expand everything in Template tree in Objects and Timeline window
  13. Click on element called Background, set CornerRadius in Properties window to 10,10,10,10
  14. Click on element called BackgroundAnimation, set CornerRadius in Properties window to 10,10,10,10
  15. Click on element called BackgroundGradient , set RadiusX and RadiusY in Properties window to 10
  16. Click on element called DisabledVisualElement, set RadiusX and RadiusY in Properties window to 10
  17. Click on element called FocusVisualElement, set RadiusX and RadiusY in Properties window to 10
  18. Save all
  19. Flip back to Visual Studio and run the application
  20. You can now see your rounded button in action

Your XAML for the button should look something like this:

<Button Content="Button" Margin="5,10,5,0" Style="{StaticResource RoundedButtonStyle}"/>

If you have template set instead, just change the XAML to use the style

All done and easy as pie!

In this little excersize we did not change the look drastically.  To do that instead of choosing edit a copy in step 8, choose Create Empty.  Now you will need to add visual elements yourself.  For a quick and dirty rounded button from scratch, add a rectangle and set Radius X and Y to the values of your liking.  This of course will not give you mouse over effects, disabled and focus effect etc…  You will still need to code those using visual states.  You can see those in Interaction window if you click on a button.  If you do not see the states, you may need to click on little drop down on top of the screen and choose Edit Control Parts –> Edit Template

Please feel free to ask questions if you cannot find a particular option.

Introduction to Silverlight

I just posted the sample project I used for “Intro to Silverlight” presentation at the Atlanta .NET Users group meeting yesterday on SkyDrive.  Please follow this link to get the sample project:

I would like to thank everyone who attended the meeting.

Atlanta .NET Users Group

It is official now.   I will be speaking at the next Atlanta .NET Users Group (http://atldotnet.org/).  The topic is Introduction to Silverlight.  It has been a while since I got an opportunity to talk in front of Atlanta users group, and I am quite excited about it.

RIA Services for Silverlight

I downloaded the CTP of RIA Services for Silverlight along with accompanying documentation this morning.  I have read the documentation and wanted to share a few thoughts on this product.

The product looks very promising to me.  Here is an overview of the key features.  You can configure RIA Services to use ether Linq to SQL or Entity framework as data access layer, which gives you flexibility along with possibility to use services over non-SQL Server databases.  You can quickly generate service class directly off your EF or LTS data model.  This means direct support for RAD application development.  There is no difference in accessing the service from Silverlight client in comparison to plain WCF service.  The RIA Services also support validation via custom attributes.  It has built-in attributes such as required field or minimum / maximum string length attribute.  These attributes are setup on  metadata class that corresponds to the entity class it is designed to validate and enhance.  In addition to pre-built attributes you can create custom validation via custom validation attribute.  You can also share classes between client and server side via shared class (decorated with Shared attribute).  You can also define custom queries on your data context.  You can use the following Linq clauses for querying: where, orderby and skip or take.  You also have support to delete, insert and update operations.  All CRUD operations are supported either via attributes or naming conventions for access methods.  There is also built-in change tracking and ability to revert changes via interfaces: IEditableObject, IChangeTracking, IRevertibleChangeTracking,  IEditableCollection.  There is also support for authorization via custom attributes as well.

One interesting thing to notice is that the code for client side is entirely generated by RIA Services framework.  So, on the client side you do not see any code – it is in hidden classes under the project.  Very nifty trick.

One last note – RIA Services framework seem to implement a lot of the features that CSLA for Silverlight has.  Almost feels like the authors of RIA Services were quite familiar with CSLA for Silverlight :-)

Silverlight 3.0

I read a few notes from Mix 09 about Silverlight 3.0.  It has a lot of great new features.  Read for yourself if you would like.  Here is a link to a free short eBook that covers parts of new functionality.

http://download.microsoft.com/download/3/0/5/3055A230-B06F-4A58-AC93-B7CFD2184A70/FirstLookSL3Moroney.pdf

Working with resources in Silverlight

Localizing a Silverlight application is a pretty trivial task if you use resources.  Once you create a resource file you are working with, you can use the code-behind class in XAML and bind to properties from that class that contain localized strings.  First, import the namespace that is used for resx file, typically Application\Resources

xmlns:Localized="clr-namespace:MyApplication.Resources"

Then add an instance of a specific resx code-behind class to resources in your user control

<UserControl.Resources>
    <Localized:SpecificFile x:Name="LocalizedStrings"/>

In this case SpecificFile corresponds to SpecificFile.resx.  Now that this is done, you can bind labels to it

<TextBlock Text="{Binding Path=MyPropertyFromResourceFile}/>

There is one issue though, if you edit resource file again in resources editor, and save it, the constructor scope in code behind is set to internal.  This in turn will cause an exception (AG_E_PARSER_UNKNOWN_TYPE  ) when you try to load this user control.  All you have to do to fix it is edit code behind file for you resource file and change its constructor to public.  Unfortunately, you have to do it every time you edit the file in resources editor.

Atlanta Code Camp 2009

This year’s code camp is upon us.  I have volunteered to speak at this code camp.  My topic is “Building Silverlight Business Applications using CSLA.NET for Silverlight”.  Please check out the Code Camp web site for more details.  As always, I am excited to speak in front of my fellow coders.

Download presentation and sample project here.

Editing Silverlight’s DataGrid’s templates in Blend

Blend has a small issue when it comes to editing of column templates for DataGrid.  If you define the template in-line as part of column definition, there is no way to edit that in Blend.  There is an easy workaround however.  You need to define DataTemplate as part of user control’s resources.  Once you open the user control in Blend, you can flip to resources tab and click on that template in order to edit it. 

Deploying Silverlight applications that use CSLA for Silverlight

Here are a few steps that need to be taken in the process

  • Update XAP file for Silverlight application in order to set deployment time IP address/name
  • Make sure to install .NET framework version 3.5 SP1 on the application server that hosts WCF service
  • Check and create if missing MIME types for virtual directory that hosts Silverlight web application:
    • Extension: .xap MIME type:application/octet-stream
    • Extension: .xaml MIME type: application/xaml+xml
  • Set execute permissions on virtual directory to scripts only
  • Set content expiration to desired setting – I set mine to expire immediately
  • Update SQL server (or other database) connection string WCF host web.config file.  If you are using IP protocol, then here is an example: Data Source=127.0.0.1\SQL2008;Initial Catalog=MyDBName;User ID=myUser;Network Library=dbmssocn

Binding to Silverlight WrapPanel

I had recently investigated the use of WrapPanel for Silverlight.  You can download it along with other controls as part of Silverlight Toolkit.  Example on the web site does not demonstrate the binding to it, so here is how you would do it.

You cannot bind to WrapPanel directly because it does not have property to bind a list of items to.  So, you have to use it as part or a control that inherits from ItemsControl.  In the following example we are setting up ItemsPanel for ItemsControl to be WrapPanel.  Then we also define a template for each individual items contained within the list.  I am binding to SelectedItems property of a an object that ItemsControl’s DataContext property is pointing to.  This property contains a list of items as List<T>.  Each item has properties MyImage1, MyImage2, MyImage3, Name.  So each item within the wrap panel has a title (Name) and three pictures.  Here is the XAML for it:

<ItemsControl ItemsSource="{Binding SelectedItems}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <toolkit:WrapPanel>
                        </toolkit:WrapPanel>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="5,5,5,5" >
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <PersonalysisSilverlightApplication:SLBackBoxUserControl />
                            <TextBlock FontSize="12" Foreground="#FFFFFFFF" Text="{Binding Path=Name}" TextWrapping="NoWrap" FontFamily="Arial" VerticalAlignment="Top" Grid.Row="0" Margin="5,5,5,0" HorizontalAlignment="Left" />

                            <Image Source="{Binding Path=MyImage1, Converter={StaticResource ConvertImage}}" Grid.Row="1" Margin="5,0,5,2" VerticalAlignment="Top" HorizontalAlignment="Left" />

                            <Image Source="{Binding Path=MyImage2, Converter={StaticResource ConvertImage}}" Grid.Row="2" Margin="5,0,5,2" VerticalAlignment="Top" HorizontalAlignment="Left" />
                            <Image Source="{Binding Path=MyImage3, Converter={StaticResource ConvertImage}}" Grid.Row="3" Margin="5,0,5,2" VerticalAlignment="Top" HorizontalAlignment="Left" />

                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

– Sergey

Showing images from database in in Silverlight

You can show images in Silverlight using Image control.  You can furthermore bind Source property of the image to byte[] type property of a business object.  You would think this is sufficient, but it is not.  You will need a converter to convert byte array into image source.

Here is the class for converter

public class ImageSourceConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        BitmapImage bitmap = new BitmapImage();
        bitmap.SetSource(new MemoryStream((Byte[])value));
        return bitmap;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Here is how this class is used in a control:

<UserControl.Resources>
       <helpers:ImageConverter x:Key="ConvertImage"/>
   </UserControl.Resources>

<Image Source="{Binding Path=MyByteArrayPropertyName, Converter={StaticResource ConvertImage}}" />

Design surface in Silverlight

If you are working on a resizable user control in Silverlight, you usually do not specify height and width of any elements in order to ensure that all controls resize properly when application size changes.  For example if you use Grid as your layout base, you can specify relative sizes for columns and rows in format of Width=”1*” or Height=”1*”.  Runtime will interpret  the numbers next to * and will use them as ratios.  As a result, you cannot see this control in Blend because the default size is zero.  So, how do you deal with this?  You have to specify design size (width and height).

Here is area from header of such control:

<UserControl x:Class="MyNamespace.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignWidth="581" d:DesignHeight="355">

Once this is done, you can easily estimate final layout in Blend.   Blend automatically adds this code to controls you design in it.

Full screen toggling in Silverlight

If you would like to push browser in and out of full screen mode from Silverlight application, you can do this very easily.

To go full screen:

Application.Current.Host.Content.IsFullScreen = true

To go to normal display:

Application.Current.Host.Content.IsFullScreen = false

Since Application.Current.Host.Content.IsFullScreen is a property, you can also test for current mode.

Reporting in Silverlight

Reporting in Silverlight environment has one major problem.  Silverlight does not have a report viewer control for either SQL Server reporting services or Crystal reports.  As a result, one has to come up with a workaround that uses existing report viewer controls.  Luckily both Crystal and SSRS have report viewer controls designed for the web.  So, all we need to do is cleanly integrate these controls into a Silverlight application, using browser integration capabilities of Silverlight.  By cleanly, I mean as cleanly as possible :-) .

We have two options to do this.  We can launch another browser window from Silverlight and open the report in new ASPX page or we can embed a new web page that hosts report viewer control inside the web page that hosts Silverlight application.  I will demonstrate these options in the following manner.  Launch a new web page that hosts SSRS report viewer and embed a web page that hosts Crystal reports viewer.

This post builds on top of previous post I had about SSRS implementation.

SSRS implementation

Create ASPX page for report viewer:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReportViewerForm.aspx.cs"
    Inherits="MyWeb.ReportViewerForm" %>
<!–
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">–>
<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">
<head runat="server">
    <title>Report</title>
</head>
<body>
    <form id="form1" runat="server" style="height:100%" >
    <div style="height:100%" >
        <rsweb:ReportViewer ID="MainReportViewer" runat="server" 
            AsyncRendering="false"
            ProcessingMode="Remote"
            Width="100%"
            ShowExportControls="True"
            ShowFindControls="True"
            ShowParameterPrompts="False"
            ShowPromptAreaButton="False"
            ShowRefreshButton="False"
            BackColor="White">
            <ServerReport DisplayName="MainReport" ReportServerUrl="" />
        </rsweb:ReportViewer>
    </div>
    </form>
</body>
</html>

Create a class to launch a report with the following routine:

public static void LaunchReport(string reportName)
       {
           Uri sourceUri = new Uri(HtmlPage.Document.DocumentUri, Application.Current.Host.Source.ToString().Substring(0, Application.Current.Host.Source.ToString().IndexOf("ClientBin") – 1) + "/ReportViewerForm.aspx?ReportName=" + reportName);

           if (ArePopupsAllowed())
           {
               System.Text.StringBuilder codeToRun = new System.Text.StringBuilder();
               codeToRun.Append("window.open(");
               codeToRun.Append("\"");
               codeToRun.Append(sourceUri.ToString());
               codeToRun.Append("\",");
               codeToRun.Append("\"");
               codeToRun.Append("\",");
               codeToRun.Append("\"");
               codeToRun.Append("width=1100,height=900,scrollbars=yes,menubar=no,toolbar=no,resizable=yes");
               codeToRun.Append("\");");
               try
               {
                   HtmlPage.Window.Eval(codeToRun.ToString());
               }
               catch (Exception ex)
               {
                   // do something               }
           }

           else
              //inform the user that popups need to be enabled
       }

ArePopupsAllowed function tests if popups are allowed in the browser.  Contact me if you need this code.

If you need to pass in parameters, you can easily pass them in as query parameters and parse them inside  ReportViewerForm.aspx just like the report name itself.  Here is code in Load event for this web page:

protected void Page_Load(object sender, EventArgs e)
        {
            MainReportViewer.ProcessingMode = ProcessingMode.Remote;
            MainReportViewer.ServerReport.ReportPath = "/MySSRSReports/" + this.Request.QueryString["ReportName"];
            MainReportViewer.ServerReport.ReportServerUrl = new Uri("http://localhost:8080/ReportServer_SQL2008");
            List<ReportParameter> parameters = new List<ReportParameter>();
            List<string> values = new List<string>();
            values.Add("1");
            values.Add("2");
            values.Add("3");
            ReportParameter oneParamter = new ReportParameter("ParmeterName", values.ToArray());
            parameters.Add(oneParamter);
            MainReportViewer.ServerReport.SetParameters(parameters.ToArray());
            MainReportViewer.ShowParameterPrompts = false;
            MainReportViewer.ServerReport.Refresh();
        }

In the example above I do hard code parameter values, but you get the idea.  Just add your parameters to the URL for ReprotViewerForm and have the form add them to each report.

Of course you also need to create SSRS report as well, but this is a separate subject.

Crystal Reports implementation

First thing is to create a crystal report.  You do have the usual options here to have the report get data directly from database (which is what I am using) or you can write more code to get data into a DataSet for example, using additional .NET classes and pass DataSet to the report.  We have to create a web page here as well to host report viewer.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReportView.aspx.cs" Inherits="MyApp.Web.ReportView" %>

<%@ Register assembly="CrystalDecisions.Web, Version=10.5.3700.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" namespace="CrystalDecisions.Web" tagprefix="CR" %>

<!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 runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <CR:CrystalReportViewer ID="CrystalReportViewer1" runat="server"
            AutoDataBind="true" />
    </div>
    </form>
</body>
</html>

Again, you have to put some code to Load event to interpret report name and parameters as well as setup connection information

protected void Page_Load(object sender, EventArgs e)
        {
            string filter = Request.Params["param"];
            CrystalReportViewer1.Attributes.Add("Width", "100%");
            CrystalReportViewer1.Attributes.Add("Width", "100%");

            CrystalDecisions.CrystalReports.Engine.ReportDocument doc = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
            doc.Load(Server.MapPath("MyReport.rpt"));
            foreach (CrystalDecisions.CrystalReports.Engine.Table item in doc.Database.Tables)
            {
                CrystalDecisions.Shared.ConnectionInfo connection = new CrystalDecisions.Shared.ConnectionInfo();
                connection.ServerName = "(local)";
                connection.UserID = "myUser";
                connection.Password = "myPassword";
                connection.DatabaseName = "MyDatabase";
                CrystalDecisions.Shared.TableLogOnInfo logInfo = new CrystalDecisions.Shared.TableLogOnInfo();
                logInfo.ConnectionInfo = connection;
                item.ApplyLogOnInfo(logInfo);
            }

            CrystalDecisions.Shared.ParameterField param = new CrystalDecisions.Shared.ParameterField();

            CrystalDecisions.Shared.ParameterDiscreteValue discreteVal = new CrystalDecisions.Shared.ParameterDiscreteValue();

            discreteVal.Value = filter;
            param.ParameterFieldName = "@Test";
            param.CurrentValues.Add(discreteVal);
            doc.SetParameterValue(param.ParameterFieldName, param.CurrentValues);

            this.CrystalReportViewer1.ReportSource = doc;
        }

So far pretty easy.  How the Silverlight part.  In this case we do not want to have a popup, but instead have our page appear to be a part of Silverlight application.  Let’s see what web page looks like that hosts Silverlight application.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="MyApp.Web._Default" %>

<%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls"
    TagPrefix="asp" %>

<!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" style="height: 100%;">
<head id="Head1" runat="server">
    <title>Report</title>
</head>
<body style="height: 100%; margin: 0;">
    <form id="form2" runat="server" style="height: 100%;">
    <asp:ScriptManager ID="ScriptManager2" runat="server">
    </asp:ScriptManager>
    <div style="height: 100%;">
        <asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/MySilverlightApp.xap" MinimumVersion="2.0.30523"
            Width="100%" Height="80%" Windowless="true"/>
    </div>
    <iframe id="reportFrame" style="position:absolute; width:0px; height:0px; visibility:hidden"></iframe>
    </form>
</body>

</html>

As you can see, we are using frames in this case to show the report.  Now, the Silverlight code to launch a report:

private void ShowReportButton()        {
            HtmlElement m = HtmlPage.Document.GetElementById("reportFrame");
            if (m != null)
            {
                int top, left, width, height;
                top = (int)this.outerGrid.RowDefinitions[0].ActualHeight;
                left = (int)(this.outerGrid.ColumnDefinitions[0].ActualWidth + this.outerGrid.ColumnDefinitions[1].ActualWidth);
                width = (int)this.outerGrid.ActualWidth – left;
                height = (int)this.outerGrid.ActualHeight – top;
                m.SetStyleAttribute("left", left.ToString());
                m.SetStyleAttribute("top", top.ToString());
                m.SetStyleAttribute("width", width.ToString());
                m.SetStyleAttribute("height", height.ToString());
                m.SetAttribute("src", "ReportView.aspx?param=P");
                m.SetStyleAttribute("visibility", "visible");
            }
        }

In the code about outerGrid is the control that hosts main Silverlight application.  So, since our Silverlight application is located at position (0,0) in the web page (top left corner), we can compute the coordinates and size of report frame by using actual height and width of our Silverlight controls.  Once that is done, we can control the location of the frame and its size to make it appear as part of Silverlight application.  You would also need to listen to resize events of the browser in order to control the size of the report window.

This is my attempt to write a comprehensive guide to Silverlight reporting.

GGMUG Presentation on Silverlight Data Access

Today I did a presentation at the GGMUG (Gwinnett, GA Microsoft Users’ Group) meeting on Silverlight’s data access.  Download presentation and project here.

Integrating Reporting Services (SSRS) 2008 into Silverlight applications

Task of the day: create SSRS reports that can be shared between desktop (WPF) and Silverlight applications.

Silverlight does not have SSRS report viewer.  So what should we do?  The cleanest (and easiest) solution is to utilize ASP.NET capabilities.  ASP.NET does have web based controls for viewing SSRS reports.  So, we will create an aspx page in the web application that hosts Silverlight application.  We will set it up as follows:

<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">
<head runat="server">
    <title>Report</title>
</head>
<body>
    <form id="form1" runat="server" style="height:100%" >
    <div style="height:100%" >
        <rsweb:ReportViewer ID="MainReportViewer" runat="server" 
            ProcessingMode="Remote"
            Width="95%"
            Height="700"
            ShowExportControls="True"
            ShowFindControls="True"
            ShowParameterPrompts="False"
            ShowPromptAreaButton="False"
            ShowRefreshButton="False"
            BackColor="White">
            <ServerReport DisplayName="MainReport" ReportServerUrl="" />
        </rsweb:ReportViewer>
    </div>
    </form>
</body>
</html>

Now the next step is to make sure this web page can parse query parameters and show appropriate report:

protected void Page_Load(object sender, EventArgs e)
        {
            MainReportViewer.ProcessingMode = ProcessingMode.Remote;
            MainReportViewer.ServerReport.ReportPath = "/SSRSReports/" + this.Request.QueryString["ReportName"];
            MainReportViewer.ServerReport.ReportServerUrl = new Uri("http://localhost:8080/ReportServer_SQL2008");
            List<ReportParameter> parameters = new List<ReportParameter>();
            List<string> values = new List<string>();
            values.Add("1");
            values.Add("2");
            values.Add("3");
            ReportParameter oneParamter = new ReportParameter("MyParameter", values.ToArray());
            parameters.Add(oneParamter);
            MainReportViewer.ServerReport.SetParameters(parameters.ToArray());
            MainReportViewer.ShowParameterPrompts = false;
            MainReportViewer.ServerReport.Refresh();
        }

Code above contains hard-coded report parameters.  But, as you can see those can be easily passed in as part of query string as well.

Now, code from Silverlight application:

private void Button_Click(object sender, RoutedEventArgs e)
    {

        Uri sourceUri = new Uri(HtmlPage.Document.DocumentUri, Application.Current.Host.Source.ToString().Substring(0, Application.Current.Host.Source.ToString().IndexOf("ClientBin") – 1) + "/ReportViewerForm.aspx?ReportName=DevelopmentPlanAction");

        if (true == HtmlPage.IsPopupWindowAllowed)
        {
            System.Text.StringBuilder codeToRun = new System.Text.StringBuilder();
            codeToRun.Append("window.open(");
            codeToRun.Append("\"");
            codeToRun.Append(sourceUri.ToString());
            codeToRun.Append("\",");
            codeToRun.Append("\"");
            codeToRun.Append("\",");
            codeToRun.Append("\"");
            codeToRun.Append("width=1000,height=900,scrollbars=yes,menubar=no,toolbar=no,resizable=yes");
            codeToRun.Append("\");");
            try
            {
                HtmlPage.Window.Eval(codeToRun.ToString());
            }
            catch
            {
                MessageBox.Show("You must enable popups to view reports.  Safari browser is not supported.", "Error", MessageBoxButton.OK);
            }
        }
        else
            MessageBox.Show("You must enable popups to view reports.  Safari browser is not supported.", "Error", MessageBoxButton.OK);
    }

This code simply creates a javascript that is using the same web URL, but adds the address to our report viewer web page we just created.  Ideally, we should have use  built-in Silverlight function HtmlPage.PopupWindow, but it does not honor options, always creating non-resizeable browser window.  So, I am resorting to javascript instead that does create a resizeable window, but without menu, etc…  The only sad part is that Siliverlight application does launch another window, but there is no way to workaround this issue.  Overall I am pretty happy with this solution.  What is also pretty cool is that the same SSRS report can be called from WPF application.  In that case we use WinForm SSRS viewer that we host inside WindowsFormsHost  control like so:

<winForms:WindowsFormsHost x:Name="ViwerHost" Grid.Row="1" Background="White">
            <reports:ReportViewer x:Name="ReportViewerControl">
            </reports:ReportViewer>
        </winForms:WindowsFormsHost>

The code to launch the report is pretty much identical to the one for ASP.NET

Cool, hah?

Reusable WPF/Silverlight Animations

As I was working on fixing some animations that got broken due to splitting on one control into multiple controls, I came up with an idea of creating a single animation that could be apply to multiple controls.  In my case, the animation was two-fold.  As control came into view, it should fade into the view as well as "bounce".  Essentially, this animation utilizes scale transform and opacity transform.  Here is the new class I wrote.  The cool thing is that this class can be called with any UI element or control.As a matter of fact, the control does not even need to have transform group defined for it, as the class will create one on the fly to support desired animation.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media;

namespace App.Animation
{
    public static class InitialControlAnimation
    {
        public static void Play(UIElement controlToAnimate)
        {
            Storyboard story = new Storyboard();

            // opacity animation
            DoubleAnimationUsingKeyFrames opacityAnimation = new DoubleAnimationUsingKeyFrames();
            opacityAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.8, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            ((SplineDoubleKeyFrame)opacityAnimation.KeyFrames[2]).KeySpline = new KeySpline(0, 1, 1, 1);
            Storyboard.SetTarget(opacityAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(UIElement.OpacityProperty));
            story.Children.Add(opacityAnimation);

            //stretch horizontally
            DoubleAnimationUsingKeyFrames scaleXAnimation = new DoubleAnimationUsingKeyFrames();
            scaleXAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.95, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1.08, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            Storyboard.SetTarget(scaleXAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));
            story.Children.Add(scaleXAnimation);

            //stretch vertically
            DoubleAnimationUsingKeyFrames scaleYAnimation = new DoubleAnimationUsingKeyFrames();
            scaleYAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.95, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1.08, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            Storyboard.SetTarget(scaleYAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));
            story.Children.Add(scaleYAnimation);

            if (!(controlToAnimate.RenderTransform is TransformGroup))
            {
                TransformGroup group = new TransformGroup();
                group.Children.Add(new ScaleTransform(1, 1, controlToAnimate.RenderSize.Height / 2, controlToAnimate.RenderSize.Width / 2));
                controlToAnimate.RenderTransform = group;
            }
            story.Begin();

        }
    }
}

CSLA .NET for Silverlight webcast on 11/13

Magenic is sponsoring a webcast about CSLA .NET for Silverlight on November 13. I will be doing this presentation.  I am very excited about this opportunity.  I think very highly of Silverlight/WPF technologies.  I have also being using CSLA for almost 2 years now on nearly daily basis.  As you may have noticed from other posts, I got an opportunity to work with Rocky Lhotka on CSLA for Silverlight for about three months.  I am hopeful that I can share my excitement and get people interested in CSLA for Silverlight.  I honestly believe that Silverlight can revolutionize business application development for the web, and CSLA can play a very big role in this process as the very first (to my knowledge) business framework for Silverlight.

CoDe magazine article

I have been working on CSLA for Silverlight project with Rocky Lhotka, Justin Chase, Nermin Dibek, and Mark Steinberg for about three months.  I really enjoyed this challenging and interesting work.  It has been a great opportunity for me to work with the latest technologies and great, smart and super knowledgeable people.  About a month ago Rocky invited Justin and I to help write an article for CoDe magazine on CSLA for Silverlight.  As you can imagine,  both of us jumped at this opportunity.  As Justin just informed me, the article has been published!  I am super (and I mean SUPER) excited.  Read "Using CSLA .NET for Silverlight to Build Line-of-Business Applications" article online here.

Yeay, I am a published author!

Silverlight Error Code 4001 AG_E_NETWORK_ERROR

I encountered this error today, working on a custom Silverlight application.  According to Silverlight.Net this is not a bug.  However, I think it is an issue with Silverlight 2.0 RTW release.  Based on other posts the following situation causes this issue.  You have two images one next to another in your XAML that have the same image file name as source.  Image is actually displayed properly even with the error.  This is exactly what I have in my page.  Here is a workaround that I found.  I had to add the following code to the ASPX page that hosts Silverlight control.

<script type="text/javascript">
    function tellerror(msg, url, linenumber) {
        if (msg.toString().indexOf("Image") >= 0 && msg.toString().indexOf("4001") >= 0) {
            return true;
        }
        else {
            alert('Error message= ' + msg + '\nURL= ' + url + '\nLine Number= ' + linenumber)
            return true;
        }
    }

    window.onerror = tellerror;
</script>