ListViewItem MouseDoubleClick MVVM way - c#

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>

Related

WPF Data binding error on a checkbox within a combobox

Using WPF, I have a checkbox within a combobox and I keep getting a data binding error when trying to bind a command in a checkbox back to my view model. Here's the error
'OnComboMultiSelectCheckedCommand' property not found on 'object' ''String' (HashCode=-66358460)'. BindingExpression:Path=OnComboMultiSelectCheckedCommand;
DataItem='String' (HashCode=-66358460);
target element is 'InvokeCommandAction' (HashCode=61927311);
target property is 'Command' (type 'ICommand')
Here's an excerpt from the XAML
<ComboBox Name="comboMultiSelectBox" SelectedItem="{Binding TargetValue, UpdateSourceTrigger=LostFocus}">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<DataTrigger Binding="{Binding TargetPropert}" Value="Weather">
<Setter Property="ItemsSource" Value="{Binding WeatherList}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
<ComboBox.ItemTemplateSelector>
<customControls:ComboBoxItemTemplateSelector>
<customControls:ComboBoxItemTemplateSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding}"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding OnComboMultiSelectCheckedCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding Path = OnComboMultiSelectUncheckedCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</StackPanel>
</DataTemplate>
</customControls:ComboBoxItemTemplateSelector.ItemTemplate>
<customControls:ComboBoxItemTemplateSelector.SelectedItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text ="{Binding TextForDisplay}"></TextBlock>
</StackPanel>
</DataTemplate>
</customControls:ComboBoxItemTemplateSelector.SelectedItemTemplate>
</customControls:ComboBoxItemTemplateSelector>
</ComboBox.ItemTemplateSelector>
</ComboBox>
I have used a Template selection technique as described in #1012 (https://wpf.2000things.com/?s=combobox).
The itemsource for the combo box (WeatherList) is just a list of strings and the binding for the combobox is definitely working. The problem is that the checkbox is not picking up the commands I have defined in the viewmodel and I get the binding error as described above.
Thanks
Several tips and suggestions here:
You are missing the /CheckBox closure
Try using
{Binding ElementName=comboMultiSelectBox, Path=OnComboMultiSelectCheckedCommand }.
<CheckBox Content="{Binding}"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding ElementName=comboMultiSelectBox, Path=OnComboMultiSelectCheckedCommand }" />
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding ElementName=comboMultiSelectBox, Path=OnComboMultiSelectUncheckedCommand }" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
Create a viewmodel for each WeatherListItem so events can be handled in this dedicated viewmodel itself.

DoubleClick on my ListBox item is not being fired

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>

Binding double click in nested listview

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.

Context menu event or trigger of a control inside an itemtemplate of a listview is not fired

I've got following problem. Following situation in my xaml code:
<ListView ItemsSource="{Binding ListViewItems}">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Label Content="Test">
<Label.ContextMenu>
<ContextMenu ItemsSource="{Binding MenuItems}">
</ContextMenu>
</Label.ContextMenu>
</Label>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding LabelMouseUpCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
After clicking a label no context menu is shown and the trigger does not work as well, LabelMouseUpCommand method is not entered. I fear the listview handles the click itself and does not pass it to the embedded controls.
Is there any way to pass it to the controls. In future i want to add several controls to the itemtemplate and everyone has it own different context menu.
I found the answer for my problem with this stackoverflow article
There the author explains that the contextmenu does not lie in the same visual tree as the listview. Therefore my initial binding can't work because the source can't be found within the visual tree.
Furthermore Sinatr was totally right, the trigger was initially defined for listview, not for the label.
Here is my working code:
<ListView ItemsSource="{Binding ListViewItems}" x:Name="listViewMain">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Label Content="Test">
<Label.ContextMenu>
<ContextMenu ItemsSource="{Binding DataContext.MenuItems, Source={x:Reference listViewMain}}">
</ContextMenu>
</Label.ContextMenu>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding DataContext.LabelMouseUpCommand, Source={x:Reference listViewMain}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

How to proper bind action for view model when invoking Event Selected in TreeViewItem (CaliburnMicro)

I have problem with invoke action in XAML with TreeViewItem. My XAML is following:
<TreeView Name="SystemNodes" ItemsSource="{Binding FirstGeneration}" Margin="0,0,0,0" HorizontalAlignment="Left" Grid.Row="1" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="cal:Message.Attach" Value="[Event Selected] = [Action SendMyText]"/>
</Style>
</TreeView.ItemContainerStyle>
When I run this code I get exception method SendMyText not found. But on the other hand in this same view I have following code:
<StackPanel Grid.Row="4">
<TextBox Text="{Binding Path=MyText, Mode=TwoWay}"/>
<Button Content="Click me" cal:Message.Attach="[Event Click] = [Action SendMyText]"/>
</StackPanel>
And here it works. Why the first approach doesn't work if the second do?
Instead of using TreeView.ItemContainerStyle, replace it by :
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<cal:ActionMessage MethodName="SendMyText" />
</i:EventTrigger>
</i:Interaction.Triggers>

Categories

Resources