I've got a ListView nested into another Listview. Now I want to bind an double-click event to the ListViewItems of the inner ListView
<UserControl>
<UserControl.Resources>
<DataTemplate x:Key="DefaultTemplate">
<ListView Name="jobsView" ItemsSource="{Binding jobs}" SelectedItem="{Binding Path=SelectedProduction}" >
<ListView.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding Path=DataContext.ItemSelectedCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" CommandParameter="{Binding ElementName=jobsView, Path=SelectedItem}" />
</ListView.InputBindings>
</ListView>
</DataTemplate>
</UserControl.Resources>
<ListView Name="weekView" ItemsSource="{Binding dayList}" ItemTemplate="{StaticResource DefaultTemplate}" >
</ListView>
</UserControl>
I created a RelayCommand called ItemSelectedCommand in my ViewModel.
public RelayCommand ItemSelectedCommand { get; private set; }
The RelayCommand is not getting triggered. I guess I'm setting the wrong RelativeSource. How would it look correct?
Where is your ListView inserted. Is there in a Visual Tree a parent with type of UserControl?
Also, what's quite good to fix Binding errors is to take a look at the Console. There should be Binding errors that might point you wherte is the mistake. Usually is writes down where it is trying to search for object and property :)
Also, I am not sure if private get; is actually allowed when binding to property.
<StackPanel Grid.Column="1">
<StackPanel.Resources>
<DataTemplate x:Key="DefaultTemplate" DataType="{x:Type sys:String}">
<StackPanel>
<TextBlock Text="{Binding .}"/>
<ListView>
<ListView.ItemsSource>
<CompositeCollection>
<sys:String>Sub Item</sys:String>
</CompositeCollection>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}">
<TextBlock.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding DataContext.RenameCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}, PresentationTraceSources.TraceLevel=High}" CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"/>
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</StackPanel.Resources>
<ListView ItemTemplate="{StaticResource DefaultTemplate}">
<ListView.ItemsSource>
<CompositeCollection>
<sys:String> First Item</sys:String>
</CompositeCollection>
</ListView.ItemsSource>
</ListView>
</StackPanel>
Reason why it wasn't working for you is because the double Click was on an actual ListViewItem and NOT the ListView.
Related
I am implementing a listbox using MVVM approach and I'm having an issue where my double click command is not being triggered. When I launch my application I see my ListBox populated via binding just fine. But when I double click on an item nothing happens. Is there something I'm missing? Many thanks in advance.
Here is how I have my UserControl (xaml) set up
<ListBox
x:Name="Files"
ItemsSource="{Binding FileCollection, Mode=TwoWay}"
SelectedItem="{Binding Filename, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}">
<TextBlock.InputBindings>
<MouseBinding
Gesture="LeftDoubleClick"
Command="{Binding EditFileCommand}"/>
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is how I am setting up my command object in my View Model:
//..using system.windows.input for ICommand
private ICommand editFileCommand = null;
public ICommand EditFileCommand
{
get
{
//RelayCommand comes from GalaSoft.MvvmLight.Command
return editFileCommand ?? new RelayCommand(EditFile);
}
}
private void EditFile()
{
MessageBox.Show("Double Click!");
}
This is almost similar to RelayCommand, you can use it like this:
Declare in your ViewModel:
public RelayCommand EditFileCommand { get; set; }
Then, you need to initialize it:
EditFileCommand = new RelayCommand(EditFile);
The XAML remains equal:
<ListBox
x:Name="Files"
ItemsSource="{Binding FileCollection, Mode=TwoWay}"
SelectedItem="{Binding Filename, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}">
<TextBlock.InputBindings>
<MouseBinding
Gesture="LeftDoubleClick"
Command="{Binding EditFileCommand}"/>
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If the command property is defined in the File class, it should work provided that you actually click on the TextBlock. You could make the TextBlock stretch across the ListBoxItem container by using an ItemContainerStyle:
<ListBox x:Name="Files" ...>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If the command is defined in the view model where the FileCollection property is defined, you should use a RelativeSource:
<TextBlock.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding DataContext.EditFileCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"/>
</TextBlock.InputBindings>
I got a Listbox where each item is a Usercontrol MatchPanel.
That UserControl has a button.
I d like to remove an item when I click on the button of that item.
I used the SelectedItem which is bind to my ViewModel and works well. But sometimes I m able to click on a button of one item without moving the SelectedItem value (the Listbox item dont get focused even if I click on the button of that item...).
Hence I m looking for a way to receive in the command CloseSelectedMatchCommand a parameter which would tell me, for the button I have clicked, at which index of the Listbox it is.
Thanks
Here is my View
<UserControl
DataContext="{Binding ListTradingMatches, Source={StaticResource Locator}}" Height="503.175" Width="409">
<ListBox ItemsSource="{Binding Path=ListMatches}" SelectedItem="{Binding Path=SelectedMatch}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<local:MatchPanel />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is my MatchPanel UserControl
<UserControl x:Class="MatchPanel"
<Label Content="Pts"/>
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBox}},
Path=DataContext.CloseSelectedMatchCommand}" CommandParameter="{Binding}">
</Button>
</Grid>
You can set the DataContext of your UserControl to the item in the DataTemplate:
<DataTemplate>
<StackPanel>
<local:MatchPanel DataContext="{Binding}" />
</StackPanel>
</DataTemplate>
Now the DataContext is set to the item from the collection, you can set the CommandParameter to the relevant property from that object...:
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBox}}, Path=DataContext.CloseSelectedMatchCommand}"
CommandParameter="{Binding Id}" />
..., or just the whole object:
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBox}}, Path=DataContext.CloseSelectedMatchCommand}"
CommandParameter="{Binding}" />
I'm converting my project to use MVVM Light.
So far everything worked fine until I got stuck with binding ListViewItem MouseDoubleClick to a command.
Now it looks like that:
<ListView x:Name="ItemsFromStash" Grid.Column="0" Grid.Row="1"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
ItemsSource="{Binding DropBox.DroppedItems}"
ItemTemplate="{DynamicResource DropItemTemplate}"
SelectedItem="{Binding DropBox.SelectedDropItem}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="Control.MouseDoubleClick"
Handler="EventSetter_OnHandler"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
I'd like to make it look somewhat like that:
<ListView x:Name="ItemsFromStash" Grid.Column="0" Grid.Row="1"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
ItemsSource="{Binding DropBox.DroppedItems}"
ItemTemplate="{DynamicResource DropItemTemplate}"
SelectedItem="{Binding DropBox.SelectedDropItem}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Custom:EventToCommand Command=
"{Binding DropBox.RenameItemCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
But it says:
Property 'Triggers' is not attachable to elements of type 'Style'
I tried moving the command to ListView.MouseDoubleClick, but than the SelectedItem is null sometimes.
How should do it?
The following code works for me on a listbox, it should be the same:
<ListBox x:Name="listbox_name_here"
ItemsSource="{Binding LastEntries}"
SelectedItem="{Binding SelectedExercise, UpdateSourceTrigger=PropertyChanged}"
MinHeight="150" ToolTip="Double click to edit"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<Command:EventToCommand Command="{Binding your_command_name_here}"
CommandParameter="{Binding ElementName=listbox_name_here,
Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
Do note that the command parameter is using the listbox (listview in your case) name to bind the target for the selected item.
View:
<ListView x:Name="lw" ItemsSource="{Binding DroppedItems}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<Custom:EventToCommand Command="{Binding DataContext.RenameItemCommand, ElementName=lw}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.ItemTemplate >
<DataTemplate >
<Label Content="{Binding Field}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Your command:
private ICommand renameItemCommand;
public ICommand RenameItemCommand
{
get
{
if (renameItemCommand == null)
{
renameItemCommand = new RelayCommand(
param => RenameItem()
);
}
return renameItemCommand;
}
}
private void RenameItem()
{
}
One option could be to create a DataTemplate for the ListView items, and include your EventTrigger there. For example,
<ListView x:Name="ItemsFromStash"
ItemsSource="{Binding DropBox.DroppedItems}" ItemTemplate="{DynamicResource DropItemTemplate}"
SelectedItem="{Binding DropBox.SelectedDropItem}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<Custom:EventToCommand Command="{Binding DropBox.RenameItemCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<!-- Place your template controls here -->
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have the following user control
<ListBox ItemsSource="{Binding Persons}"
SelectedItem="{Binding SelectedPerson}"
VerticalAlignment="Top" Width="166" >
<ListBox.Template>
<ControlTemplate>
<StackPanel >
<ItemsPresenter/>
<Button Content="Add" Background="Transparent" Command="{Binding NewItemCommand}"/>
</StackPanel>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Height="16" Width="16" Background="Transparent" Command="{Binding DeleteItemCommand}">
<Image Source="images/delete-icon.png" />
</Button>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and i have a view model for it with two commands, the first command that you can see above NewItemCommand is working fine, how ever the second command DeleteItemCommand doesn't function.
is it because its in the item template?
Yes, this is because the DataContext for the ItemTemplate is the Item from Persons not the ViewModel
To bind the DeleteItemCommand on each item you will need to bind back to the ViewModel that is holding the command
Example, binding to the DataContext of the ListBox
<Button Command="{Binding Path=DataContext.DeleteItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" />
Edit:
If you want to remove the item that the button was clicked on you can pass the item the button belongs to as the CommandParameter and handle that in your comman, Not sure what type of command you are using but this is simple if you are using RelayCommand or DelegateCommand
<Button Command="{Binding Path=DataContext.DeleteItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"
CommandParameter="{Binding}" />
public MainWindow()
{
InitializeComponent();
DeleteItemCommand = new RelayCommand(person => DeletePerson(person as Person));
}
private void DeletePerson(Person person)
{
Collection.Remove(person);
}
This is a pretty easy question I think , but I can't find the answer. I have an itemtemplate defined into a datatemplate. When an item is selected, I wanna trigger a command to select the name of my element and apply it somewhere else. For the moment the MouseDown event doesn't accept my command.
<ListView Margin="4" Grid.Row="1" Grid.ColumnSpan="2" ItemsSource="{Binding Path=ExistingStateInfos, ElementName=Window}"
SelectedItem="{Binding Path=SelectedStateInfo, ElementName=Window}" x:Name="statinfoListview">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type States:StateInfo}">
<TextBlock Text="{Binding Path=Name}" MouseDown="{x:Static MyWindow.ApplyStateInfoNameToStateCommand}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You can't set a command directly to an event handler.
Use EventToCommand from the MVVM LightToolkit
<DataTemplate DataType="{x:Type States:StateInfo}">
<TextBlock Text="{Binding Path=Name}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<Command:EventToCommand Command="{Binding YourCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
In fact ot was bulshit from me, I just add to do
<TextBlock Text="{Binding Path=Name}" MouseDown="{x:Static ApplyStateInfoNameToState_Click}" />
Sorry it's friday. Have a nice weekend :)