Ian 的个人资料Silverlight for Business照片日志列表更多 工具 帮助

日志


5月16日

Silverlight for Business is moving

Because of the ongoing limitations of hosting this blog on spaces, I am moving over to WordPress.
 
There is nothing for you to do for browsing this site, all existing links will still work, and once the DNS changes have propagated you will be taken to the new blog automatically when you visit http://silverlightforbusiness.net
 
However you will need to update your links for your favourite reader to http://silverlightforbusiness.net/feed
 
Cheers
 
Ian
4月7日

Silverlight for Mobile – further thoughts

iStock_000006159184XSmallBart Czernicki had good post recently titled Silverlight 3 - Where is Silverlight Mobile?

I thought a lot of the comments he made were spot on.  We have been lead up the garden path by the mobile team and in particular Amrit Chopra who has been announcing Silverlight for Mobile for 3 years now.  In fact I was expecting that he would announce it again at Mix year and then deliver nothing again!  Turns out he took a back seat in the 6.5 overview instead and no significant news on Silverlight Mobile was forthcoming.

In my opinion though, Microsoft are playing with smoke and mirrors because they want to make a big as splash as possible when Windows Mobile 7 arrives.  I think they are concerned that whatever they have up their sleeve for mobile will be leaked (in fact I have heard two evangelists say as much), but I think we can take a good guess at what will be in Windows Mobile 7 (or could it even by 6.5 - wishful thinking perhaps, but I thought the comments about silverlight “missing the window” for 6.5 at 54mins in this presentation sounded vague at best, and there was the tweet on the right (since deleted) from the windowsmobile team)

So what will be in the next version of Windows Mobile?

Note: By saying “next version” I am adopting the same language that Microsoft seem to be using – could be 7, could be 6.5, could be 7 in 6.5 timeframe…but I am referring to the next significant release.

