Latest Tweet:
  • Loading...

Wow. Friday 20th of March and MSDN Live Winter 2009 is now history. I delivered my last two talks on Silverlight during this round of MSDN Live in Oslo yesterday. Over the last two and a half week the MSDN Live road-show have visited Stavanger, Bergen, Trondheim and Oslo. It has been a great experience, and I’ve gotten to meet some interesting developers around the country. It has been great to hear how many people are starting to adopt Silverlight and WPF for their rich client applications, and I’m certain this trend is only going to continue.

As promised this blog post contains links to the Dive Log example application (which will be updated to Silverlight 3 shortly), as well as links to more information relevant to the two sessions I gave during MSDN Live. I've also included a Flickr Photomentury by Rune Grothaug showing a full day of MSDN Live.

Model-View-ViewModel

My first talk at MSDN was about building business focused applications using Silverlight 2. Throughout the talk I demonstrated how the MVVM pattern can help you achieve separation of concerns, and thus giving you more flexible, testable and designer friendly code. Some links to more information:

Silverlight Tips & Tricks

My second talk at MSDN was 6 different Silverlight Tips & Tricks showing how to solve some of the not-so-obvious problems in Silverlight.

  • Recompressing the XAP file to save download size
    A Silverlight XAP file is just a standard ZIP file. By recompressing it with you can save up to 25% download size. During my talk I demonstrated the ReXapper tool, which can be easily integrated to your project as a post-build command.
  • Deep linking in Silverlight applications
    Linking is a core concept of the web. With Rich Internet Applications in AJAX, Silverlight and Flash this becomes a challenge, as we no longer have different pages for each piece of information or screen in the application. Instead we load the application once, and then dynamically load pieces of information without navigating to a new page. This breaks the concept of linking, booking marking and back/forward navigation in the browser. To solve this we need to manually manage history state. In my blog post I use ASP.NET AJAX to solve this. Robby Ingebretsen has another approach using jQuery to manage the browser history.
  • Printing in Silverlight
    Silverlight looks great on screen but does not have a good print story. Printing in Silverlight can be solved by opening a new window showing a server-side rendered report, or you can use the HTML Bridge to generate a client side report.
  • Testing in Silverlight

Hopefully you enjoyed this round of MSDN Live and got a good introduction on how to build Silverlight 2 applications. If you have any questions related to the presentations feel free to post them in the comments section. The code and slides are available as downloads from my SkyDrive (embedded in the blog post).

Dive Log and Flickr Demo Slides for both presentations
Tuesday, March 24, 2009 12:50:08 PM (W. Europe Standard Time, UTC+01:00)
Hi

Thanks for an excellent demo on silverlight and mvvm in Oslo. You were by far the best of all the demos I saw.

I've started to migrate our project from a massive codebehind (yikes!!) to mvvm, and it works great so far. One thing, however, that is proving hard to incorporate is commands in datagrids.

Is there a way to include a command on, lets say, SelectionChanged event? The reason I want to do this is because of the massive amounts of data that we currently transfer. Currently i've seen regular sizes of 2-3mb of data each time I get the customer list and over a slow connection that would take up to half a minute or more to retrieve all the data. What I'd like to do is to transfer a barebone customer list, that does not include any related orders, addresses, etc. When the customer is selected in the datagrid, all that data should be transfered. So, is there a way to do this via commands, or do I have to use codebehind for this?

Thanks

Henning
Henning
Tuesday, March 24, 2009 2:11:23 PM (W. Europe Standard Time, UTC+01:00)
Hi Henning,

And thanks for the comment! I'm really glad you enjoyed the presentation and demo, and that the MVVM pattern is working out nicely for you.

You have a couple of options:

You can add a new property to your ViewModel called "SelectedCustomer". This property could be two-way databound against the SelectedItem property of the grid. In the property setter you could make the web service request to lazy load the additional data from the server.

Second option: You could probably write some kind of attached behaviour (I will have to write a blog post about this soon) to map a Silverlight Event against a Command. Attached behaviour is what I use to add commands to Buttons in the first place in Silverlight (since Silverlight does not got build in support for Commands like WPF do).

The third approach: If you need to handle the UI event, then move the code handling the event out to a seperate class (a Supervising Controller), and have the code to handle this logic in a testable class.

So you could do:

public interface ISelectableView
{
event SelectedIndexChanged;
}

public class MyView : UserControl, ISelectableView
{
public MyView()
{
new SelectedCustomerController(this.customerGrid, this.ViewModel);
}
}

public class SelectedCustomerController
{
public SelectedCustomerController(ISelectableView view, IViewModel viewModel)
{
view.SelectedIndexChanged += ...
}
}


By doing this you move the interaction logic to handle the selection changed event into a testable class only depending on the interface for selected index changed, as well as the ViewModerl which it n eeds to manipulate.

