srzsanti
srzsanti

Reputation: 300

Command for button inside a listbox

I have two buttons for each row in one ListBox. I want to link different Click events to the buttons (OuterClick and InnerClick). For some reason, when I click on the button (right now I'm only working on OuterClick), nothing happens.

this is my XAML:

<ListBox ItemsSource="{Binding PlayingNowItems}" BorderThickness="0" HorizontalContentAlignment="Stretch">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Padding" Value="0"/>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Button HorizontalContentAlignment="Stretch">
                <Button.InputBindings>
                    <MouseBinding Gesture="LeftDoubleClick" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.OuterClickCommand}"/>
                </Button.InputBindings>
                <Grid HorizontalAlignment="Stretch">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="2.5*" />
                        <ColumnDefinition Width="6*" />
                        <ColumnDefinition Width="4.5*" />
                        <ColumnDefinition Width="5*" />
                        <ColumnDefinition Width="2*" />
                    </Grid.ColumnDefinitions>
                    <Button Content="Play" Grid.Column="0">
                        <!--<Button.InputBindings>
                            <MouseBinding Gesture="LeftClick" Command="InnerClickCommand"/>
                        </Button.InputBindings>-->
                    </Button>
                    <Label Content="{Binding Name}" Grid.Column="1"/>
                    <Label Content="{Binding Artist}" Grid.Column="2"/>
                    <Label Content="{Binding Album}" Grid.Column="3"/>
                    <Label Content="{Binding Duration}" Grid.Column="4"/>
                </Grid>
            </Button>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

My ViewModel:

private ICommand _outerClickCommand;

public ICommand OuterClickCommand
{
    get;
    set;
}
private void OuterClick()
{
    MessageBox.Show("test");
}

Upvotes: 0

Views: 353

Answers (2)

Surendra Shrestha
Surendra Shrestha

Reputation: 1080

I have created a simple demo that might help you with your problem. Here I used prism's MVVM for simplicity. You can use it according to your requirement. Here are two command that are binded to the outer button command to OuterClickCommand (ListViewItem) and the Inner button command to InnerClickCommand. I didn't know where the command for the inner click was located so here I have demonstrated how to use the InnerClickCommand in both the cases, one is if the command is inside the Item and another is if it is outside the items collection. I personally find it useful to use the Command property of the button but if you like you can also use the MouseBinding and the result should be unchanged.

<Window x:Class="BlankApp1.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="http://prismlibrary.com/"
    prism:ViewModelLocator.AutoWireViewModel="True"
    Title="{Binding Title}" Height="350" Width="525">
<ListBox ItemsSource="{Binding PlayingNowItems}" BorderThickness="0" HorizontalContentAlignment="Stretch">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Padding" Value="0"/>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Button HorizontalContentAlignment="Stretch" Command="{Binding DataContext.OuterClickCommand, RelativeSource={RelativeSource AncestorType=ListBox}}">
                <Grid HorizontalAlignment="Stretch">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="2.5*" />
                        <ColumnDefinition Width="6*" />
                        <ColumnDefinition Width="4.5*" />
                        <ColumnDefinition Width="5*" />
                        <ColumnDefinition Width="2*" />
                    </Grid.ColumnDefinitions>
                    <Button Content="Play 1" Grid.Column="0" Command="{Binding InnerClickCommand}" />
                    <!--<Button Content="Play 2" Grid.Column="0" Command="{Binding DataContext.InnerClickCommand, RelativeSource={RelativeSource AncestorType=ListBox}}" />-->
                    <Label Content="{Binding Name}" Grid.Column="1"/>
                    <Label Content="{Binding Artist}" Grid.Column="2"/>
                    <Label Content="{Binding Album}" Grid.Column="3"/>
                    <Label Content="{Binding Duration}" Grid.Column="4"/>
                </Grid>
            </Button>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

ViewModel

public class MainWindowViewModel : BindableBase
{
    private string _title = "Demo Application";
    public string Title
    {
        get { return _title; }
        set { SetProperty(ref _title, value); }
    }

