Tag Archives: DataGridHyperlinkColumn

Hyperlink columns: displaying the link in a browser

A while back I posted an article on how to use the WPF DataGridHyperlinkColumn. There, the web page referenced by the hyperlink was displayed in the application’s own window, using WPF’s internal web browser. This browser has a lot of limitations, and it’s more usual for links like these to lead to the page being displayed in the user’s favourite web browser.

This post shows the modifications we need to make to have this happen.

The first thing we need to do (assuming we don’t want the page to show up in the application’s own window as well) is convert all uses of the NavigationWindow back to a normal Window. This is fairly safe to do by using a global find and replace in Visual Studio. Typically, NavigationWindow is used only in the XAML file and in the behind code for this file (where it serves as the base class for the MainWindow class). This will prevent the web page from appearing in the application itself.

To get the link to show up in the default browser, we need to add an explicit event handler to the DataGridHyperlinkColumn. If we modify the hyperlink column we used in our earlier example of a comic book database application, the XAML now looks like this:

                                <DataGridHyperlinkColumn  Header="ComicVine" Binding="{Binding ComicVine}"
                                        ContentBinding="{Binding ComicVine, Converter={StaticResource ComicVineConverter}}"
                                          Width="67">
                                    <DataGridHyperlinkColumn.ElementStyle>
                                        <Style>
                                            <EventSetter Event="Hyperlink.Click" Handler="WebPageClick"/>
                                        </Style>
                                    </DataGridHyperlinkColumn.ElementStyle>
                                </DataGridHyperlinkColumn>

The properties of the hyperlink column itself are the same as before. The change is that we’ve added an ElementStyle section, in which we’ve provided a link to a handler for the Hyperlink.Click event. This handler is in the MainWindow class and looks like this:

    private void WebPageClick(object sender, RoutedEventArgs e)
    {
      Hyperlink link = e.OriginalSource as Hyperlink;
      Process.Start(link.NavigateUri.AbsoluteUri);
    }

This code retrieves the hyperlink that was clicked, and then starts an external process by calling Process.Start() with the hyperlink as the argument. This uses Windows’ association of file type to application, so if your default browser is, say, Google Chrome, then sending a URI to Process.Start() will cause Chrome to be started and sent the URI to display.

In order for this code to work, you’ll need a couple of ‘using’ statements at the top:

using System.Diagnostics;
using System.Windows.Documents;

That’s all there is to it.

Advertisements

Hyperlink columns in a WPF DataGrid

In the last couple of posts (here and here) we’ve seen how to connect to a MySQL database and use a DataGrid as a UI for editing the contents of the database. One useful feature of a DataGrid is its DataGridHyperlinkColumn, in which each cell is a hyperlink to a URL. In the Comics database, for example, we store with each comic a link to its page at the ComicVine web site.

In order for the hyperlinks in such a column to become active, we need to embed the page in a NavigationWindow or a Frame. We’ll have a look at NavigationWindow here.

The NavigationWindow works pretty much the same way as the ordinary Window. To convert an existing Window-based WPF application into one using NavigationWindow, replace the Window tag at the start and end by NavigationWindow. Also, change the Window.Resources block to NavigationWindow.Resources.

One difference, however, is that the NavigationWindow doesn’t support direct content, meaning that you can’t place a layout manager like Grid directly into a NavigationWindow. After the NavigationWindow.Resources block, you need to insert a NavigationWindow.Content block, and you can then place your root Grid layout inside that. Those are the only changes you need to make to convert to NavigationWindow.

So what does a NavigationWindow do for you? The main thing is that it provides an embedded web browser, so that when you click on a hyperlink, the web page will be displayed inside the application’s main window. You will also see ‘forward’ and ‘back’ navigation buttons at the top of the window, which work in the same way as in a regular browser, except that the original display of the DataGrid is included in the sequence of windows displayed. For example, if you start with a DataGrid containing a hyperlink and click on the hyperlink, you’ll be sent to the web page you clicked on. If you then click the ‘back’ button, you’re taken back to the DataGrid.

I haven’t explored the browser in great depth, but it appears to be a stripped-down version of Internet Explorer. It seems to be OK for displaying more web pages, but pages requiring interaction (such as the editing page at ComicVine) aren’t fully supported; the text editor on this page won’t work, and ComicVine provides a simpler notepad-like editor in its place. But for just displaying a page for the user’s information it seems fine.

One other feature of the hyperlink column is worth mentioning. By default, the column will display the text entered into a cell as a hyperlink. However, usually URLs are quite long and often don’t contain user-friendly text so it’s not obvious where the link is directing you. A better interface can be built by providing a converter that displays more user-friendly text. In the Comics example, the entry for the column is this:

   <DataGridHyperlinkColumn  Header="ComicVine" Binding="{Binding ComicVine}"
     ContentBinding="{Binding ComicVine, Converter={StaticResource ComicVineConverter}}"
     IsReadOnly="True"/>

The ‘Binding’ property binds the text that is used as the URL. By default, this is also the text that is displayed in the column’s cells. If we want the column to display different text, but still link that text to the underlying URL, we can specify a ‘ContentBinding’. In this case, we’ve bound the content to the same text as the main URL binding, but we’ve provided a converter which will change the text displayed. In a cleverer application, we might be able to extract some text from the URL to create a user-friendly label. In this case, however, we’ve just produced the constant string ‘ComicVine’ as the display content. The converter is specified in the NavigationWindow.Resources section as:

    <local:ComicVineConverter x:Key="ComicVineConverter"/>

The code behind looks like this:

  class ComicVineConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      if (value != null && value.ToString().Length > 0)
      {
        string comicVine = "ComicVine";
        return comicVine;
      }
      string empty = "";
      return empty;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      Uri comicVine = new Uri((string)value);
      return comicVine;
    }
  }

We could get fancy and do some string parsing on the URL, or we could pass in a parameter containing other information such as the issue’s title and number, and use these to build a label tailored to each issue. However, since all the information is already displayed on the same row in the DataGrid, this seems a bit redundant.