Search code examples
c#xamlmvvmwindows-phone-8.1icommand

Unable to bind a Command to a HyperlinkButton (Windows Phone 8.1)


I am building an application that uses MVVM and am trying to bind a command to a button as seen in this tutorial:

https://channel9.msdn.com/Series/Windows-Phone-8-1-Development-for-Absolute-Beginners/Part-24-Binding-to-Commands-and-CommandParameters

However, I cannot get the binding to work - nothing happens when i click the HyperlinkButton and a breakpoint I put at the beginning of the Execute method does not fire.

Here is my ViewModel:

public class ArticleListViewModel
{
    public IEnumerable<ArticleItem> Items { get; set; }

    public async Task PopulateArticles()
    {
      // ...
    }
}


public class ArticleItem
{
    public ArticleItem()
    {
        OpenLinkCommand = new OpenArticleLinkCommand();
    }

    public ICommand OpenLinkCommand; 

    public string Url { get; set; }

    public string Title { get; set; }
}

OpenArticleLinkCommand.cs:

public class OpenArticleLinkCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public async void Execute(object parameter)
    {
        var article = parameter as ArticleItem;

        if (article != null)
        {
            var success = await Launcher.LaunchUriAsync(new Uri(article.Url));

            //TODO: handle success/fail
        }
    }
}

Here is what my View looks like:

<UserControl
    x:Class="LTNewsFeed.Views.ArticleItemView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:LTNewsFeed.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">


    <ListBox ItemsSource="{Binding}" x:Name="mainListBox">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">

                    <HyperlinkButton x:Name="Title" 
                                     Content="{Binding Path=Title, Mode=OneWay}" 
                                     Command="{Binding OpenLinkCommand}"   
                                     Grid.Column="0"/>

                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

</UserControl>

Main Page.xaml:

<Page
    x:Class="LTNewsFeed.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:LTNewsFeed"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:views="using:LTNewsFeed.Views"
    xmlns:src="using:LTNewsFeed"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <views:ArticleItemView x:Name="ItemsOnPage" />
    </Grid>
</Page>

I populate the view model items collection in the MainPage.xaml.cs:

    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        await viewModel.PopulateArticles();

        ItemsOnPage.DataContext = viewModel.Items;
    }

Things I've tried with no success:

  • Referencing the DataContext and specifying ElementName, as suggested in this answer.
  • Changing the HyperlinkButton to a simple Button.
  • Moving the OpenArticleLinkCommand to the same file as my ArticleItem model, in case the namespace is somehow not recognized.
  • Browsing similar questions on Google and StackOverflow - it seems to me I'm doing everything the same as in the examples.

Any help pointing me in the right direction, or describing how I could debug this kind of stuff would be greatly appreciated.


Solution

  • As weird as it sounds, bindings only work on properties. So you need to expose your command as a property instead of a field:

    public ICommand OpenLinkCommand { get; set; }
    

    You could have noticed this by looking at the Output panel of Visual Studio, where the error message was displayed at execution time:

    Error: BindingExpression path error: 'OpenLinkCommand' property not found

    Note that you'll immediately encounter another issue: you're expecting a parameter for your command, but you forgot to set one. Since you're apparently expecting an ArticleItem as parameter, you can simply bind the datacontext:

    <HyperlinkButton x:Name="Title" 
         Content="{Binding Path=Title, Mode=OneWay}" 
         Command="{Binding OpenLinkCommand}"   
         CommandParameter="{Binding}"
         Grid.Column="0"/>