Reputation: 300
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
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
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