    private IEnumerable<Item> _playNowItems;
    public IEnumerable<Item> PlayingNowItems
    {
        get { return _playNowItems; }
        set { SetProperty(ref _playNowItems, value); }
    }

    public MainWindowViewModel()
    {
        PlayingNowItems = new List<Item>
        {
            new Item { Name="Item1", Album="Album1", Artist="Artist1", Duration=60 },
            new Item { Name="Item2", Album="Album2", Artist="Artist2", Duration=60 },
            new Item { Name="Item3", Album="Album3", Artist="Artist3", Duration=60 },
            new Item { Name="Item4", Album="Album4", Artist="Artist4", Duration=60 },
        };
    }

    private DelegateCommand _outerClickCommand;
    public DelegateCommand OuterClickCommand =>
        _outerClickCommand ?? (_outerClickCommand = new DelegateCommand(ExecuteOuterClickCommand));

    void ExecuteOuterClickCommand()
    {
        MessageBox.Show("Outer Clicked");
    }

    private DelegateCommand _innerClickCommand;
    public DelegateCommand InnerClickCommand =>
        _innerClickCommand ?? (_innerClickCommand = new DelegateCommand(ExecuteInnerClickCommand));

    void ExecuteInnerClickCommand()
    {
        MessageBox.Show("Inner 1 Clicked");
    }
}

public class Item
{
    public string Name { get; set; }
    public string Artist { get; set; }
    public string Album { get; set; }
    public long Duration { get; set; }

    private DelegateCommand _innerClickCommand;
    public DelegateCommand InnerClickCommand =>
        _innerClickCommand ?? (_innerClickCommand = new DelegateCommand(ExecuteInnerClickCommand));

    void ExecuteInnerClickCommand()
    {
        MessageBox.Show("Inner 2 Clicked");
    }
}

Upvotes: 1

SamTh3D3v
SamTh3D3v

Reputation: 9944

I am not sure what do you mean by nothing happens, your code works just fine, be aware that you are binding the command to a LeftDoubleClick event!

A more straight forward way to bind the commands would be to use ElementName binding, to the ListBox like so:

  <ListBox x:Name="MyListBox" ItemsSource="{Binding PlayingNowItems}" BorderThickness="0" HorizontalContentAlignment="Stretch">
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="Padding" Value="0"/>
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Button HorizontalContentAlignment="Stretch">
                    <Button.InputBindings>
                        <MouseBinding Gesture="LeftDoubleClick" Command="{Binding DataContext.OuterClickCommand,ElementName=MyListBox}"/>
                    </Button.InputBindings>
                    <Grid HorizontalAlignment="Stretch">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="30" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="2.5*" />
                            <ColumnDefinition Width="6*" />
                            <ColumnDefinition Width="4.5*" />
                            <ColumnDefinition Width="5*" />
                            <ColumnDefinition Width="2*" />
                        </Grid.ColumnDefinitions>
                        <Button Content="Play" Grid.Column="0">
                            <Button.InputBindings>
                                <MouseBinding Gesture="LeftClick" Command="{Binding DataContext.InnerClickCommand,ElementName=MyListBox}"/>
                            </Button.InputBindings>
                        </Button>
                        <Label Content="{Binding Name}" Grid.Column="1"/>
                        <Label Content="{Binding Artist}" Grid.Column="2"/>
                        <Label Content="{Binding Album}" Grid.Column="3"/>
                        <Label Content="{Binding Duration}" Grid.Column="4"/>
                    </Grid>
                </Button>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

While the commands in your VM looks something like that:

 private RelayCommand _outerClickCommand;
    public RelayCommand OuterClickCommand
    {
        get
        {
            return _outerClickCommand
                ?? (_outerClickCommand = new RelayCommand(
                () => { MessageBox.Show("OuterClickCommand"); }));
        }
    }
    private RelayCommand _innerClickCommand;
    public RelayCommand InnerClickCommand
    {
        get
        {
            return _innerClickCommand
                ?? (_innerClickCommand = new RelayCommand(
                () => { MessageBox.Show("InnerClickCommand"); }));
        }
    }

Ps: RelayCommand is just a handy relay command implementation from MvvmLight (that you might consider using)

Upvotes: 0

Related Questions