I am building an application that uses MVVM and am trying to bind a command to a button as seen in this tutorial:
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:
DataContext
and specifying ElementName
, as suggested in this answer.OpenArticleLinkCommand
to the same file as my ArticleItem
model, in case the namespace is somehow not recognized. Any help pointing me in the right direction, or describing how I could debug this kind of stuff would be greatly appreciated.
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"/>