# Friday, 13 February 2009

In the wake of our Silverlight presentations this week, Shaun (CTO of SoftSource, and my boss) is going to be blogging on his demos, starting with Silverlight/JavaScript interactivity.  His demos were pretty cool, so I’m looking forward to reading his commentary.  I might just follow suit with a few examples too…

Friday, 13 February 2009 12:16:28 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 

Check out http://events.sftsrc.com/ for more new classes…

  • LINQ
    • 2 days of LINQ to Objects, LINQ to XML, LINQ to SQL, LINQ to Entities and more
  • ASP.NET
    • 5 days of ASP.NET including some AJAX and a hint of Silverlight
  • WPF
    • 3 days of WPF goodness
  • Silverlight
    • 2 days for those with WPF experience or
    • 3 days for web developers
  • C#  and the .NET Framework
    • 5 days of C# 3.0 and the 3.5 framework, including LINQ, extension methods and the rest of the new language features
Friday, 13 February 2009 10:17:36 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, 06 February 2009

Google is great at providing 20/20 hindsight. 

The little problem I was having with insert triggers is (unsurprisingly) not uncommon.  I googled a bit after a suggestion in a comment (thanks El Guapo) and found a great explanation by Mike Taulty on how to deal with just such a concurrency problem.  He’s specifically dealing with a timestamp column, but the issue is essentially the same. 

Good to know…

Friday, 06 February 2009 09:39:15 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, 05 February 2009

I’ll be there, soaking up the Silverlight-y goodness. 

Thursday, 05 February 2009 14:56:38 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 

Lets say I have a nice simple database (guess which one…)

CropperCapture[5]

Now I want to insert a new Order into the Orders table

 

using (NorthwindDataContext context = new NorthwindDataContext())

{

    Order order = new Order();

    context.Orders.InsertOnSubmit(order);

    context.SubmitChanges();

}

No problem.  Totally works like you’d think.  What happens if I make more changes after that and call SubmitChanges() again?

using (NorthwindDataContext context = new NorthwindDataContext())

{

    Order order = new Order();

    context.Orders.InsertOnSubmit(order);

    context.SubmitChanges();

 

    order.Freight = 98.77M;

    order.ShipName = "Fred Jones";

 

    context.SubmitChanges();

}

Still cool.  The problem comes in if I add an insert trigger.  Let’s say I add a trigger to set the OrderDate column of the order to make sure it’s always the right date…

ALTER TRIGGER Trigger1

ON dbo.Orders

FOR INSERT

AS

UPDATE Orders

SET OrderDate = GETDATE()

FROM Orders INNER JOIN inserted ON Orders.OrderID = inserted.OrderID

Whether or not that’s a good idea is a whole ‘nother topic.  Seemed like the thing to do at the time…  However, now there’s a problem.  The first SubmitChanges() works fine, but the second one fails with an update conflict.  WTF?  After I stopped to think about it (and talked to Stuart) I realized that that makes perfect sense.  The copy of Order that I have in memory doesn’t know anything about the result of the insert trigger, and so the record is out of date, hence the conflict.  In this particular case it wasn’t a problem because it wasn’t too much work to just take out the trigger and set the date in the code.  I had been hoping that I wouldn’t have to redeploy the web app, hence the trigger.  Best laid plans…

Anyway, it turns out that something similar came up on another project, so it is something to be aware of.

Thursday, 05 February 2009 14:49:23 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [2]  | 

After reading Scott’s latest missive, I finally gave in and joined the Tweeple.

@pcauldwell

Thursday, 05 February 2009 13:04:23 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, 22 January 2009
Yesterday I posted a bit about a dynamic survey in Silverlight, and today I wanted to start delving into a few details.  First of all, databinding to a user control…

I wanted my datagrid to show a series of radio buttons representing a “rating” from 1-5, where that rating corresponds to an enum value in C# and an integer in SQL. 

CropperCapture[4]

For databinding to work the way I’d want, I need to bind the one value in the source to the set of radio buttons in the target.  The easiest way I could think of (and there may be a better way I haven’t thought of) was to make the radio buttons into a user control, and expose a single value.  In the XAML for the datagrid, it looks like

<data:DataGridTemplateColumn.CellTemplate>

    <DataTemplate>

        <t:Rating UserRating="{Binding Path=Answer, Mode=TwoWay}" />

    </DataTemplate>

</data:DataGridTemplateColumn.CellTemplate>

The CellTemplate contains just the user control, and binds its UserRating property to the Answer property in the source.

The XAML for the UserControl is simple

<UserControl x:Class="Evaluation.Rating"

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

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

    <StackPanel Orientation="Horizontal">

        <RadioButton Content="Excellent (5)" x:Name="excellent" Checked="excellent_Checked"/>

        <RadioButton Content="Good" x:Name="good" Checked="good_Checked"/>

        <RadioButton Content="Neutral" x:Name="neutral" Checked="neutral_Checked"/>

        <RadioButton Content="Adequate" x:Name="adequate" Checked="adequate_Checked"/>

        <RadioButton Content="Poor (1)" x:Name="poor" Checked="poor_Checked"/>

    </StackPanel>

</UserControl>

In order to get two-way databinding notifications to work properly both ways, the UserRating property of the control is implemented as a DependencyProperty…

public ScaledAnswer UserRating

{

    get { return (ScaledAnswer)GetValue(UserRatingProperty); }

    set { SetValue(UserRatingProperty, value); }

}

 

// Using a DependencyProperty as the backing store for UserRating.  This enables animation, styling, binding, etc...

