fire an event in ViewModel on ListBoxItem click - c#

Issue
I am having some problems finding the correct property to use to bind a click event on a ListBoxItem to a property in my ViewModel.
Code
Here is my ListBox XAML code:
<ListBox dd:DragDrop.IsDragSource="True" dd:DragDrop.IsDropTarget="True" Background="#ececec" SelectedItem="{Binding SelectedSlideDataItem}" ItemsSource="{Binding SlideDataItems}" Grid.Column="2" Grid.Row="10" Grid.RowSpan="4" Grid.ColumnSpan="13">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<!--<Setter Property="Padding" Value="5,0,5,5" />-->
<Setter Property="Height" Value="110"/>
<Setter Property="Width" Value="200"/>
<Style.Triggers>
<Trigger Property="Control.IsMouseOver" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<Image Source="{Binding BackgroundImage}" Height="240" Width="400" />
</Setter.Value>
</Setter>
<Setter Property="Control.Background" Value="#d64b36" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#c83a25" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="#c83a25" />
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="#c83a25"/>
</ListBox.Resources>
</ListBox>
So when a user clicks one of the items in the ListBox. I need an event to fire in my ViewModel.

1) With Interactivity and MVVM :
<ListBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding YourCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
2) - Or in Style without MVVM
<Style TargetType="ListViewItem">
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick"/>
</Style>

