Friday, May 7, 2010

Create a DataDriven Hyperlink for Silverlight 4 Navigation

The Navigation model that is provided to us in a Silverlight application rocks!  For a good overview, check out this MSDN site.

One thing I wish we could do would create more data-driven approach to create a HyperlinkButton control on a page.

When we create a hyperlink button right now the XAML looks like

<HyperlinkButton NavigateUri="/Home" Content="home"/>

What we would like is something like

<HyperlinkButton NavigateUri="/Product/{Binding ProductId}" Content="home"/>

So we can put links within databound list type controls, obviously this blows up!

One option is to create something that inherits form HyperlinkButton and provide an additional property so we can get the ID and then bind that into the URI.  Something like this could potentially work.

<CustomHyperlinkButton NavigateUri="/Home/{0}" ItemId={Binding ProductId} Content="home"/>

The value pulled from ItemId will be used to populate the NavigateUri so the result will be a link that contains the id for the current record being bound in the data list.

Here’s the code to make it happen.

namespace MyNamespace
{
    public class CustomItemHyperlink : HyperlinkButton
    {       
        public new Uri NavigateUri
        {
            get{return base.NavigateUri;}
            set
            {
                var currentUri = value.ToString();

                if (!string.IsNullOrEmpty(IdField))
                    base.NavigateUri = new Uri(string.Format(value.ToString(), IdField),
                                         value.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative);
                else
                    base.NavigateUri = value;
            }
        }

        public string IdField
        {
            get { return (string)GetValue(IdFieldProperty); }
            set { SetValue(IdFieldProperty, value); }
        }

        public static readonly DependencyProperty IdFieldProperty =

                          DependencyProperty.Register("IdField", typeof(string), typeof(ListItemHyperlink),

                                                                       new PropertyMetadata(OnIdFieldChanged));

        static void OnIdFieldChanged(object sender DependencyPropertyChangedEventArgs e)
        {
            var item = (sender as ListItemHyperlink);
            item.NavigateUri = new Uri(string.Format(item.NavigateUri.ToString(), item.IdField),
                                item.NavigateUri.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative);
        }
    }
}

Probably could use a bit of effort to make it a bit more solid (checking URI’s and better error messages) but this seems to be working great for my usage.

enjoy

-twb

btw – sorry to my 2 or 3 readers about the lack of additions to my blog over the past few months.  My father passed away April 10, 2010, he will be deeply missed.

2 comments:

  1. Hey Kevin,

    Have you checked out my MVVM Light Template(s) to replace the Navigation Project. Here's the URL - http://www.jaykimble.net/analysis-of-my-sl4-navigation-template-with-mvvm-light-plus-1-more-template.aspx

    I had the same feeling you did and I solve it in the ViewModel of the MainPage (Aka ViewModel/MainPageModel.cs).

    ReplyDelete
  2. Could you use an IValueConverter?

    ReplyDelete