Monday, June 29, 2009

Adventures while building a Silverlight Enterprise application part #14

As some of you may remember from the very first episodes of this series, in our application we use modules to separate functionality. This allows for a scalable solution on many fronts. Recently however I was asked by some of the functional designers if it was possible to use the modules in multiple ways.
Now this always was the plan, but some of the requirements were missed in the earlier stages of our project. We didn't anticipate the fact that, not only would our modules have a different look, based on where they would be used, also they would have to have some features change, based on the fact that they were used differently.
Here is what we have identified we need:
  • Normal use: this is basically how we have our modules in our applications. They should display there titles on the top, provide sizing capabilities for either two or three formats (title bar only, normal view and extended view for datagrid modules), provide a save button (and a new button for our datagrid) and some other functionality.
  • Wizard use: we want to stack some modules on top of each other in different steps of wizards we provide for our users. This means the title bar should be gone, the new and save buttons are not there, modules can't size and there should be a title on the left with a description for each module.
  • Popup use: we want some modules to be able to pop up and be modal to all other parts of the UI. The exact requirements are to be determined.
  • Separate use: we want to be able to use some modules as a standalone peace of kit. Again we're not completely sure as to what the requirements will be.
I pondered about this for a bit and then said, "sure we can do this, just give me a day". Here is what I came up with. I decided that each module should not provide any of the functionality that has to change between uses. These functionalities should be provided by a container. I could then build a container for each use of a module. This allows me to not only provide XAML code in the container (which, as you all know from a previous post is not possible in base classes for user controls). It would also give me a single point to change these shared functionalities, which took away another conceirn about not being able to implement changes to the general functionality of a module without touching each module.

I went ahead and put this in our application and I was pleased by the fact that it was so easy to do this in Silverlight. I simply have a usercontrol with the functionality and XAML required and all I needed to embed a module was a ContentPresentor and to have some interface (IModule) to provide access to some of the functionality inside the module (like save and new).

I would love to show you some code, but I can't as this is part of my companies software. Still I hope this inspires anyone that needs to have a single point to put code, but still needs to be able to place XAML as part of that, to consider using a container type of solution with the ContentPresentor. If you have any questions, comments or other responses, please wait for the beep...

Beep! :-)

Wednesday, June 24, 2009

The birth of CodeEmbed4Web

I've been blogging here for some time now and I've been active on many forums and in several communities and I've always been annoyed by the fact that non of the media used has decent support for adding different kinds of source code and other technical content to them. Sure, a there are a lot of suggestions as how to do this, but they never really met my expectations. They either take to much effort or the result is not looking good enough.

Thinking about this the other day made me decide to make my own tool for this. I sad down, thought about my process of using technical content and I came up with how I felt the flow should be. Here is what I figured will work the best for me:
  1. Copy some code from Visual Studio
  2. Click a button in my tool / press some short-cut key combination
  3. Paste the result in whatever
Using these steps would have the least impact on my normal working flow and therefor make the most sense. There are some challenges, however. I would need the tool to detect whatever I put in to it and I would need it to know what format to convert it into. Especially that last step seems to be impossible. How would it know what I'm planning to paste my code into?
Thinking about that some more, I decided to scrap that last bit and add a small step to the flow:
  1. Copy some code from Visual Studio
  2. Choose a target if necessary
  3. Click a button in my tool / press some short-cut key combination
  4. Paste the result in whatever
Obviously I can still optimize that by making available more buttons or short-cut key combinations, but I didn't want to put in that much effort right at the beginning.

As I'm experienced in buildin Silverlight 2.0 applications I decided to use WPF as my technology. This allows me to access the clipboard and it has better keyboard support then Silverlight. Also, having to open a web application, has been one of the causes that using some of the existing tools takes to much effort.

I've been playing around with WPF and the clipboard and found out that VS (at least 2008) copies it's content to the clipboard using the RTF format. This drew me towards the RichTextBox control, so I placed one in my window and pasted the content into it and it looked great. I studied the documentation on the underlying FlowDocument technology and decided to run with it.

Now I've already built code to convert RTF to a FlowDocument instance (without the RichTextBox control, obviously) and then to XML, which will allow me to build several XSLT templates on top of that XML, which I can then apply to the XML to get to the end result.