My guesses:

  • Silverlight (obviously) - but will it be browser only or the whole environment in a wpf kind of way?  My bet it will be the whole environment with xaml everywhere.  This is why they hint about it not being Flash Lite and why at the end of the Mix 09 presentation when the question was asked (55:45mins) “Silverlight will bring xaml to Windows Mobile, would that make xaml a first class citizen for use on Windows Mobile” was met with an emphatic “We agree” from Loke Uui Tan
  • IE8 - Loke Uei Tan said in the mix presentation no plans for 6.5 but definitely for the next release
  • Cloud Services integration – We have the My Phone service now, and a client for Live Mesh but I predict that we will have much more in this space.  This video gives a sneak peak of some of that vision, and this page takes about how “Through the combination of Windows, Windows Live and Windows Mobile, Microsoft is delivering the platforms, tools, infrastructure and solutions to enable new kinds of applications and services that extend from the server, to the datacenter, to the cloud – and from the browser, to the PC, to the phone and beyond.”image
  • Multi-touch – as Bart mentions – the multi-touch support in Silverlight 3 could be primarily for Windows Mobile
  • Accelerometer functionality with gestures for the interface 
  • Zune integration – this story goes back and forth – my bet is that Zune type functionality will be built in and this will also be the first time that is officially available outside the US.
  • Marketplace: Games & Xbox 360 integration of some sort – again this would seem like a natural fit – I have heard nothing about this, apart from comments about marketplace, and we do of course have Windows Mobile Marketplace announced for Windows Mobile 6.5 (and a recent announcement on free updated listings for developers

Add all that up and it is looking pretty exciting from a user and a developer story.  Let’s hope it is sooner rather than later.

Cheers

Ian

Technorati Tags: ,

3月27日

Silverlight Pulse Grok Presentation

Unfortunately the Silverlight UK User Group meeting was cancelled last night, because Mark Mann injured his ankle – I understand he is recuperating though (http://twitter.com/mark_mann) – hope it gets better soon Mark :-)

I was due to do a Grok on SilverlightPulse.net and my presentation is below.  Mark has also asked me  to do a more in-depth talk on this and it’s current migration to Silverlight 3 beta in a forthcoming meeting, which I am looking forward to.  Stay tuned (as they say)

Silverlight pulse grok 
View more presentations from IanBlackburn.

Cheers

Ian

3月17日

Updated Silverlight Pulse now on http://silverlightpulse.net

I have updated the app I created for keeping track of Silverlight tweets and now hosted it on http://silverlightpulse.net (DNS changes have just been made so may to a few hours to propagate to you).  So far I have had an overwhelming positive response, so thanks everyone who has taken a look.

Changes include:

  • Much better logic in summarising the data in the chart
  • Some animation (woot! – of course any designers who would like to add their love, please get in touch ;-)
  • Manual Refresh and countdown to next auto refresh
  • Gets all tweets in the past 8 hours (previous version just got the last 99 tweets)

I have plenty of other ideas for this app, so stay tuned, but even in it’s current form I think it will be interesting to see how the Twitter world lights up (or not) for the SL announcements at Mix 09 this week.

Cheers

Ian

Technorati Tags: ,,

Silverlight Pulse – a twitter silverlight app

Just a quick note to point you towards a little app I have been playing with to keep track of Silverlight news on Twitter.  Thought it might be interesting to keep an eye on this week with all the Silverlight announcements.

This is a very early attempt at some ideas I have for a richer Silverlight Twitter app – I will blog about it more later, but for now, you can have a play below or by opening this link:

 

Cheers

Ian

Technorati Tags: ,

3月9日

Brad Adams talks about “Silverlight 3 for Great Business Apps”

Robert Hess has a interesting chat with Brad Adams about silverlight 3 – this is a sneak peak of Brad’s session for Mix09, without, as he calls “the super secret stuff”.

Highlights:

    • We already have a couple of different App.Xaml’s you can drag in and replace to get a new design: ~5:30
    • A new browser navigation system, you can control the browser back and forward buttons & the url can expose a deep link to one page within your app. ~6:00
    • Exception handling: better handling, easier customisation out of the box ~8:00
    • New set of controls for SL3 (“there are a ton of controls”).  Grouping and paging added to DataGrid, works with sorting.  Details view added~10:20
    • Built in validation in a data form.  This is really good, wait for some great info on this in Mix09 ~12:00
      • “You can still produce a rich experience with little time to work on a project”
      • Showing validation errors
      • “Just the form itself is beautiful looking” – Robert Hess
      • “Raise the standard for what it is to build a great data entry app” – Brad Adams

image

Technorati Tags: ,,

Cheers

Ian

3月2日

Silverlight M-V-VM Resources

The Model-View-ViewModel pattern has been gaining a lot of popularity for WPF, and there have been a growing number of posts and resources about adapting it for Silverlight.

This is a short summary post of some of those resources.  I will follow this up later with a detailed post on M-V-VM where I will also explore the business case for adopting such a design (design patterns are great but I am wary about adopting them for the sake of it like this)

If you want to pick one to get started with I’d recommend the Tim Heuer’s screencast:

image

Cheers

 

Ian

Technorati Tags: ,
2月24日

Windows Live Spaces: Top 5 Wish List

Windows Live wave 3 brought great improvements to live.com, and was part of my motivation for hosting this blog on Spaces (which has only been updated slightly).  But I am starting to regret it.  Here’s my top 5 reasons why:

  1. I set up a domain for the blog (http://silverlightforbusiness.net) but this just gets redirected to the standard spaces url (in my case: http://blackburnian.spaces.live.com/) – this is a problem because I lose a bit of identity for the blog, and because spaces.live.com is blocked in many corporate networks as a social networking site.  I have seen this is the last two clients I visited.  My blog can be made as an exception in their proxy servers, but it obviously limits visibility to many corporate clients.  Why can’t the domain just stay as the one I have chosen, in the way that Wordpress and Tumblr do (for example my http://backofabeermat.co.uk site is hosted on tumblr but that domain never changes, and ironically is often visible in corporate networks)
  2. The statistics provided by spaces are terrible.  A paged table with columns that aren’t wide enough, only next and previous buttons (no jumping to a particular page), poor amount of data, no export, poor amount of summary data.  Really this is pretty lame; looks like something someone produced at the last minute.  Can we have something on the lines of the stats provided by SubText or at least an answer to the next point.
  3. Limited customisation.  OK I can do plenty with colours and layout, which is all ok, but I can’t embed any scripts – so using an analytics script to mitigate point 2 appears out of the question. Even using Microsoft’s own scripts from adcenter are not allowed.
  4. Limited blog.  Again I can’t embed things I want to embed.  You can include pictures and videos  It would be nice to include Silverlight in a blog called Silverlight for business, but this is not possible currently AFAIK Just found out that you can do this using an IFrame from Silverlight streaming at least – yes!
  5. No Search – my users can’t search my blog.  Can we have a search please?
  6. Categories – why can I only have one category per entry? (ok that’s 6 but I just remembered this one and it really bugs me, and 4 has been somewhat mitigated…

I am hoping that there is an update for Spaces on the way – but I haven’t heard anything about that.  At the moment there is a possibility that the current setup is going to harm potential business by reducing it’s visibility, and that is obviously not acceptable.  So if anyone has any pointers or hints on solutions to the above, I would love to hear them!

Cheers

Ian 

Technorati Tags: ,

Windows Live Tags: clubhouse, Story, Spaces

Silverlight Visualisation Example – how much energy is wasted in US households?

This example was produced rather quickly in response to a challenge by Tim Heuer and shows the energy consumption of US households over the last few years and then predicted to 2030.  I was inspired by an article in National Geographic that I was reading, and it highlights I hope, the rather dramatic amount of energy is wasted through “electrical loss” (though I was a little disappointed from the visualisation point of view, how little the data changed in the prediction, made for a less dramatic animation!).  This is US data, but I would expect the UK would be very similar.

You can view it here

The code is very simple really, and illustrates how easy it is to do this sort of thing in Silverlight.  It could easily be improved with some nicer animation and design though.

The following are illustrated in the code:

  • Simple custom control: EnergyConsumptionBubble – this is an ellipse and some text and in a grid cell, with some exposed dependency properties, and could benefit from some funky designer skills (which I seem to have misplaced ;-)
 
    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:controls="clr-namespace:EnergyConsumptionControls"
        >
        <Style TargetType="controls:EnergyConsumptionBubble">
            <Setter Property="Template" >
                <Setter.Value>
                    <ControlTemplate TargetType="controls:EnergyConsumptionBubble">
                        <Grid Margin="10 0"  >
                            <Ellipse Fill="{TemplateBinding Fill}" 
                                     Width="{TemplateBinding EnergyValue}" 
                                     StrokeThickness="{TemplateBinding StrokeThickness}" 
                                     Stroke="{TemplateBinding Stroke}"  
                                     Height="{TemplateBinding EnergyValue}" />
                            <StackPanel VerticalAlignment="Center" 
                                        HorizontalAlignment="Center">
                            <TextBlock TextAlignment="Center" 
                                       FontWeight="Bold" 
                                       Foreground="{TemplateBinding TextForeground}" 
                                       TextWrapping="NoWrap" 
                                       Text="{TemplateBinding EnergyText}" ></TextBlock>
                                <Image Source="{TemplateBinding ImageSource}" 
                                       Stretch="UniformToFill"/>
                            </StackPanel>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
     
    it is used in the page like this:
     
    <controls:EnergyConsumptionBubble 
        Stroke="Red" 
        TextForeground="Black"  
        StrokeThickness="10" 
        Fill="Red" 
        EnergyValue="{Binding Converter={StaticResource EnergyValueConverter}, Path=Electricity}" 
        EnergyText="Electricity"  
        Canvas.Top="0" 
        Canvas.Left="-21"/>
    
     
  • Use of Linq to Xml: the data is only available via an Excel spreadsheet, so I converted that to Xml that I hosted in the web site and used the WebClient to retrieve it and then processed it using Linq to Xml.  This is actually the bulk of the code!
WebClient client = new WebClient();
client.OpenReadAsync(new Uri("EnergyConsumption.xml", UriKind.Relative));
client.OpenReadCompleted += (o, args) =>
{

    XElement xelement = XElement.Load(args.Result);
    var results = from c in xelement.Elements("EnergyConsumption")
                  select new EnergyConsumption()
                  {
                      Electricity = double.Parse(c.Element("Electricity").Value),
                      ElectricityRelatedLosses = double.Parse(c.Element("Electricity_Related_Losses").Value),
                      LiquidFuels = double.Parse(c.Element("Liquid_Fuels").Value),
                      NaturalGas = double.Parse(c.Element("Natural_Gas").Value),
                      RenewableEnergy = double.Parse(c.Element("Renewable_Energy").Value),
                      Year = int.Parse(c.Element("Year").Value)
                  };
    DataGrid1.ItemsSource = results;
    foreach (EnergyConsumption item in results)
    {
        records.Add(item);
    }
    this.DataContext = records.First();
    YearSlider.SmallChange = 1;
    YearSlider.LargeChange = 5;
    dataLoaded = true;
};

 

  • Use of a slider to change the datacontext of the page.  As the slider is moved either manually or by playing the animation, the datacontext for the page is changed to the currently selected year:
private void YearSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    if (dataLoaded)
    {
        this.DataContext = records.Where(c => c.Year == Math.Round(YearSlider.Value)).First();
    }
    
}

  • A simple value converter that just magnifies the raw data a bit (in retrospect this should have been done in the EneryConsumptionBubble rather than as a converter).

That’s pretty much it – full source is available on my sky drive – feel free to download it and have a play.

Cheers

 

Ian

Windows Live Tags: Silverlight, Visualisation, Energy

2月7日

Implementing Validation Logic in Silverlight 2

In Silverlight 3 we have seen that the Alexandria Framework will have a rich validation and business logic framework that is really very powerful and productive.  Silverlight 3 is due to be announced at Mix 09, and I would expect a CTP or Beta to be available then.

But what can you do now?  Even if we get a go-live license on a SL 3 Beta it will be too early for many corporate teams to adopt.  This post will look at using Silverlight 2 and:

  • Replicating validation logic from an Entity Model on the Server exposed via an Ado.Net Data Service
  • Handling validation in the UI

Replicating validation logic from an Entity Model on the Server exposed via an Ado.Net Data Service

If you have not created Entity Models and Ado.Net Data Services you may want to refer to my earlier post here.

Alexandria (a.k.a. SL3) provides an automatic way of doing this which is not available in SL2, however we can provide a reasonably simple manual process to achieve a similar result.  The key is that the service reference you create will generate a client proxy partial class, with partial methods available in Silverlight that mimic the ones available in the model on the server.

So if on the server I create the following extremely simple Entity Model

image

I can add some validation logic by creating the following partial class on the server on then implementing the partial methods I want (in this case the OnUnitPriceChanging)

public partial class Products
{
    partial void OnUnitPriceChanging(decimal? value)
    {
        if (value < 0)
        {
            throw new ArgumentOutOfRangeException("UnitPrice","Must be positive");
        }
    }
}

I now add an Ado.Net Data Service as follows to “surface” that data:

public class NorthwindDataService : DataService< NorthwindEntities >
{
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(IDataServiceConfiguration config)
    {
        // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
        // Examples:
         config.SetEntitySetAccessRule("*", EntitySetRights.All);
         config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
    }

 

and add a Service reference to it from the Silverlight project.

image

This will cause Visual Studio to generate two proxy classes for use with the service.  If you want to see these you will need to turn on “Show All Files” in the project and then expand the Service Reference folder until you see Reference.cs

image

Interestingly this also builds an entity data model (service.edmx) that cannot be viewed using the Entity Data Model Designer, though you could open it up in the xml editor.  However we are not interested in that for this scenario.  Rather we want to have a look at those generated proxy classes.  From the class diagram below we can see that the Products entity has been replicated to the Silverlight project but the partial OnUnitPriceChanging method has not been implemented (i.e. our implementation has not been carried over from the server)

image

image

However since this is a partial class it is easy for us to create own own partial Products class in the Silverlight project and then implement this method.  In this case we can copy and paste the code directly from our server version of this class.  Ideally of course, this would be generated for us automatically, and this is in fact what Alexandria in Silverlight 3 does, but in Silverlight 2 it is a manual process.  Note that you will need to make sure your namespace is correct and matches the one used by the service reference generated class.

namespace SilverlightValidation.DataServiceReference1
{
    public partial class Products
    {
        partial void OnUnitPriceChanging(decimal? value)
        {
            if (value < 0)
            {
                throw new ArgumentOutOfRangeException("UnitPrice","Must be positive");
            }
        }

    }
}

Ok so we now have data validation logic replicated on the client.  How can we use it?

Handling Validation Logic in the UI

I am going to build a very simple UI that shows how we can handle our validation logic.  It has a button that retrieves a single product given a product ID and then displays the productname and unit price.  Editing the UnitPrice should raise our validation check, and if it fails we want to indicate that in the UI by making something go red and displaying a message somewhere.

Here is the Xaml:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <TextBox x:Name="TextBox1" Text="1" Margin="5" />
        <Button Content="Get Product" Margin="5" Click="Button_Click"/>
        <TextBlock Foreground="Red" x:Name="TextBlockError"/>
    </StackPanel>
    <StackPanel Grid.Row="1" >
        <TextBlock Text="{Binding ProductName}"/>
        <TextBox BindingValidationError="TextBox_BindingValidationError" >
            <TextBox.Text>
                <Binding Mode="TwoWay"
                         Path="UnitPrice"
                         ValidatesOnExceptions="True"
                         NotifyOnValidationError="True"
                         />
            </TextBox.Text>
        </TextBox>
    </StackPanel>
</Grid>

 

And here is the code behind:

public partial class Page : UserControl
{
    DataServiceReference1.NorthwindEntities entities = 
            new SilverlightValidation.DataServiceReference1.NorthwindEntities(
                new Uri("NorthwindDataService.svc", UriKind.Relative)); public Page() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { int productId = 0; int.TryParse(TextBox1.Text, out productId); DataServiceQuery<Products> query = (DataServiceQuery<Products>) from c in entities.Products where c.ProductID==productId select c; query.BeginExecute(new AsyncCallback(c => { var results = query.EndExecute(c); this.DataContext = results.First(); }), query); } private void TextBox_BindingValidationError(object sender, ValidationErrorEventArgs e) { if (e.Action == ValidationErrorEventAction.Added) { ((TextBox)sender).Background = new SolidColorBrush(Colors.Red); TextBlockError.Text = e.Error.Exception.Message; } else { ((TextBox)sender).Background = new SolidColorBrush(Colors.White); TextBlockError.Text = string.Empty; } } }

 

Let’s have a look at this bit by bit.  First the Button_Click code: this builds a DataServiceQuery and then executes it, setting the DataContext of our page to the first result (there should only ever be one since we are querying by primary key).  There is no exception handling in here though, so an invalid product Id will just throw an exception; feel free to add your own.  Setting the DataContext on the page to the resulting Product entity will cause the data to be shown in our little data form as follows:

image

In the Xaml I have set the following binding properties on the TextBox:

<Binding Mode="TwoWay" Path="UnitPrice" ValidatesOnExceptions="True" NotifyOnValidationError="True" />

  • Mode="TwoWay" ensures that as we edit the bound data it is sent back to the underling data object – in our case the local Product Entity in Silverlight
  • Path="UnitPrice" is the field we want to bind to from the DataContext
  • ValidatesOnExceptions="True" means that exceptions raised in setters (or ValueConverters) for the bound object (in our case the Product entity)  will create a validation error
  • NotifyOnValidationError="True" means that if a validation error is created (because we have ValidatesOnExceptions="True") then the binding engine will raise a BindingValidationError.

so having both the last two settings set to True means that any validation errors set in our Products entity can be handled in a single BindingValidationEvent.  In this case I have handled this event on the textbox itself but you may handle it further up the tree (e.g. a stack panel or the page) in a more complicated data form.

<TextBox BindingValidationError="TextBox_BindingValidationError" >

This event handler is then simply changing the background colour of the textbox to red and displaying the error message.

To test this you will need to:

  • Start without debugging  (otherwise Visual Studio will break on the exception in our OnUnitPriceChanging method – if that happens you can just continue with F5 to see the validation exception being handled instead)
  • Enter a negative number for the Unit price and then tab out of the textbox control to raise the event

image

Happily we also get data type validation for free using this model.  So entering some text into this field (which should of course be a number) also raises the validation error:

image

Moving Forward

This validation model works but we have to do more work than we would have to in WPF (see here and here).  We can also reasonably expect Alexandria (SL3) to provide a richer model for validation – watch out from the sessions at Mix 09 for more details on that.

cheers

Ian

2月5日

Silverlight Accessibility and creating DDA Compliant applications in the UK

In the UK the DDA (The Disability Discrimination Act, 1995) makes it a legal requirement for service providers to ensure access for disabled customers and if necessary make reasonable adjustments to the way they deliver their services; this includes web sites (see Part III, 2.2, 4.7, 2.13-2.17, 5.23 and 5.26). 

This almost certainly isn’t news to most of you, but I think there is a large degree of confusion about what creating a DDA Compliant site actually means, if not among the legal profession, it certainly appears to be among the development teams I generally come across.

It seems that in order to be able to claim that a website is DDA compliant, it must be tested against the three checkpoint levels laid down in the WAI guidelines issued by the World-Wide-Web Consortium (W3C). These are of course the commonly quoted A, AA and AAA (levels 1, 2 and 3).  Level AA is recommended and level A is the minimum acceptable standard for accessibility.

However I believe that most developers look at the A, AA, and AAA levels against WCAG (Web Content Accessibility Guidelines) version 1, which were published in 1999 and required sites that contain no CSS or Script.

Importantly, it seems that DDA compliance could be based on either WCAG Version 1 or Version 2

Version 2 was published on 11 December 2008 and “applies to more advanced technologies, and is more precisely testable” than the previous version. For example, scripting is not forbidden and is even included as techniques to enhance accessibility. And where WCAG 1.0 essentially did not allow flashing or other movement, WCAG 2.0 allows it within defined parameters that won't cause seizures.

So WCAG version 2 opens up the ability to build compliant applications using Silverlight 2, and I have it on good authority that “you can build a WCAG 2.0 acceptable experience using Silverlight”.

So that means:

You can build DDA compliant application in Silverlight 2 by following the WCAG version 2

I will post further on what you will need to do in terms of your Silverlight app to achieve this, but for me at least this is a significant realisation, and I know of at least one client where not being able to do this would have been a show-stopper for Silverlight adoption in their new product.

Perhaps too, with the more realistic WCAG v2 now published, we can start developing web applications in general that are useful, accessible, and legal without resorting to producing a “fall-back WCAG v1 compliant version” and that the majority of web sites that are currently in breach of the law, and have been for over 6 years, can come into line.

Cheers

 

Ian

1月2日

Microsoft.com gets Silverlight on it’s home page

We are starting to see Microsoft push Silverlight out on more of it’s assets.  Microsoft.com home page (one of the most visited in the world) now shows the following to users without Silverlight installed

image

And the following once it is installed; an accordion type control highlighting current content on the site (By the way Microsoft, SkyDrive now offers 25GB of storage for free, not 5GB as stated on this page, at least my account does. CORRECTION – the site has just been updated as I wrote this to show 25GB of free space!)

image

Interestingly they have also added a more prominent Live Search at the top of the page.  Live Search is still struggling to get traction so perhaps this will help, though it does not go as far as some have suggested.

This is good for developers using or considering Silverlight in their solutions because it will drive usage up, and because Microsoft are actively pushing it rather than taking the “no-installation-experience” option I highlighted in my previous post that is shown on some other Microsoft sites.

It would be nice to summarise all the Microsoft sites that are using Silverlight, but I haven’t found an easy way to do this – if anyone has any ideas on how to get or find that information please let me know.

Cheers

Ian

Technorati Tags: ,

12月25日

Computer Weekly: Silverlight Skills are Hot!

Nick Langley at Computer weekly just published an article titled: Hot Skills: Silverlight.

It’s nice to see that there is a growing understanding of the importance of Silverlight for business’s working in the RIA space and that rates of pay are reflecting that. Nick is quoting the following rates of pay:

C# and ASP.Net web developers with Silverlight: £28-40k

If you want to get up to speed on Silverlight then silverlight.net is a great place to start, but bbits also offer customised Silverlight training and seminars for designers and developers.  Also look out for our new online based training in the new year…

Ian

Technorati Tags: ,,

12月18日

itv.com helps push Silverlight – but is the installation experience good enough and why aren’t more Microsoft sites using Silverlight?

itv.com pushes Silverlight installation in the UK

Sometime ago I was pleased to see that itv.com were using Silverlight to live stream their 4 TV channels.  However it was a disappointment that the Silverlight player was only shown if the user already had Silverlight installed – if they hadn’t pre-installed it then itv would “fall back” to their standard Flash player.  This could be termed a “no-installation-experience” perhaps.

image

However it is nice to see that they are now actively pushing Silverlight as their “upgraded” video player.  On the home page they now display this link:

image

which leads to this page (http://www.itv.com/silverlight2/):

image

This is a much more aggressive “installation experience” and I think significant in the UK, because of the strength of the ITV brand and the fact that they are pushing Silverlight right on their home page.

Interestingly itv.com have chosen to link to http://www.microsoft.com/silverlight/resources/install.aspx for the actual installation rather than provide a link directly to the Silverlight.2.0.exe (which is what the standard installation experience is when you create a project in Visual Studio for example – see my post here for details on customising that).  I’m not sure that is the best choice since it takes the user to another site, but does provide a measure of comfort in that that user can be reassured the installation is from Microsoft, which takes me to the second point of this post.

Is the installation experience of Silverlight good enough?

No matter how you wrap it up with context and assistance for the user, users will eventually will see this:

image

I have had comments from friends when trying Silverlight for the first time that this looked like a virus and they refused to install it. 

It is slightly strange to me that Microsoft have chosen to provide a link directly to the exe and not use the browser info bar, in the way that Adobe do with Flash, and Microsoft do with many other ActiveX controls.  This I think passes the “mum test” much more easily, and is a more reassuring experience, more clearly showing what you are installing and from who, rather than the slightly cryptic: silverlight.dlservice.microsoft.com url that the above dialog presents.  How long before some dodgy web site provides a silverlight installation that points to a fake Silverlight.2.0.exe that is a virus?

Active X screen shot

Current Silverlight Penetration

Do we have any figures on current installation levels for Silverlight?  Scott Guthrie said in October:

"We launched Silverlight just over a year ago, and already one in four consumers worldwide has access to a computer with Silverlight already installed,"

source: cnet: http://news.cnet.com/8300-10805_3-75.html?keyword=%22Silverlight%22 

That’s a strange way to state a figure: my dad has “access to my computer” which has Silverlight installed, but it doesn’t mean he is using it on his own, still it is a positive statement overall, and seeing an increasing number sites like itv.com using Silverlight is only going to help.

An interesting site showing stats on various ria technologies is here: http://riastats.com/. The statistics shown on this site are collected through a small javascript included on various websites so it cannot be deemed definitive but it is an interesting comparison.  It currently shows Silverlight staying at around 12% since release of version 2 – that obviously needs to improve and having Silverlight on high profile sites is the way that will happen.

image

Silverlight on Microsoft Sites

Perhaps surprisingly we have not seen a huge take up of Silverlight on Microsoft sites, but as Steve Ballmer stated at Mix08 this is only a matter of time, and we are certainly starting to see more.  For example http://photos.live.com has a recently added a Silverlight slide show (though they use the “no-installation experience” – and roll back to an Ajax version with no silverlight player detected). Still it is frustration there are not many more and that Microsoft sites consistently display: image  even if Silverlight is already installed, and provide no context on why you might do that – this links directly to the exe!  Furthermore sites like xbox.com which you think would be an ideal candidate for Silverlight, still have Flash all over them – perhaps they should too take the “no-installation experience” at very least, or maybe take a leaf out of itv.com’s book.

image

Cheers

Ian

Technorati Tags: ,,

12月17日

Third Party & Free Silverlight Controls – Demo Pages

A quick look at the current Silverlight controls available, starting with the paid for ones, and then the surprisingly good free ones!  The screenshots list all the controls available in the collections.  If I have missed any, please let me know.

The Paid For Ones

Infragistics NetAdvantage

http://labs.infragistics.com/silverlight/lobsamples

image

DevExpress Silverlight Controls

http://demos.devexpress.com/Silverlight/

NB: Also see the free DevExpress controls below

image

ComponentOne

http://demo.componentone.com/Silverlight/ControlExplorer/

image

ComponentArt

http://www.componentart.com/webui/roadmap.aspx#sl

image

Telerik

http://demos.telerik.com/silverlight

image

The Free Ones!

Silverlight Contrib

http://www.codeplex.com/Silverlightcontrib & http://silverlightcontrib.org

image

Silverlight Toolkit

http://www.codeplex.com/Silverlight 

image

Dev Express AgDataGrid

http://demos.devexpress.com/AgDataGridDemos/

image

Dev Express AgMenu

http://demos.devexpress.com/AgMenuDemos/

image

Cheers

Ian

Technorati Tags: ,

Silverlight Drag and Drop and HitTest on any layout (not just Canvas)

A common requirement for a rich UI in a business application is to support dragging and dropping of UI elements.  For this to be successful you will need to be able to detect what elements you are dragging over, and you will need to support dragging over any type of layout (such as a complex grid layout), which is a contrast to many examples out there that only show dragging and dropping in relation to absolute layout with a Canvas.

In addition many blogs appear to mention that the UIElement.HitTest method, available in beta’s of Silverlight 2, has since disappeared.  However we have the VisualTreeHelper.FindElementsInHostCoordinates method instead that can perform a point hittest for us (that is it will return the elements a point is inside).

So to that end I have created a simple DragManager class that makes it easy to make any element draggable, and raises events when the dragged element collides with one or more elements.

To use the DragManager simply add the class to your project, create an instance of it, wire up the collision event and call EnableDragableElement on the elements you want to drag.  Note that since this uses the MouseLeftButtonDown, Move and Up events, any control that handles these events internally will not work (e.g. the Button).

DragManager dm = new DragManager(LayoutRoot);
dm.Collision+= dm_Collision;
dm.EnableDragableElement(Ellipse1);
dm.EnableDragableElement(TextBlockStatus);
dm.EnableDragableElement(Image1);

void dm_Collision(object sender, CollisionEventArgs e)
{
    TextBlockStatus.Text = ((FrameworkElement)e.Element).Name + " " + e.Position.X + "," + e.Position.Y + ": ";
    foreach (UIElement element in e.CollidedElements)
    {
        TextBlockStatus.Text += ((FrameworkElement)element).Name + " ";
    }
}

 

Of the interesting methods in the DragManager, the following performs the move for the element, and uses a TranslateTransform to move the element.  This is in contrast to many examples which use the Canvas.Top and Canvas.Left properties, and has the benefit of working with any layout.

void elementToDrag_MouseMove(object sender, MouseEventArgs e)
{
    if (isDragging)
    {
        UIElement element = (UIElement)sender;
        TranslateTransform transform = GetTranslateTransform(element);
        Point currentMousePosition = e.GetPosition(layoutRoot);
        double mouseX = currentMousePosition.X - lastMousePosition.X;
        double mouseY = currentMousePosition.Y - lastMousePosition.Y;
        transform.X += mouseX;
        transform.Y += mouseY;
        if (Collision != null)
        {
            List<UIElement> collidedElements = 
                VisualTreeHelper.FindElementsInHostCoordinates(
                    currentMousePosition, layoutRoot) as List<UIElement>;
            collidedElements.Remove(element);
            collidedElements.Remove(layoutRoot);

            if (collidedElements.Count() > 0)
            {
                CollisionEventArgs args = new CollisionEventArgs() 
                    {   Element = element, 
                        Position = currentMousePosition, 
                        CollidedElements = collidedElements };
                Collision(this, args);
            }
        }
        lastMousePosition = currentMousePosition;

    }
}

 

This method calls GetTranslateTransform which looks for an existing TranslateTransform on the element or adds one if not present.

It also calls the VisualTreeHelper.FindElementsInHostCoordinates method to determine if a collision has taken place and returns a collection of the elements that have been hit (note that we need to remove the layout root and the element we are dragging since they will always be returned.)

Full source is available here:

 

Cheers

Ian

12月11日

Creating Reusable Animations in Silverlight 2

I answered a post on the Silverlight forums recently about creating reusable animations for an Image, and thought that it was worth a blog entry to expand on it a little.

I am looking here at two common approaches to creating reusable animations within a single project:

  1. Create the animation in xaml (using Blend) on one element and then change the target in code.  This is easier to do but means you can only play one animation at a time (because only one animation actually exists)

  2. Create the animation purely in code.  This means you can create as many as you want and have them all playing at the same time, and writing the code gives you more control over changing the animation conditionally at run time.

Of course you can also have a combination of the two (so you could create the animation in blend, then create a copy of it in code and manipulate it)

Using the Xaml Approach

Here's an example of the first approach.  This is the Xaml created by recording an animation in Blend against "Image1".   Notice that I have given the two DoubleAnimationUsingKeyFrames elements names (GrowImageScaleXAnimation and GrowImageScaleYAnimation) so that it is easy to change their properties in code later on:

 

<Storyboard x:Name="GrowImage" AutoReverse="True">
            <DoubleAnimationUsingKeyFrames 
                x:Name="GrowImageScaleXAnimation" 
                BeginTime="00:00:00" 
                Storyboard.TargetName="Image1" 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
                <SplineDoubleKeyFrame 
                    KeyTime="00:00:00.5000000" 
                    Value="1.1" 
                    KeySpline="0.24,0.75,0.9,1"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames 
                x:Name="GrowImageScaleYAnimation" 
                BeginTime="00:00:00" 
                Storyboard.TargetName="Image1" 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
                <SplineDoubleKeyFrame 
                    KeyTime="00:00:00.5000000" 
                    Value="1.1" 
                    KeySpline="0.24,0.75,0.9,1"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>

So if you have two images like this:

<Image x:Name="Image1" Width="100" Height="100" Source="Images/beta.jpg" 
           MouseLeftButtonUp="Image_MouseLeftButtonUp" RenderTransformOrigin="0.5,0.5"> <Image.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Image.RenderTransform> </Image> <Image x:Name="Image2" Width="100" Height="100" Source="Images/beta.jpg"
           MouseLeftButtonUp="Image_MouseLeftButtonUp" RenderTransformOrigin="0.5,0.5"> <Image.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Image.RenderTransform> </Image>

 

You can write the following code to play the animation on either one:

private void PlayXamlImageAnimation(string ImageName)
{
    GrowImage.Stop();
    Storyboard.SetTargetName(GrowImageScaleXAnimation, ImageName);
    Storyboard.SetTargetName(GrowImageScaleYAnimation, ImageName);
    GrowImage.Begin();
}

Using the Pure Code Approach

For the pure code approach you create the animation in code and attach it to the image.  Here is my code to create the animation:

private Storyboard CreateAnimation(DependencyObject image)
{
    Storyboard board = new Storyboard();
    board.AutoReverse = true;

    DoubleAnimationUsingKeyFrames scaleXAnim = 
           GetAnimation(image, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"); DoubleAnimationUsingKeyFrames scaleYAnim =
           GetAnimation(image, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"); board.Children.Add(scaleXAnim); board.Children.Add(scaleYAnim); return board; } private DoubleAnimationUsingKeyFrames GetAnimation(DependencyObject image,string propertyPath) { DoubleAnimationUsingKeyFrames animation = new DoubleAnimationUsingKeyFrames(); animation.BeginTime = TimeSpan.FromSeconds(0); Storyboard.SetTarget(animation, image); Storyboard.SetTargetProperty(animation, new PropertyPath(propertyPath, new object[0])); SplineDoubleKeyFrame spline = new SplineDoubleKeyFrame(); spline.KeyTime = TimeSpan.FromSeconds(0.5); spline.Value = 1.1; KeySpline keySpline = new KeySpline(); keySpline.ControlPoint1 = new Point(0.24, 0.75); keySpline.ControlPoint2 = new Point(0.9, 1); spline.KeySpline = keySpline; animation.KeyFrames.Add(spline); return animation; }

This produces exactly the same animation that was shown in the Xaml above, but is quite a bit more work (in truth I still find it easier to record this in Blend, then manually convert it to code from the Xaml)  The benefit is that we have more control and we can get as many animation instances we want so that we can have them all playing at the same time on different images.  So in this example I create two Storyboards and then instantiate them against my images in the constructor for the page:

 

Storyboard image1Animation;
Storyboard image2Animation;

public Page()
{
    InitializeComponent();
    image1Animation = CreateAnimation(Image1);
    image2Animation =  CreateAnimation(Image2);

}

Then it is simple a matter of playing the animations when needed.

You can download the source from my sky drive:

Cheers

Ian

Technorati Tags: ,,
12月7日

Working with Data in Silverlight 2 (Entity Framework, Ado.Net Data Services, and DataGrid)

Since the announcement from Tim Mallalieu (Program Manager, LINQ to SQL and Entity Framework) that “as of NET 4.0 the Entity Framework will be our recommended data access solution for LINQ to relational scenarios” your first decision on how to get data into and out of your databases has been made easier: EF is the way to go when looking at solutions from Microsoft (of course you may still decide that you would prefer to use something else from a third party, perhaps LLBLGEN, or maybe a hand crafted solution?).

But after that decision you still have another before we get the data anywhere Silverlight – how to “surface” or expose it.  Here you could use a WCF service with a basicHttpBinding a-la the “Silverlight enabled wcf service” template offered to us by Visual Studio 2008 with the Silverlight tools installed.

However a more interesting approach and one that appears to be a better fit with the way Alexandria (i.e. Silverlight 3) will work is to use an Ado.Net Data Service.

So what is an Ado.Net Data Service?  The documentation provides a nice summary:

The goal of the ADO.NET Data Services framework is to facilitate the creation of flexible data services that are naturally integrated with the web. As such, ADO.NET Data Services use URIs to point to pieces of data and simple, well-known formats to represent that data, such as JSON and ATOM (XML-based feed format). This results in the data service being surfaced as a REST-style resource collection that is addressable with URIs and that agents can interact with using standard HTTP verbs such as GET, POST, PUT or DELETE.

So that means that we can surface our data very simply via a REST interface.  Bottom line – you don’t have to write a whole load of methods in your service such as GetProducts, GetProductsById, GetOrder(int Id), UpdateOrder etc etc.  Instead you simple expose your data model through the service.

At this point I usually hear a gasp of belief – “what all our data is available read/write over the web?” – erm yes, but only if you choose not to lock it down.  Ado.Net Data Services combined with the EF give you plenty of scope to control access to data based on a users authentication and to inject business and validation logic.  But that is a blog post for another time.

What I think is particularly interesting from Silverlight when you use this combination of EF and ADO.Net Data Services is that the code you write feels as if you are writing it on the same tier as the database and application logic – in fact, it is not much different, and that is quite compelling.  It makes the classic find data, edit it with business logic applied, and sent back to the database quite easy (with a few gotcha’s which I will list below)

When I show this to delegates on a course who are used to using the Asp.Net Datagrid it gets another gasp, but this time in a positive way (well maybe not a gasp -  but certainly a look of bewilderment that belies the effort that have had to put into doing the same thing in Asp.net previously).

Ok so lets see a little code – I am going to demonstrate editing data from the Products table in the Northwind sample database.

I created a Silverlight Project then added a Ado.Net Entity Data Model to the web site and used the Wizard to add all the tables in the Northwind database to it. At this point you will most likely want to at least add some validation logic, or for more complex systems, extend the model.  I will cover this is later posts, but for now you can get more info on using EF from zeeshanhirani's free entity framework learning guide.pdf  including a walkthrough on this very item.  The msdn documentation is getting better too.

image

Next we add an Ado.Net Data Service to the web site and configure it to use our Entities type (in this case NorthwindEntities).  Also in the example below I have allowed full read/write access to all the data in the model (gasp!).  For more info on controlling access to the entities see the msdn documentation and I will be blogging about this in more details later.

public class NorthwindDataService : DataService< NorthwindEntities >
{
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(IDataServiceConfiguration config)
    {
        // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
        // Examples:
         config.SetEntitySetAccessRule("*", EntitySetRights.All);
         config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
    }
}

Ok we have our data available.  At this point you can browse the svc file and see your data exposed as ATOM. 

image

You can try navigating through the data by using the Url.  For example try the following (changing the port to your own web site of course :-)

image

image

image

Although this looks like read-only data, the service supports updates too through other HTTP verbs (e.g PUT).  So lets put that to the test by adding a service reference to Silverlight and creating an editable grid for the Products table (we will just edit one column for reasons that will become clear).

In the Silverlight project select Add Service Reference, click Discover and give it appropriate name (e.g. NorthwindDataService).  This will build a proxy class for us that supports the Ado.Net Data Service in Silverlight.

image

We are going to use the DataGrid to display and edit the data.  What we want to do is bind the data from our service to the DataGrid, use the grid to edit it, then send the changes back in a batch update.  Currently the DataGrid has a few issues, not least we do not have an event that lets us know when row data has been edited (this was available in beta’s of the grid but was removed in the final release – a strange decision, one that I would expect to be resolved sometime in the future).  To stack up another blog post with the others I have declared in this post, I will take a look at the free AgDataGrid from DevExpress in a later post which does not suffer from this.  We will work around this problem by using a DataTemplate and attaching to the LostFocus event of the TextBox that we will use to edit the data. 

Here is the Xaml for our UI (if you can call it that – just a couple of buttons and a one column grid)

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <Button Content="Get data " Click="Button_Click" Margin="5"  ></Button>
        <Button Content="Save data " Click="Button_Click_1" Margin="5"></Button>
    </StackPanel>

    <data:DataGrid x:Name="DataGrid1"  AutoGenerateColumns="False" Grid.Row="1">
        <data:DataGrid.Columns >

            <data:DataGridTemplateColumn Header="Product">
                <data:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding ProductName, Mode=TwoWay}"></TextBlock>
                    </DataTemplate>
                </data:DataGridTemplateColumn.CellTemplate>
                <data:DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <TextBox LostFocus="TextBox_LostFocus" Tag="{Binding ProductID}" 
                                 Text="{Binding ProductName, Mode=TwoWay}" ></TextBox> </DataTemplate> </data:DataGridTemplateColumn.CellEditingTemplate> </data:DataGridTemplateColumn> </data:DataGrid.Columns> </data:DataGrid> </Grid>

In the code behind we will need to instantiate our service as a class scoped variable.  Notice that the constructor takes a Uri pointing to the svc file we want to use.

NorthwindDataService.NorthwindEntities entities = 
                  new NorthwindDataService.NorthwindEntities(new Uri("NorthwindDataService.svc",UriKind.Relative));

We can then use the DataServicesQuery type to create and execute a query when the Get Data button is clicked.  Ideally we would just bind the results to the DataGrid, but this does not currently work, so instead I am also storing the results of the query in a List<Products> and binding that – this is really a hack to get around the DataGrid problem.

private List<Products> loadedProducts;
private void Button_Click(object sender, RoutedEventArgs e)
 {
     DataServiceQuery<Products> query = (DataServiceQuery<Products>)
         from c in entities.Products
         where c.Discontinued ==false
                 select c;
     DataGrid1.ItemsSource = null;
     query.BeginExecute(new AsyncCallback(c =>
     {
         IEnumerable<Products> results= query.EndExecute(c);
         loadedProducts = results.ToList();
         DataGrid1.ItemsSource = loadedProducts;
         
     }),query);

     
 }

Ok so when this button is clicked the DataGrid will show the result of the query using it’s DataTemplate:

image

Selecting a cell, then clicking again in it will switch the DataGrid it to edit mode (or you could double-click, but that’s not very web ui ;-).  After the data is edited we want to update our entity data with the changes.  Ideally the DataGrid would do this for us automatically, but unfortunately it does not at the moment, so instead we have hooked the LostFocus event on the textbox:

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
    
        int changedItemId = (int)((TextBox)sender).Tag;
        Products changedItem = (from c in loadedProducts
                                where c.ProductID == changedItemId
                                select c).Single();
        entities.UpdateObject(changedItem);
        

}

You will notice that in the DataTemplate for the grid, I embedded the ID for the item in a tag property for the TextBox – I am using this to find the actual product data in the List<Products> we populated when we got the data.  We then call UpdateObject on our entities object and pass the updated item to it.  This has not made any call to the database at this point, just updated our –in-memory entities collection.

Our Save Data event handler looks like the following, most of which is examining the OperationalResponses fro the Ado.Net Data service for exceptions.  The nice bit is that we only need to call BeginSaveChanges on our entities object to update all the changes in the database.

entities.BeginSaveChanges(SaveChangesOptions.ContinueOnError, new AsyncCallback(c =>
           {
               try
               {
                   DataServiceResponse response = entities.EndSaveChanges(c);
                   var operationalResponses = response.GetEnumerator();
                   while (operationalResponses.MoveNext() == true)
                   {
                       MessageBox.Show(operationalResponses.Current.StatusCode + " " + operationalResponses.Current.Error);
                   }
                   MessageBox.Show("Saved");
               }
               catch (DataMisalignedException ex)
               {
                   MessageBox.Show("Misaligned " + ex.Message);
               }
               catch (DataServiceClientException ex)
               {
                   MessageBox.Show("Client " + ex.Message);
               }
               catch (DataServiceRequestException ex)
               {
                   MessageBox.Show("Request " + ex.Message);
                   var operationalResponses = ex.Response.GetEnumerator();
                   while (operationalResponses.MoveNext() == true)
                   {
                       string message = string.Empty;
                       if (operationalResponses.Current.Error != null)
                       {
                           message = operationalResponses.Current.Error.Message;
                       }
                       message += " Status code: " + operationalResponses.Current.StatusCode;
                       MessageBox.Show(message);
                   }
               }
               catch (DataServiceQueryException ex)
               {
                   MessageBox.Show("Query " + ex.Message);
               }
           }), entities);

I hope that has given you an insight to using data with Silverlight 2 – I will be adding more posts to drill deeper into these topics, but you may want to look at the Msdn docs for this for further info

I have uploaded this sample project to my skydrive here:

 

Cheers

Ian

11月27日

Serializing Objects to Isolated Storage in Silverlight 2

Silverlight 2 does not have a BinaryFormatter like the full framework does so you have to take a different approach to serializing data to Isolated Storage.

However there is a simple solution by using the DataContractSerializer.  You will need to add a reference to System.Runtime.Serialization.  This will serialize the object to an Xml format and is what Silverlight uses when you add a service reference.

So if we have an object called Person, we can use the DataContract and DataMember attributes to mark it up as follows:

[DataContract]
public class Person
{
    [DataMember]
    public int PersonId { get; set; }
    [DataMember]
    public string Name { get; set; }
    
}

You can then use the DataContractSerializer as follows to save Person data to Iso storage:

Person p = new Person() { PersonId = 1, Name = "Fred" };
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForSite())
{
    IsolatedStorageFileStream stream = store.CreateFile("Person.dat");
    DataContractSerializer serializer = new DataContractSerializer(typeof(Person));
    serializer.WriteObject(stream, p);
    stream.Close();
}
MessageBox.Show("Data Saved");

And the following to read it:

Person p;
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForSite())
{
    IsolatedStorageFileStream stream = store.OpenFile("Person.dat", FileMode.Open);
    DataContractSerializer serializer = new DataContractSerializer(typeof(Person));
    p = (Person)serializer.ReadObject(stream);
    stream.Close();
}
MessageBox.Show("Data Loaded");
TextBlock1.Text = p.Name + " " + p.PersonId;

If you want to make this more generic you could create a generic method as follows:

private void SaveData<T>(T dataToSave,string fileName)
{
    using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForSite())
    {
        IsolatedStorageFileStream stream = store.CreateFile(fileName);
        DataContractSerializer serializer = new DataContractSerializer(typeof(T));
        serializer.WriteObject(stream, dataToSave);
        stream.Close();
    }
}

Then you can call it as follows:

SaveData<ObservableCollection<Person>>(people, "People.dat");
SaveData<Person>(person, "Person.dat");

Cheers

Ian

11月12日

Working with Xml Files in Silverlight and Isolated Storage

There was a question regarding this over on the Silverlight Forums and I put together a little example there.  This struck me as a scenario that many corporate developers will come across and it is actually so easy and powerful with the combination of Linq to XML and Silverlight Isolated Storage that I thought it was worth a post here.

Isolated Storage is one of the areas that offers a clear advantage to Silverlight – local protected (sandboxed) storage on a per application or site basis that works just like a file system.  Careful use of this can reap great performance gains as demonstrated by Jesse here

And Linq to Xml is Microsoft’s best api yet for working with Xml documents (and we’ve had a few!).  I can see this being one of the easiest “Linq” wins for corporate developers.

So on to the simple example:

Here is the Xaml:

<StackPanel x:Name="LayoutRoot" Background="White">
        <StackPanel Orientation="Horizontal">
            <Button Margin="10" Content="Create Xml" Click="Button_Click"></Button>
            <Button Margin="10" Content="Save Xml file" Click="Button_Click_3"></Button>
            <Button Margin="10" Content="Read Xml file" Click="Button_Click_1"></Button>
            <Button Margin="10" Content="Add Child" Click="Button_Click_2"></Button>
            <Button Margin="10 10 0 10" Content="Remove Child" Click="Button_Click_4"></Button>
<
TextBox Margin="0 10" Text="1" x:Name="TextBox2"></TextBox> </StackPanel> <ScrollViewer Height="200" ScrollViewer.VerticalScrollBarVisibility="Auto"> <TextBox x:Name="TextBox1" AcceptsReturn="True" TextWrapping="Wrap" ></TextBox> </ScrollViewer> </StackPanel>

Which will look like this:

image

Here is the code for the first button which will create an arbitrary XDocument:

private void CreateXdoc()
{
    _xdoc = new XDocument(
                    new XComment("Created " + DateTime.Now.ToLongTimeString()),
                    new XElement("Root",
                        new XElement("Child",  "data1",new XAttribute("attr", 1)),
                        new XElement("Child", "data2", new XAttribute("attr", 2)),
                        new XElement("Child", "data3", new XAttribute("attr", 3)),
                        new XElement("Child", "data4", new XAttribute("attr", 4))
                        )
                        );
    
    ShowXDoc();
}

ShowXDoc() is simple showing the XDoc in the TextBox:

private void ShowXDoc()
{
    TextBox1.Text = _xdoc.ToString();
}

To Save the XDocument into isolated storage we can use the following:

private void SaveXDoc()
{
    using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        IsolatedStorageFileStream stream = store.OpenFile("MyXmlFile.Xml", FileMode.Create, FileAccess.Write);
        _xdoc.Save(stream);
        stream.Dispose();
    }
    MessageBox.Show("Saved");
}

And to read it back:

private void ReadXDoc()
{
    using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        IsolatedStorageFileStream stream = store.OpenFile("MyXmlFile.Xml", FileMode.Open, FileAccess.Read);
        _xdoc = XDocument.Load(stream);
        ShowXDoc();
        stream.Dispose();
    }
}

Because XDocument can work with streams these operations are really simple.

How about manipulating the XDocument?  That’s where Linq to XML comes into play.  It is so easy and intuitive to use that it can be done in a few lines of code.  Here is how to add a new Element to the XDocument:

XElement newChild = new XElement("Child","newdata" ,(new XAttribute("attr", "somevalue")));
_xdoc.Element("Root").Add(newChild);

And here is how to find a particular element based on an attribute value and remove it:

var item = from c in _xdoc.Element("Root").Elements("Child")
           where c.Attribute("attr").Value == TextBox2.Text
           select c;

item.Remove();

Full project available here:

Cheers

Ian