1
votes

I made UWP app with MVVM pattern(i think so :) ) My app have data template for listbox. ListBox in View.xaml:

<ListBox x:Name="lbMySongs" ItemsSource="{Binding Path=MySongs}" ItemTemplate="{StaticResource lbSongsTemplate}" Grid.Row="1">
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            </Style>
        </ListBox.ItemContainerStyle>
</ListBox/>

DateTemplate resource:

       <DataTemplate x:Key="lbSongsTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition Width="auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Path=Artist}" Grid.Column="0"/>
            <TextBlock Text=" - " Grid.Column="1"/>
            <TextBlock Text="{Binding Path=Title}" Grid.Column="2"/>
            //Here i bind command, but it's not binding cos ItemsSource have no command. ViewModel have this command.
            <Button Command="{Binding Path=DownloadCommand}" Content="{Binding Path=Query}"/>
            <TextBlock Text="{Binding Duration}" Grid.Column="5" HorizontalAlignment="Right"/>
        </Grid>
       </DataTemplate>

Need to set DataContext for this button. My command in ViewModel. Example:

class ViewModel
{
    ...
    public RelayCommand DownloadCommand { get; set; }
    public ObservableCollection<SomeClass> MySongs { get; set; }
    ...
}

My problem: DataTemplate have ItemsSource = ViewModel.MySongs. But "DownloadCommand" is in ViewModel. What i type in DataTemplate for my button set binding to DownloadCommand?

2
Select the Button -> Tap F4 on your keyboard you will see properties -> search for Command -> Click Little Grey button after the text box, select Create Binding -> from the binding window select your DownloadCommand - > VoilaAVK

2 Answers

3
votes

Try to use:

<Button Command="{Binding Path=DataContext.DownloadCommand, ElementName=lbMySongs}"
        CommandParameter="{Binding}"
        Content="{Binding Path=Query}"/>

And change

public RelayCommand DownloadCommand { get; set; }

to

public RelayCommand<SomeClass> DownloadCommand { get; set; }
...
DownloadCommand = new RelayCommand<SomeClass>(DownloadExecute);
...
private voir DownloadExecute(SomeClass item)
{
    ...
}
3
votes

Use a RelativeSource binding to say you want to bind to ListBox.DataContext.DownloadCommand

<Button Command="{Binding Path=DataContext.DownloadCommand, 
                          RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" 
        Content="{Binding Path=Query}"/>

Its often common practice like this to also bind the CommandParameter to the item to know what item the command was executed on :

<Button Command="{Binding Path=DataContext.DownloadCommand, 
                          RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" 
        CommandParameter="{Binding }"
        Content="{Binding Path=Query}" />

You could also use an ElementName binding, but then you have to give your ListBox a Name to specify in your DataTemplate, and I don't personally like to hardcode ElementName in my DataTemplates. Makes it annoying to find and fix if you change something's name, or want to use the DataTemplate in another ListBox.