Next steps will be:
  1. Test this with XAML
  2. Build templates for C# and XAML to convert to HTML (and maybe XAML?)
  3. Brush up the user interface
  4. Build a setup
  5. Release Beta 1
You've read that right. I will release this tool, and for free (at least for now). So if you're interested in this tool, please come back to my blog for more news or better yet, subscribe to my RSS feed on the top-right of this page.
If you have any question, suggestions or comments, you know the drill (that means, leave them below).

Wednesday, June 17, 2009

Adventures while building a Silverlight Enterprise application part #13

At times you run into decisions made at the early stages of design, that you regret, or at least find inconvenient. This happens to the best of us, especially when using new technologies. In our case we ran into the downside of using ADO.NET Entity Framework (EF) in our application and part #13 already looked like a good one to look at why this is the case.

Why EF doesn't always make sense
Because we are talking a big application here (several hundred forms and grids), and because we are using Silverlight 2 as our client, we decided to make a Business Layer Service, that takes care of our CRUD operations and make this generic. This means we now only have five operations instead of having over a thousand. This still makes us very happy as maintenance is low and you don't have to bother with a lot of code in this part of the system, however...

... in EF, whenever you do a save you need to supply all the connected entities or at least a reference it can use. For a small application with a very limited number of entities this is not a problem. Just code it up for each class and you're done. For our application however, we have a generic save and although we are able to write code for separate business objects (which translate into entities in our service), we'd rather not do this for something that should be the same for all our objects. I should state that this choice was a direct result of us using Silverlight 2 as our client. Writing several hundred save routines sounds like a job for an intern, which we don't have. :-)

We did end up building a generic save, but it did take some hassle to make it work in all scenarios. Especially combining both saving a new entity with saving an already existing one proved to be somewhat problematic.

If I then look further back in the process and see the effort that wend in to building the generic loading in several scenarios, getting a single item, getting a list of items based on some criteria, etc., I'm realy not sure if it was worth the effort with using EF. Why not just build your own?

The good
There is one reason however, and that's the model. The fact that you have in intermittend model that all your code is based on is something that may very well prove very valuable in the future. You could make changes to your datamodel and just change your mappings to go with it and presto, it still works.

If you're reading this and think to yourself: "Design your datamodel right and there is no need to do this", then you realy should get a few more years of experience in the new world. It is no longer acceptable to say that something can't be done, because the datamodel doesn't support it. Customers will not understand / don't care about this and just tell us to fix it and they are right (they eventually pay my salary :-) ).

Conclusion
So was it a bad choice? Should you or shouldn't you use EF in your larger applications? In our case I'd say it hasn't payed itself back yet, but it very well may still do that. I guess it still depends on your application and you should always have a good look at requirements like lifespan, scalability, performance, etc.. In general I think that EF can work for larger applications (as it does work for us), but you shouldn't be caught by what the demos try to make us believe. You can't build your data access services in a matter of minutes, especially if you need your service to work with Silverlight 2. It can still take months to do it with EF.

I hope this post is helpful to you when making your technology choices. Please leave any comments and/or questions below. I'm always happy to read and reply to them.

Wednesday, June 10, 2009

Adventures while building a Silverlight Enterprise application part #12

In this episode we have a closer look at the behavior of the Silverlight 2 DataGrid and especially when databinding and in relation to selecting items.

One of the UI elements that we have in our application is that whenever you select an item in DataGrid A, this updates DataGrid B. Not a very difficult peace of code on itself. However, if you need to select an item from DataGrid B right after this update, that's where trouble begins.
Debugging my source I realized that it had to do with the timing between setting the ItemsSource property to supply new data, and setting the SelectedItem property to select the correct item.
DataGrid A is only a UI element that happens to trigger the refreshing of the data, so it's not important in our problem.

With this information I wrote a small testapplication that demonstrates the problem I had.
The XAML looks like this:

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="DataGridSelection.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300" Loaded="UserControl_Loaded">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<data:DataGrid x:Name="dataGrid"
SelectionChanged="dataGrid_SelectionChanged"
ItemsSource="{Binding}"
LoadingRow="dataGrid_LoadingRow"/>
<Button x:Name="updateItemsSourceButton"
Content="Update ItemsSource"
Click="updateItemsSourceButton_Click"
Grid.Row="1"/>
</Grid>
</UserControl>