This is similar to the approach I used in the "Combining Different Seperated Presentation Patterns" blog post:
http://jonas.follesoe.no/ct.ashx?id=15ef3682-616a-48e0-96ce-e3f253863cbc&url=http%3a%2f%2fjonas.follesoe.no%2fCombiningDifferentSeparatedPresentationPatterns.aspx

Let me know how it works out! :)

- Jonas

Wednesday, March 25, 2009 3:18:48 PM (W. Europe Standard Time, UTC+01:00)
Hi

Thanks for your answer.
I found a solution to my problems, after some trouble shooting. I was actually using commands on buttons, and after some digging in the code I found out that the CommandManager class we're using is actually hooking up specific event, such as button click, mouse events, etc to the command.
I was able to add an additional "hookup" for SelectionChanged event and it works like a charm.

I now have another issue though, related to updating the ViewModel.
Lets say I have a a list of "light" customer objects, that only contain a few properties, such as name and address. When the customer is selected in the datagrid, the actual customer object, with orders, addresses,etc is downloaded. That works perfectly.
What doesnt work is when I want to update the customer. When the service method is done, it returns the light customer object and the customer list should be updated I try to edit the selected customer, like this

var customers = _model.Customers; //ObservableCollection of customers in viewmodel

var updatedCustomer = e.Object as Customer; //the lightweight customer object that is returned

int index = customers.IndexOf(updatedCustomer);
if (index >= 0)
{
customers.Remove(_model.SelectedCustomer);
customers.Insert(index, updatedCustomer);
}

and I get the following error message, “This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread”, which isnt to difficult to understand, since I'm in a different thread. How can I update the selected customer in the datagrid from another thread?

One solution would be to return a list of all the customers, but that would result in an unneccesary amount of data being transfered, since I only need to update/add one customer to the list.

Sorry for all these dumb newbie questions. Silverlight and mvvm is quite new to me.

Thanks
Henning
Henning
Wednesday, March 25, 2009 3:55:19 PM (W. Europe Standard Time, UTC+01:00)
Hi Hennig,

1) is the updatedCustomer a new object from the service, or an existing object that has been updated? The reason I ask is that if it's a new object returned from the web service, you will not be able to find it in the customers list using IndexOf() (unless you override GetHashCode etc). But I assume that since the Remove and Insert calls (and the threading exception) occour that this isn't the issue.

The problem of updating UI from a non-UI thread is a classic problem. So this is what you have to do:

private void UpdateList(ObservableCollection<Customer> customers, Customer selectedCustomer, Customer updatedCustomer)
{
// your existing logic to get index, remove and add object...
}

then in your async event handler (where your code is currently executing) you have to do:

Dispatcher.BeginInvoke( () => UpdateList(customers, model.SelectedCustomer, updatedCustomer );

This will execute the UpdateList method call on the UI thread. More info about the Dispatcher over at http://wildermuth.com/2008/05/06/Executing_Code_on_the_UI_Thread_in_Silverlight_2.aspx

And your questions isn't dumb at all - and hopefully helpfull to others :)

- Jonas
Wednesday, March 25, 2009 4:39:17 PM (W. Europe Standard Time, UTC+01:00)
The updatedCustomer object is returned from the service.
I did manage to fix this, but in my opinion in a possibly bad way. Since I've implemented mvvm and commands, I don't have any code in my codebehind (wohoo!), but this present me to a new problem. I don't have access to the Dispatcher object in my viewmodel OR UpdateCommand.

The way I solved it was to include a Dispatcher property in my viewmodel. I feel that this is a bad solution, because it ties my viewmodel directly to an xaml, and possibly makes testing a bit more complicated. What are your thoughts on that?

Below is my entire UpdateCommand class.

public class UpdateCommand : ICommand
{
private readonly CustomerViewModel _model;
public UpdateCommand(CustomerViewModel model)
{
_model = model;
}

public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}

public void Execute(object parameter)
{
var customer = parameter as Customer;

if (customer != null)
_model.CustomerClient.UpdateAsync(OnUpdateCustomerCallback, customer);
}

private void OnUpdateCustomerCallback(object sender, ClientEventArgs e)
{

_model.Dispatcher.BeginInvoke(delegate
{
var customers = _model.Customers;
var updatedCustomer = e.Object as Customer;
int index = customers.IndexOf(updatedCustomer);

if (index >= 0)
{
customers.Remove(_model.SelectedCustomer);
customers.Insert(index, updatedCustomer);
_model.SelectedCustomer = updatedCustomer;
}
});

}
}

Henning
Henning
Sunday, April 11, 2010 3:47:42 PM (W. Europe Daylight Time, UTC+02:00)
Nice post
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, strike) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview
<August 2010>
SunMonTueWedThuFriSat
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234