Derik Whittaker

Syndication

News


Navigating to an external URL using the HyperlinkButton.

If you have ever tried used the HyperlinkButton inside your WP7 application and navigate to an external URL you are familiar with the following error.

"Navigation is only supported to relative URIs that are fragments, or begin with '/', or which contain ';component/'.\r\nParameter name: uri"

Basically when you set the NavigateUri property to anything that is not a local view you will get bad results.  I wanted to build out a version of the HyperlinkButton which not only allows you to navigate to an external url via the WebBrowserTask but I also wanted something that was MVVM friendly.  To accomplish these goals I needed to do the following:

Create a custom HyperlinkButton control called HyperlinkCommandButton

public class HyperlinkCommandButton : HyperlinkButton
{
    public HyperlinkCommandButton()
    {            
        Click += ( sender, e ) =>
                        {
                            if ( Command != null && Command.CanExecute( CommandParameter ) )
                                Command.Execute( CommandParameter );
                        };
    }

    public static DependencyProperty CommandProperty =
        DependencyProperty.Register( "Command",
                                        typeof( ICommand ), typeof( HyperlinkCommandButton ),
                                        new PropertyMetadata( null, CommandChanged ) );

    private static void CommandChanged( DependencyObject source, DependencyPropertyChangedEventArgs args )
    {
        var button = source as HyperlinkCommandButton;
        if ( button == null ) return;

        button.RegisterCommand( args.OldValue as ICommand, args.NewValue as ICommand );
    }

    private void RegisterCommand( ICommand oldCommand, ICommand newCommand )
    {
        if ( oldCommand != null )
            oldCommand.CanExecuteChanged -= HandleCanExecuteChanged;

        if ( newCommand != null )
            newCommand.CanExecuteChanged += HandleCanExecuteChanged;

        HandleCanExecuteChanged( newCommand, EventArgs.Empty );
    }

    private void HandleCanExecuteChanged( object sender, EventArgs args )
    {
        if ( Command != null )
            IsEnabled = Command.CanExecute( CommandParameter );
    }

    public ICommand Command
    {
        get { return GetValue( CommandProperty ) as ICommand; }
        set { SetValue( CommandProperty, value ); }
    }

    public static DependencyProperty CommandParameterProperty =
        DependencyProperty.Register( "CommandParameter",
                                        typeof( object ), typeof( HyperlinkCommandButton ),
                                        new PropertyMetadata( null ) );

    public object CommandParameter
    {
        get { return GetValue( CommandParameterProperty ); }
        set { SetValue( CommandParameterProperty, value ); }
    }
}

Create a ViewModel (which is based of of the MvvM Light framework)

public class MainPageViewModel : ViewModelBase
{
    public MainPageViewModel()
    {
        Url = "http://www.yahoo.com";
        InvokeUrlCommand = new RelayCommand( HandleUrl );
    }

    private void HandleUrl( string url )
    {
        var webBrowserTask = new WebBrowserTask { URL = url };
        webBrowserTask.Show();            
    }

    public ICommand InvokeUrlCommand { get; set; }

    private string _url;
    public string Url
    {
        get { return _url; }
        set 
        { 
            _url = value;
            RaisePropertyChanged( "Url" );
        }
    }
}

Hookup the ViewModel to the HyperlinkCommandButton

<WP7_HyperlinkTextPoc:HyperlinkCommandButton Content="HyperlinkButton" Height="30" HorizontalAlignment="Left" Margin="106,191,0,0" Command="{Binding InvokeUrlCommand}" CommandParameter="{Binding Url}" x:Name="hyperlinkButton2" VerticalAlignment="Top" Width="200" />

After you have created your custom HyperlinkButton which supports commanding and you have setup the ICommand correctly in your ViewModel you can see that enabling it in Xaml is cake.  You should also notice that I am NOT using the NavigateUrl property on the control, this is because I want to handle everything via the command which was wired up.

Now in my example I am NOT checking the URL to see if it is truly a public web address but this would be very easy to do if you want it.

Till next time,


Posted 01-01-2011 1:36 PM by Derik Whittaker
Filed under: ,

[Advertisement]

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)