Use MouseLeftButtonUp event
<ListBox dd:DragDrop.IsDragSource="True" dd:DragDrop.IsDropTarget="True"
Background="#ececec" SelectedItem="{Binding SelectedSlideDataItem}" ItemsSource="
{Binding SlideDataItems}" Grid.Column="2" Grid.Row="10" Grid.RowSpan="4"
Grid.ColumnSpan="13" MouseLeftButtonUp={//Bind with VM}/>

Related

WPF XAML listbox selected item border color

I have implemented some listbox which contains border and a grid in this border.
<Style x:Key="SelectedHiglightStyle"
TargetType="{x:Type ListBoxItem}"
BasedOn="{StaticResource MaterialDesignListBoxItem}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="Transparent" />
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Background"
Value="#316308" />
<Setter Property="Opacity"
Value="0.8" />
</Trigger>
</Style.Triggers>
</Style>
<ListBox IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Row="3"
ScrollViewer.CanContentScroll="False"
Style="{StaticResource MaterialDesignListBox}"
ItemsSource="{Binding Devices}"
SelectedItem="{Binding SelectedDevice, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
ItemContainerStyle="{StaticResource SelectedHiglightStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Rectangle Width="35"
Height="35"
Margin="5"
HorizontalAlignment="Left"
OpacityMask="{DynamicResource DashboardDeviceLogo}">
<Rectangle.Fill>
................
<Grid Grid.Column="1">
<StackPanel>
<TextBlock Text="{lex:Loc DeviceName}"
Margin="0,4,0,2" />
<TextBlock x:Name="tbDeviceName"
Text="{Binding Device.Name}"
FontSize="10" />
................
How I can change color of selected item border? Each item has his own view-model. Is there a easier way than broadcast message via Messanger (I'm using MVVM Light) , capture it in all DeviceViewModel's, compare id of device and then bind the color from view-model?
You could define a Style with a DataTrigger that binds to the IsSelected property of the parent ListBoxItem container:
<ListBox.ItemTemplate>
<DataTemplate>
<Border>
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="Black" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter Property="BorderBrush" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid>
...
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
The Style is applied to the Border element in your ItemTemplate.
The easiest way to do this is here.
If you need just to change selection border you write this in listboxitem's style triggers section
<Trigger Property="IsSelected" Value="True">
<!--your code...-->
<Setter Property="BorderBrush"
Value="Red"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
And edit your datatemplate, binding your border to setters of borderbrush and borderthickness in style
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">...
I've edited my answer cause first time I read this question, I thought you need different borderbrush for each type of data. But your case is much easier

ListBoxItem ContextMenu only when ListBox Multiple Items Selected

How can I disable the listboxitem context menu when none or only one item is selected?
ListBox has a SelectedItems property, but it is read only and you cannot bind to it.
<ListBox ItemsSource="{Binding Items}" SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="GOGO" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This should work:
<ListBox ItemsSource="{Binding Items}" SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="GOGO" />
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItems.Count, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" Value="0">
<Setter Property="ContextMenu" Value="{x:Null}" />
</DataTrigger>
<DataTrigger Binding="{Binding SelectedItems.Count, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" Value="1">
<Setter Property="ContextMenu" Value="{x:Null}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Adding two DataTriggers checking whether the SelectedItems.Count is 0 or 1 in which case it sets the ContextMenu to {x:Null}.

disable ListBox Highlighting when Right Clicked

Is anyone able to tell me, what is not right in the following source code ??
(I'm trying to disable the gray highlight on my listBox Items when doing a right click on them)
<ListBox ItemsSource="{Binding TotoList}"
VerticalAlignment="Stretch"
VerticalContentAlignment="Top">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="Transparent" />
</Style.Resources>
</Style>
</ListBox.Style>
<ListBox.Template>
<ControlTemplate>
<Border BorderBrush="DarkGray"
BorderThickness="0">
<ItemsPresenter />
</Border>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Transparent"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<Grid Width="120">
<Label Content="{Binding Name}"
HorizontalAlignment="Left"
Margin="5,0,0,0"/>
</Grid>
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="Transparent" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
Click="removeToto">
</MenuItem>
</ContextMenu>
</Border.ContextMenu>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When doing a right click on a listBox Item in order to remove it, the Item is highlighted in Gray...
Add the following resource also to your ListBox resources. The following key is responsible for Inactive Selection Brush.
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="Transparent" />

Changing selection color of ListBoxItem

How can I add IsSelected trigger to following ListBox, which will change Background of Border called PlaceHolder. I can't do this by adding IsSelected trigger just next to IsMouseOver. I don't want to select whole ListBoxItem, just Border. Appreciate any help!
<ListBox>
<ListBox.Template>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</ListBox.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="2" Columns="3"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Border CornerRadius="5" x:Name="PlaceHolder" BorderBrush="PapayaWhip" BorderThickness="1">
<StackPanel Orientation="Horizontal" Width="148" Height="60">
<Image Source="{Binding Image}"></Image>
<Label VerticalAlignment="Center" x:Name="title" FontSize="12" FontWeight="SemiBold" Foreground="Gray" Content="{Binding Title}"></Label>
</StackPanel>
</Border>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="Bisque"></Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
You will have to bind to the ListBoxItem.IsSelected property.
This should work
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</Style.Resources>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Border CornerRadius="5" x:Name="PlaceHolder" BorderBrush="PapayaWhip" BorderThickness="1">
<StackPanel Orientation="Horizontal" Width="148" Height="60">
<Image Source="{Binding Image}"></Image>
<Label VerticalAlignment="Center" x:Name="title" FontSize="12" FontWeight="SemiBold" Foreground="Gray" Content="{Binding Title}"></Label>
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True">
<Setter TargetName="PlaceHolder" Property="Border.Background" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>

Highlight TextBlock only in TreeViewItem with Image

So I have a TreeViewItem that has the following style:
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Name="img" Width="20" Height="16" Stretch="Uniform" Source="Images/Folder.png"/>
<TextBlock Text="{Binding}" Margin="5,0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
When selected, the TextBlock AND Image are highlighted. I'm trying to just highlight the TextBlock so it functions like the folders tree in file explorer.
I've found a (somewhat hacky) but lightweight solution to this problem. I see that this question is pretty old, but nonetheless, I'll post the solution here for others to find.
In my TreeView, I override the two brushes used for setting the background of the TreeViewItem when its selection changes. I also create copies of the brushes so I can restore them later in my data template:
<TreeView ItemsSource="{Binding Path=SomeDataSource}">
<TreeView.Resources>
<SolidColorBrush x:Key="_CustomHighlightBrushKey" Color="{Binding Source={StaticResource {x:Static SystemColors.HighlightBrushKey}}, Path=Color}" />
<SolidColorBrush x:Key="_CustomControlBrushKey" Color="{Binding Source={StaticResource {x:Static SystemColors.ControlBrushKey}}, Path=Color}" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</TreeView.Resources>
</TreeView>
Note that I couldn't get this to work with a DynamicResource binding, so this solution probably won't work with theme changes. I would be very interested to know if there is a way to do this.
I then use the following hierarchical data template for formatting tree nodes:
<HierarchicalDataTemplate DataType="{x:Type SomeViewModelType}" ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="{Binding Source={StaticResource {x:Static SystemColors.HighlightBrushKey}}, Path=Color}" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{Binding Source={StaticResource {x:Static SystemColors.ControlBrushKey}}, Path=Color}" />
</StackPanel.Resources>
<Image SnapsToDevicePixels="True" Source="...">
</Image>
<TextBlock Text="{Binding Path=DisplayName}" Margin="5,0">
<TextBlock.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=IsSelected}" Value="True">
<Setter Property="Background" Value="{DynamicResource _CustomHighlightBrushKey}" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=IsSelected}" Value="True" />
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=IsSelectionActive}" Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{DynamicResource _CustomControlBrushKey}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Resources>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
Note that I restore the system brushes to their original (static) values so context menus can be rendered correctly.
You will need to roll your own highlight mark up, so instead of letting the control painting the entire panel background blue, you set your own highlight formatting based on a trigger when TreeViewItem.IsSelected is True.
In your case this would be setting the text container background to blue (when set, white normally) and leaving the image container background as white, whilst setting the overall container background to white.
The method is described here: link text

Categories

Resources