As you can see I have a single DataGrid to place data in. I subscribed to the SelectionChanged and LoadingRow events so I can demonstrate what happens.
I also use a Button that allows me to refresh the data easily and finally I have a Loaded event to handle the initial data creation.

Next is the code behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading;

namespace DataGridSelection
{
public partial class Page : UserControl
{
private ObservableCollection<string> _data;
private bool _loadingRow;

public Page()
{
InitializeComponent();
RecreateData();
}

private void RecreateData()
{
_data = new ObservableCollection<string>();
_data.Add("Item 1");
_data.Add("Item 2");
}

private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Debug.WriteLine("Selection changed to index {0}", dataGrid.SelectedIndex);
if (_loadingRow)
{
Debug.WriteLine("Changed because of loading row");
}
_loadingRow = false;
}

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
dataGrid.ItemsSource = _data;
}

private void updateItemsSourceButton_Click(object sender, RoutedEventArgs e)
{
int selectedIndex = dataGrid.SelectedIndex;
RecreateData();

dataGrid.ItemsSource = _data;
dataGrid.SelectedIndex = selectedIndex;
Debug.WriteLine("Exiting click event");
}

private void dataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
Debug.WriteLine("Loading row");
_loadingRow = true;
}
}
}


So for test data I've simply used an ObservableCollection of strings, to which I add two items in the RecreateData method. This allows me to reinstantiate the collection at any given moment.

The problem code is in the Buttons Click event. I first retrieve the SelectedItem index, so I can later try and restore the selection. I then reinstantiate the data collection and reasign the data to the ItemsSource property of the DataGrid. After that I set the SelectedIndex property to restore the original selection. It seems like this should work, right? Wrong!

If you would test this, you'd find out that after reloading the data the first item is always selected. It doesn't matter what value I put in SelectedIndex. I could do exactly the same thing with SelectedItem and it would have the same result.
To make it more clear, as to what happens when, I added the debug output to the source, ran the application, selected the second item (SelectedIndex = 1) and pressed the button.

Here is the debug output:

Loading row
Loading row
Selection changed to index 0
Changed because of loading row
Selection changed to index 1
Selection changed to index 1
Exiting click event
Loading row
Loading row
Selection changed to index 0
Changed because of loading row

Now, the first four lines are from starting the application. The fifth line is from me, selecting the second item in the grid by clicking it. The two lines after that are from the last two lines of code of the click event, first setting the SelectedIndex property and then exiting the event. As you can see, the actual loading of the data happens after we exited the click event. As a result the selection is reset after that as well.

To find out more about this, and maybe find a way to get around this, I fired up Reflector and started digging around in the DataGrid's code. I found out that it uses the SetValue method of it's base class (DependencyObject), but I couldn't exactly find out why the data gets loaded after the user code is executed, nor did I find any indication as to how I could get around this behavior. My best guess so far is that at some point the control of loading the data is passed trough a Dispatcher instance and gets transfered out the main thread (which makes sense as you don't want your user to wait for this process).

I did find a solution direction in my test application however. The _loadingRow field actually gave me some inspiration as to how to solve this in my application.

I use two methods and two fields for this solution. To update the _loadingRow field I wrote a method SetLoadingRow so I have some point where I can handle changes in the field.
I also wrote another method called SelectItem, backed by a field to store the selected item, independent of the DataGrid. In the SelectItem method optionally I also set the SelectedItem property of the DataGrid.
In the SetLoadingRow method I only update the SelectedItem of the DataGrid if I was loading rows, but I'm now done (so the new value passed is false, but the current value is true) and if I have a selected item already and it's different from the selected item in the DataGrid.

SelectItem is called whenever I need to select an item from code. SetLoadingRow(true) is called whenever the LoadingRow event of the DataGrid is triggered and SetLoadingRow(false) is called at the end of the SelectionChanged event of the DataGrid.

This workes like a charm (altough I had some very specific other issues concerning state between different parts in my application, but I won't bother you with that :-) ).
I hope this can be helpful to you as well, even if only to know your not the only one struggling with this tricky side effect. If you have any questions or comments, please leave them below. I always look forward to them.