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.
Related
How Command parameter can be bind to the selected index in ListBox? My code:
<ListBox>
<i:Interaction.Triggers>
<i:EventTrigger
EventName="MouseDoubleClick">
<i:InvokeCommandAction
Command="{
Binding Path=SelectPath,
Mode=OneTime,
RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}
}
}"
CommandParameter="ListBox.SelectedIndex" // how can this parameter be bind to SelectedIndex
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
EDIT:
What I did and it works: created new dp property SelectedListBoxIndex bind it with SelectedIndex and then pass property as command parameter. But is there a better way to do it?
<ListBox
SelectedIndex="{
Binding Path=SelectedListBoxIndex,
RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}
}}">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="MouseDoubleClick">
<i:InvokeCommandAction
Command="{
Binding Path=SelectPath,
Mode=OneTime,
RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}
}
}"
CommandParameter="{
Binding Path=SelectedListBoxIndex,
RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}
}
}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
One way could be setting your ListBox x:Name and then binding CommandParameter to its SelectedIndex property like this:
<ListBox x:Name="lb">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="MouseDoubleClick">
<i:InvokeCommandAction
Command="{
Binding Path=SelectPath,
Mode=OneTime,
RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}
}
}"
CommandParameter="{Binding ElementName=lb, Path=SelectedIndex}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
I have a context menu which is binded to a list of items. When I click on an item, the command executes however I am having problems passing the selected item as a parameter, can anyone identify what I'm doing wrong?
I have tried passing {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}} as the command parameter however it just gives me the whole list within the context menu and when. When I tried {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}} no value was seen.
<ContextMenu x:Key="SelectFileTab" ItemsSource="{Binding ContextMenuItems}" x:Name="contextmenu">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}">
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding SelectedFileToAdd, Mode=OneWay}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ContextMenu>
I really over complicated something quite simple, there was no need to use interaction.triggers issue to the command, all I needed to do was
<ContextMenu x:Key="SelectFileTab" ItemsSource="{Binding ContextMenuItems}" x:Name="contextmenu">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}" Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.SelectedFileToAdd}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
Trying to get some keybindings onto my ListBoxItems in a ListBox in WPF. I am using MVVM, and binding the ItemSource of the ListBox to a list of ViewModels. This ViewModel has a string and a boolean for 'Selected'. I wish to display Selected as a property to a CheckBox.
I am trying to make it so that if I navigate the list items with the up and down arrows on the keyboard, and then press enter/space/whatever, I can toggle the Checkbox. However, I have to press tab first, to get focus to the StackPanel which contains the checkbox.
<DataTemplate x:Key="MyTemplate" DataType="{x:Type ViewModel}">
<Border Width="2" BorderBrush="Blue">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding EnterCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<CheckBox VerticalAlignment="Center"
Content="{Binding Name}"
IsChecked="{Binding Selected}"
Margin="3" />
</Border>
</DataTemplate>
=======================
<Popup x:Name="FilterPopup" Grid.Column="1"
IsOpen="{Binding IsChecked, ElementName=FilterButton}"
StaysOpen="False"
PlacementTarget="{Binding ElementName=FilterButton}"
Placement="Top">
<ListBox ItemsSource="{Binding ViewModels}"
ItemTemplate="{StaticResource MyTemplate}" />
</Popup>
Have I missed something obvious???
The triggers above are fired inside the data template, not inside item container. So if the last one is focused there is no effect.
To avoid this, the triggers should be specified on item container level:
<ListBox.ItemContainerStyle>
<Style>
<Setter Property="l:Attach.InputBindings">
<Setter.Value>
<InputBindingCollection>
<KeyBinding Command="{Binding EnterCommand}" Key="Enter" />
<KeyBinding Command="{Binding EnterCommand}" Key="Space" />
</InputBindingCollection>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
I've taken a way to set input bindings from style from this question.
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 am trying to use AttachedCommandBehavior V2 to translate ListBoxItem events such as double click into commands that are execute against the view model.
I want to fire commands for multiple events, this is the example code I am trying to emulate:
<Border Background="Yellow" Width="350" Margin="0,0,10,0" Height="35" CornerRadius="2" x:Name="test">
<local:CommandBehaviorCollection.Behaviors>
<local:BehaviorBinding Event="MouseLeftButtonDown" Action="{Binding DoSomething}" CommandParameter="An Action on MouseLeftButtonDown"/>
<local:BehaviorBinding Event="MouseRightButtonDown" Command="{Binding SomeCommand}" CommandParameter="A Command on MouseRightButtonDown"/>
</local:CommandBehaviorCollection.Behaviors>
<TextBlock Text="MouseDown on this border to execute the command"/>
</Border>
Since I want to apply that to a ListBoxItem, I am trying to do it through a style by doing:
<ListBox.ItemContainerStyle>
<Style>
<Setter Property="acb:CommandBehaviorCollection.Behaviors">
<Setter.Value>
<acb:CommandBehaviorCollection>
<acb:BehaviorBinding Event="MouseDoubleClick" Command="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ListBox}}" CommandParameter="{Binding}"/>
<acb:BehaviorBinding Event="KeyUp" Command="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ListBox}}" CommandParameter="{Binding}"/>
</acb:CommandBehaviorCollection>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
But I get a compile error with that code that says error MC3089: The object 'CommandBehaviorCollection' already has a child and cannot add 'BehaviorBinding'. 'CommandBehaviorCollection' can accept only one child. Line 39 Position 11.
Also if I comment out one of the BehaviorBindings then it compiles but I get a runtime xaml load exception saying "Value cannot be null. Parameter name: property", so I'm not sure if I'm even taking the correct approach.
Can anyone provide an example of the correct syntax to set multiple behavior bindings on a ListBoxItem?
My solution uses interaction triggers and the ItemTemplate not the ItemContainerStyle.
This invokes a mouse double click or key up command in the text box, not the whole list box item.
<UserControl.Resources>
<DataTemplate DataType="{x:Type ViewModel:DataItem}" x:Key="ItemTemplate">
<ContentControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding DoubleClickCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding KeyUpCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBox Text="{Binding Name}">
</TextBox>
</ContentControl>
</DataTemplate>
</UserControl.Resources>
<ListBox x:Name="listBox" ItemTemplate="{StaticResource ItemTemplate}" ItemsSource={Binding Items} />
Where DataItem is something like
class DataItem : INotifyPropertyChanged
{
public string Name{get;set}
.. etc
}
and the view model set on the DataContext has an IList<DataItems> Items{get; private set} property.