public static readonly DependencyProperty UserRatingProperty =

    DependencyProperty.Register("UserRating", typeof(ScaledAnswer), typeof(Rating), new PropertyMetadata(new PropertyChangedCallback(RatingChangedCallback)));

Note the callback registered for the PropertyChanged event of the dependency property.  If databinding changes the value of the dependency property, we still need to update the UI to check the right radio button.

private static void RatingChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

    Rating r = d as Rating;

    r.updateUi((ScaledAnswer)e.NewValue);

 

}

 

private void updateUi(ScaledAnswer rating)

{

    switch (rating)

    {

        case ScaledAnswer.Excellent:

            excellent.IsChecked = true;

            break;

        case ScaledAnswer.Good:

            good.IsChecked = true;

            break;

        case ScaledAnswer.Neutral:

            neutral.IsChecked = true;

            break;

        case ScaledAnswer.Adequate:

            adequate.IsChecked = true;

            break;

        case ScaledAnswer.Poor:

            poor.IsChecked = true;

            break;

    }

}

Finally, the user control handles all the radio button “Checked” events and sets the value of the DependencyProperty to the correct value.

The UserControl provided a fairly smooth way of handling the databinding without having to implement a custom control, and could be reused in other contexts.  There’s probably a way to make it a bit more dynamic to handle more radio buttons, etc. but this worked for my particular case.

Thursday, 22 January 2009 12:54:28 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, 21 January 2009

I needed to build a survey (a course evaluation in this case, but name-your-survey…) and I wanted to be able to add new questions and question categories to the database without having to touch my (Silverlight) survey app.  I wanted the basic layout to look like this…

CropperCapture[2]

It took a little experimentation, and I’m sure there are other ways to make this work, but here’s what worked for me:

The questions and categories live in the database, like so

CropperCapture[3]

Categories contain questions, questions have text, and what we store when the survey is complete are the answers to the questions.

In the XAML, first there is an ItemsControl to deal with the categories, so that each category will have it’s own DataGrid.  The ItemsControl has a DataTemplate that defines what each category name and data grid of questions will look like (some formatting details removed for clarity)

<ItemsControl x:Name="dgPanel" >

    <ItemsControl.ItemTemplate>

        <DataTemplate>

            <StackPanel Orientation="Vertical">

                <TextBlock Text="{Binding CategoryName}"/>

                <data:DataGrid x:Name="dgOverall" ItemsSource="{Binding Questions}">

                <data:DataGrid.Columns>

                    <data:DataGridTextColumn Header="Question"

                   Binding="{Binding Text}" IsReadOnly="True"/>

                    <data:DataGridTemplateColumn Header="Rating">

                        <data:DataGridTemplateColumn.CellTemplate>

                            <DataTemplate>

                                <t:Rating UserRating="{Binding Path=Answer, Mode=TwoWay}" />

                            </DataTemplate>

                        </data:DataGridTemplateColumn.CellTemplate>

                        <data:DataGridTemplateColumn.CellEditingTemplate>

                            <DataTemplate>

                                <t:Rating UserRating="{Binding Path=Answer, Mode=TwoWay}"/>

                            </DataTemplate>

                        </data:DataGridTemplateColumn.CellEditingTemplate>

                    </data:DataGridTemplateColumn>

                </data:DataGrid.Columns>

 

            </data:DataGrid>

            </StackPanel>

        </DataTemplate>

    </ItemsControl.ItemTemplate>

</ItemsControl>

The questions come from a WCF call, and get bound in the form load

void client_GetQuestionsCompleted(object sender, GetQuestionsCompletedEventArgs e)

{

    dgPanel.ItemsSource = e.Result;

}

Each row that comes back has the category header text and a collection of questions, so that for each item in the ItemsControl, the text is bound to the header, and the questions are bound to the datagrid.  The DataGridTemplateColumn stuff above maps the Answer property of each question to a UserControl called Rating that contains the radio buttons.  Depending on which radio button gets checked, the value of the user control represents an enum value with their answer.  Because the data binding is defined as TwoWay, the user’s answers are updating in the in-memory copy of the questions, and when the user eventually hits the “Submit” button, the collection of questions (and answers) is sent back to the web service. 

Now I can add new questions to the database and have those questions show up in the survey, and previously submitted evaluations will only have answers for the questions that were present at the time the survey was submitted.  There’s still some work to do here, like setting up groups of questions so that different sets of questions could be used for different circumstances, etc, but this is a decent start.

Wednesday, 21 January 2009 10:23:06 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, 15 January 2009

Shaun (my boss) and I are going to be doing a one-day, technically intensive Silverlight event in both Portland (2/12) and Seattle(2/10) next month.  This will be a full day (plus lunch) of in depth, 300-400 level Silverlight content.  Check out our registration site for full session abstracts and time/place details.

From the event copy…

Look past the glitzy, media rich Silverlight demos, to the reality of writing browser-hosted, business-oriented applications. Learn how to leverage your .NET expertise and see how Silverlight can provide your organization with a powerful platform for building web-delivered solutions.

Thursday, 15 January 2009 14:30:33 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, 05 January 2009

We’ll be teaching several classes on the West side in the next few months, including C#/.NET and Practical .NET Debugging.

The C#/.NET class covers the new features in VS 2008/C# 3.0, including LINQ, automatic properties, the new initializer syntax and the var type, as well as the rest of C# and a solid foundation in .NET 3.5 including XML processing, threading, App Domains, etc. 

The Practical .NET Debugging class covers real-world debugging techniques for .NET including the VS 2008 debugger and using WinDbg on .NET code from a practical perspective.

For scheduling details or to register, see our training site.

Monday, 05 January 2009 16:18:30 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  |