Tuesday, February 22, 2011

Writing a WebMatrix Helper


I’ve been playing around with Microsofts WebMatrix for some time now. Together with the new Razor View Engine, Microsoft introduced the concept of Helpers. Helpers are mostly small static classes with static methods that generate some Javascript or HTML code which is rendered onto a web page at run time. It’s pretty easy to write such a helper yourself and I’m going to present the steps required within this post. As an example, I’ll show you how to create a helper, that inserts a “Add to favorites” link to a site.

Let’s first create a new class library project in Visual Studio 2010. I just name it HelperLibrary. Within the project delete the class that was generated by the Visual Studio template and create a new class named FavoriteHelper. Make the class public and static. Before we can write our methods, we need to import the following two DLLs:
·         System.Web
·         System.Web.WebPages

In the class insert a static method named AddToFavorites with the following signature:

public static HelperResult AddToFavorites(string text)
{
    return new HelperResult(tw => tw.Write(
        "<a href=\":"+
            text+
            "\" onDragstart=\"return false\" "+
            " onClick='window.external.AddFavorite(location.href,
document.title);return false'>"+
            text+"</a>"));
}

The method accepts a string parameter, whose text will later be shown on the web page. It returns an object of type HelperResult which can be interpreted by the Razor Engine. The HelperResult class is contained within the System.Web.WebPages assembly and accepts a TextWriter in its constructor.
Alternatively you could use the following method:

public static IHtmlString AddFavorite(string text)
{
    return new HtmlString("<a href=\":" +
                            text +
                            "\" onDragstart=\"return false\" " +
                            " onClick='window.external.AddFavorite(
location.href, document.title);return false'>" +
                            text + "</a>");
}

In that case you won’t need the System.Web.WebPages.dll. It’s also a little bit easier, because you don’t have to use an additional TextWriter.
After we have inserted our methods, we need to build the library and integrate it into our WebMatrix project. Before compiling the assembly, check the settings and make sure the correct framework version is used. In order to use Razor, you have to target at least .NET Framework 4.0. After building the assembly we can just copy it to the bin folder of our web application project, hit refresh within WebMatrix and insert the call to our helper method on any web page:

@HelperLibrary.Favorites.AddToFavorites("Add to favorites!")

Pay attention to use the full namespace declaration. Otherwise the method won’t be found.
If you start the page, you will see a link on it to add this page to your favorites:


A test by clicking on it reveals that it works:


Friday, January 7, 2011

WPF DataGrid – Row Double Click

The DataGrid in WPF has no special event handler to handle mouse double clicks on a row. If it had, you could easily determine the row that was clicked and could gain access to the underlying data. This blog entry shows a possible solution by implementing the standard mouse event handler. In short terms it looks for the element under the mouse cursor to determine if it’s a row and in that case gets the selected element of the grid.
Let’s start by defining the DataGrid in the view:

<DataGrid x:Name="dataGrid" MouseDoubleClick="DataGrid_MouseDoubleClick"/>

The definition already contains an event handler for the double click event of the mouse. The binding of the data happens in code and is intentionally left out for brevity. In the example a simple DataSet was used. So let’s have a look at the event handler implementation:

private void DataGrid_MouseDoubleClick(object sender,
                                  System.Windows.Input.MouseButtonEventArgs e)
{
    IInputElement element = e.MouseDevice.DirectlyOver;
    if(element != null && element is FrameworkElement)
    {
        if (((FrameworkElement)element).Parent is DataGridCell)
        {
            var grid = sender as DataGrid;
            if (grid != null && grid.SelectedItems != null
&& grid.SelectedItems.Count == 1)
            {
                var rowView = grid.SelectedItem as DataRowView;
                if (rowView != null)
                {
                    DataRow row = rowView.Row;
                    //do something with the underlying data
                }
            }
        }
    }
}

The MouseDevice class has a very nice property called DirectlyOver which returns the element that is directly under the mouse cursor when the event handler is called. All that needs to be done now is to check if this element is a FrameworkElement and in that case if its parent is a DataGridCell. The double click event is fired whenever you click on any element of the grid (e.g. header, row selector, etc.). But we are only interested in rows and so we check if a cell was clicked and only do further processing if that was the case. The rest is very easy. We get the selected item from the grid and cast it to DataRowView because the underlying data source is a DataSet. If you used another object just cast to that object. The DataRowView has a Row property which represents the underlying data.

Wednesday, December 15, 2010

WPF ListView – ScrollIntoView

Lately a colleague of mine had a requirement to add items to a ListView programmatically. After adding an item, the ListView was supposed to scroll automatically so that the newly item came into view. First attempts to use the ScrollIntoView method of the ListView failed. There was just no scrolling at all. So I decided to check things up and here are the results.
ListView uses an ItemContainerGenerator that generates the UI and the visual tree for the ListView and its items. Whenever you add an item to the ListView the generator recreates all the item container elements. It does this in an asynchronous way. Therefore if you add an item programmatically and call ScrollIntoView right afterwards the container items will not have been created at this time and that’s why you won’t see any changes in the UI.
The trick here is to subscribe to the StatusChanged event of the ItemContainerGenerator:

listView.ItemContainerGenerator.StatusChanged += new ItemContainerGenerator_StatusChanged;

In the event handler you can check if the current status of the generator is equal to GeneratorStatus.ContainersGenerated:

void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
    if(listView.ItemContainerGenerator.Status ==
GeneratorStatus.ContainersGenerated)
    {
        var info = listView.Items[listView.Items.Count - 1] as FileInfo;
        if (info == null)
            return;

        listView.ScrollIntoView(info);
    }
}

If this is the case, all items have been created and you can use the ScrollIntoView method. In the example application I used a list of FileInfo objects that were created by a background thread one after another. The parameter of the ScrollIntoView method is of type object and one might suggest passing a ListViewItem, but that won’t work. Just get an item from the Items collection of the ListView and pass it to the method and you will see that the ListView gets scrolled automatically. And don’t forget to unsubscribe from the StatusChanged event. Otherwise nobody will be able to scroll the ListView from the UI.