I'm having some problems getting the correct behavior for my WPF user control.
I use a listbox to show elements for a databound ObservableCollection in a datatemplate defined like this
<DataTemplate DataType="{x:Type ToolNodeVM:NodeViewModel}">
<Thumb>
<Thumb.Template>
<ControlTemplate>
<Border Width="160" Margin="0,0,10,0" ClipToBounds="False">
<TextBlock HorizontalAlignment="Center" Text="{Binding NodeName}" Foreground="White"/>
</Border>
</ControlTemplate>
</Thumb.Template>
<i:Interaction.Triggers>
<i:EventTrigger EventName="DragDelta">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding DragDeltaCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Thumb>
</DataTemplate>
If I press on the text block, the thumb receives the mouse event and the DragDeltaCommand databound command is executed, and if there is no element under the mouse (within the Border the Listbox recieves the command and sets the item as the selected one and highlights it with the default blue color.
Eventually I would like to give the item a background, but this would mean the listbox item would never be selected because there would be something in the way... the background of the Border.
How would I proceed in order to let the item always become selected, giving the mouse press event to both the listbox and to the thumb with its drag delta command?
Related
I have ListBox dynamically generated. Each item contains a ProgressBar which I can stop, pause or resume by the means of clicking the relative voice on its ContextMenu.
Here is the XAML code:
<ListBox Grid.Column="1" Name="TransfersList" Margin="30,10,-0.444,34.889" ItemsSource="{Binding DataTx}"
SelectionChanged="TransfersList_SelectionChanged" Grid.Row="1" Grid.ColumnSpan="3"
HorizontalContentAlignment="Stretch">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Ottieni informazioni" Click="GetInfo" />
<MenuItem Header="Metti in pausa" Click="PauseTransfer" />
<MenuItem Header="Riprendi trasferimento" Click="ResumeTransfer" />
<MenuItem Header="Annulla trasferimento" Click="StopTransfer" />
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.ItemTemplate>
<DataTemplate>
<ProgressBar Height="20" Minimum="0" Maximum="{Binding NChunks}" Name="gasparino_il_carbonaro"
Value="{Binding PbStatus}" Foreground="{Binding Color}" ToolTip="{Binding TooltipInfo}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When I click, for example, the ContextMenu "GetInfo" voice, I get always the '-1' SelectedIndex (even if I have many bars).
I suppose that the problem is due to the ProgressBar filling (performing steps and so XAML refreshing), when the ProgressBar is filling/refreshing the "system" becomes unable to understand the selected index (which bar I selected with right click?).
My concise question is:
How can I bind the right-clicked bar with the ContextMenuItem relative
method?
Trying to set up a WPF ComboBox;
some of its items should not be selectable, so I'm binding IsEnabled to some property of the underlying item.
At the same time, I need to define an ItemTemplate that contains e.g. a Button.
This button needs to be clickable, even if the item is not selectable (worth nothing a click on the button should not select the item as such of course; it will trigger a command performing some background actions, which will eventually make the underlying item selectable)
However, when ComboBoxItem.IsEnabled = false, it seems even the button automatically gets disabled.
Brief example:
<ComboBox ItemsSource="{Binding Items}">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsEnabled" Value="{Binding CanSelectItem}"/>
</Style>
</ComboBox.ItemContainerStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<!-- This button isn't clickable when ComboBoxItem.IsEnabled = false .. but it should be! -->
<Button Content="Click me" Command="{Binding SomeCmd}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Is there any way to circumvent this? E.g., set some items as non-selectable, however define a button in the ItemTemplate that remains clickable regardless?
Thanks
When you remove the ComboBox.ItemContainerStyle you can set the IsEnabled property of each element in the DataTemplate
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
IsEnabled="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.IsEnabled}"/>
<Button Content="Click me" Command="{Binding SomeCmd}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
The combobox item will still be enabled but the TextBlock will be disabled.
The binding is just an example. Depends on where your IsEnabled property is. In my example the property is in the viewmodel which is DataContext of your Window.
For future reference, have found another way of doing this, based on this answer:
WPF override IsEnabled from Parent
So basically creating a class derived from button that overrides the default IsEnabled behavior.
Benefit is that this seems to do exactly what I was looking for, but it does change one of WPF's pretty.. default behaviors, so might need to be taken with a bit of care
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 don't understand why I can't detect right click on my list box when I use an MVVM.
I use the event trigger but some events doesn't work.
<ListBox x:Name="PlaylistsList" ItemsSource="{Binding PlaylistsList}" HorizontalAlignment="Left">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseRightButtonDown">
<i:InvokeCommandAction Command="{Binding NewPlaylistCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
My command "NewPlaylistCommand" is never call. Could you help me ?
Thank you.
EDIT:
I found solution to my problem, I used the ContextMenu to interact with my ListBoxItem
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="ListBox">
<TextBlock Text="{Binding Name}"/>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Rename" Command="{Binding RenamePlaylistCommand}"/>
<MenuItem Header="Delete" Command="{Binding DeletePlaylistCommand}" CommandParameter="{Binding SelectedValue, ElementName=PlaylistsList}"/>
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Now I can right click on my item to Rename or Delete it.
Thank you for your help.
Most likely that something inside has swallowed your right click event and hence it has not bubbled up (I suspect it has something to do with context menu behaviors). You COULD use the Preview- events which bubble the other way.
The other solution you could use is to directly apply the interaction to each and every child in the list box (and their children as well).
However I honestly don't expect from a UI point of view that right clicking on a play list will create a new play list...I expect from my years of windows usage that a context menu should pop up, possibly with an "add new play list" menuitem.
I'm trying to launch an ICommand when the user double-clicks on a listbox item. Also, I'm trying to do this using the MVVM pattern.
In this XAML, the key press "p" works perfectly. When I double click on the list box, the command never starts. I've set a break point to confirm "PlayVideoCommand" is not called with a double-click. Am I missing something or do I have to use Setter (which I'm not familiar with)?
<ListBox Name="SmallVideoPreviews" Grid.Column="1" MaxHeight="965"
ItemsSource="{Binding BrowseVideos}"
ItemTemplate="{StaticResource BrowseTemplate}">
<ListBox.InputBindings>
<KeyBinding Key="p"
Command="{Binding PlayVideoCommand}"
CommandParameter="{Binding ElementName=SmallVideoPreviews, Path=SelectedItem}"/>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding PlayVideoCommand}"
CommandParameter="{Binding ElementName=SmallVideoPreviews, Path=SelectedItem}"/>
</ListBox.InputBindings>
</ListBox>
Both double-click and "p" should execute the same command. When using the mouse, I can see the listboxitem is selected. I have a hunch that the MouseBinding Command property is not a dependency property but I don't know how to confirm this.
What's happening in your sample is that the listbox itself is reacting to the double click, but only in the part of it's area that is not covered by a list box item.
You need the event handler to be tied to the listboxitem.
Some ways to do it are here:
Double Click a ListBox item to open a browser
And some discussion about why a little code-behind in MVVM is not necessarily a terrible thing:
Firing a double click event from a WPF ListView item using MVVM
More discussion:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9fb566a2-0bd6-48a7-8db3-312cd3e93340/
It seems that the ListBox doesn't handle double click on a ListBoxItem. This is a good answer:
Can't bind Command to ListBox
One could argue weather or not code-behind is terrible, but it ís possible use a command. Add the LeftDoubleClick gesture to the ItemTemplate like this:
<UserControl.Resources>
<DataTemplate x:Key="BrowseTemplate" >
<StackPanel >
<StackPanel.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding DataContext.PlayVideoCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Mode=OneWay}"
CommandParameter="{Binding }" />
</StackPanel.InputBindings>
<TextBlock Text="{Binding }" Width="50" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>