I'm attempting to bring a templated item forward (ZIndex) in a databound stackpanel. Since a stackpanel creates a ContentPresenter for each item within it, my visual tree looks like this:
ItemsControl
Border
ItemsPresenter
StackPanel
ContentPresenter
ToggleButton
ContentPresenter
ToggleButton
ContentPresenter
ToggleButton
When a ToggleButton is clicked, it fires off a storyboard like this:
<Storyboard x:Key="MyStoryboard" >
<Int32AnimationUsingKeyFrames BeginTime="0:0:0.000" Duration="0:0:0.350"
Storyboard.TargetProperty="TemplatedParent.(Panel.ZIndex)" >
<Int32KeyFrameCollection>
<DiscreteInt32KeyFrame KeyTime="0:0:0.000" Value="99" />
</Int32KeyFrameCollection>
</Int32AnimationUsingKeyFrames>
</Storyboard>
<Style x:Key="SubStateOptionButtonStyle" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<!-- Toggle Button Contents here -->
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource MyStoryboard}" />
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
However, the TemplatedParent.(Panel.ZIndex) gives me a strange exception:
Value cannot be null.
Parameter name: dp
at System.Windows.DependencyObject.GetValue(DependencyProperty dp)
at System.Windows.Media.Animation.Storyboard.ProcessComplexPath(HybridDictionary clockMappings, DependencyObject targetObject, PropertyPath path, AnimationClock animationClock, HandoffBehavior handoffBehavior, Int64 layer)
at System.Windows.Media.Animation.Storyboard.ClockTreeWalkRecursive(Clock currentClock, DependencyObject containingObject, INameScope nameScope, DependencyObject parentObject, String parentObjectName, PropertyPath parentPropertyPath, HandoffBehavior handoffBehavior, HybridDictionary clockMappings, Int64 layer)
at System.Windows.Media.Animation.Storyboard.ClockTreeWalkRecursive(Clock currentClock, DependencyObject containingObject, INameScope nameScope, DependencyObject parentObject, String parentObjectName, PropertyPath parentPropertyPath, HandoffBehavior handoffBehavior, HybridDictionary clockMappings, Int64 layer)
at System.Windows.Media.Animation.Storyboard.BeginCommon(DependencyObject containingObject, INameScope nameScope, HandoffBehavior handoffBehavior, Boolean isControllable, Int64 layer)
at System.Windows.Media.Animation.BeginStoryboard.Begin(DependencyObject targetObject, INameScope nameScope, Int64 layer)
etc.
I've double checked via code-behind that the ToggleButton's TemplatedParent is indeed the ContentPresenter and I can set the ZIndex with something like this:
Panel.SetZIndex((sender as ToggleButton).TemplatedParent as UIElement, 99);
But I'd like to animate it with a storyboard, preferably with straight XAML, since it needs to stay forward for the duration of the storyboard, then go back to where it was.
I've considered inheriting from ItemsControl to prevent the ContentPresenter from being created but that's a heavy-handed solution to something that seems like it should be easy.
Here is the answer to this question:
http://social.msdn.microsoft.com/Forums/en/wpf/thread/7b9b8209-063d-46b2-a03f-98b393cf9514
(by Min Zhu [MSFT])
Your original code doesn't work because TemplatedParent is not a dependency property. So it is not a valid path for animation.
The code TI82 suggests is correct. It still doesn't work because the TemplatedParent is the Button. But the element you want to animate is the item container.
To animate the item container, you can use ItemsControl's ItemContainerStyle. Button.Click is a bubbling routed event, so it will bubble from the button to the item container as well.
Try the following code.
<Window.Resources>
<Storyboard x:Key="MyStoryboard">
<ColorAnimation Storyboard.TargetName="ButtonRect"
Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
To="Red"
Duration="0:0:0.350"
FillBehavior="Stop"/>
</Storyboard>
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Panel.ZIndex" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContentPresenter}, Mode=OneWayToSource, Path=(Panel.ZIndex)}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Height="60" Margin="0,0,0,-10" >
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="15">
<Rectangle x:Name="ButtonRect" RadiusX="15" RadiusY="15" Fill="AliceBlue" />
</Border>
<TextBlock Text="{Binding}" FontSize="15" TextAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource MyStoryboard}" />
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="MyButtonTemplate">
<Grid>
<Button Style="{StaticResource MyButtonStyle}" />
</Grid>
</DataTemplate>
<Storyboard x:Key="MyStoryboard2">
<Int32AnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.ZIndex)"
BeginTime="0:0:0.000" Duration="0:0:0.350" FillBehavior="Stop">
<Int32KeyFrameCollection>
<DiscreteInt32KeyFrame KeyTime="0:0:0.000" Value="99" />
</Int32KeyFrameCollection>
</Int32AnimationUsingKeyFrames>
</Storyboard>
<Style x:Key="MyItemContainerStyle">
<Style.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard Storyboard="{StaticResource MyStoryboard2}"/>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="ABCDEF"
ItemTemplate="{StaticResource MyButtonTemplate}"
ItemContainerStyle="{StaticResource MyItemContainerStyle}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
Related
I have a problem with an animation within a template of an ItemsControl that is part of the template of another ItemsControl. I want a path, that is representing an Icon, to change its color and constantly rotate when a certain condition becomes true.
The DataTrigger generally works, causing the Fill of the Path changing from Gray to LightGreen when the producing Property changes to true. However, the animation does not start. When I let the animation start with the Loaded Event (as you can see in the commented section), it starts properly. So I know that the animation, as well as the DataTrigger, is configured correctly.
When I put the same Path (just copy and paste) in the outside ItemsControl and change the DataTrigger to a Property of the corresponding DataType, the animation also works as expected. So there seems to be a problem with the nested ItemsControls, but I have no idea what it might be.
<ItemsControl ItemsSource="{Binding Computers}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type models:ClientComputerWrapper}">
<Border Margin="5" BorderBrush="Black" BorderThickness="1" Padding="5">
<StackPanel>
<!-- Some Content -->
<ItemsControl ItemsSource="{Binding PlcReaderStatuses}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type resources:PlcReaderStatusResource}">
<DockPanel LastChildFill="False">
<!-- Some Content -->
<Path DockPanel.Dock="Left" HorizontalAlignment="Left" Data="{StaticResource GearIconGeometry}" Stretch="Uniform" RenderTransformOrigin="0.5, 0.5">
<Path.RenderTransform>
<RotateTransform x:Name="gearPathTransform"/>
</Path.RenderTransform>
<Path.Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="Gray"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsProducing}" Value="True">
<Setter Property="Fill" Value="LightGreen"/>
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="rotateStoryBoard">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)" To="360" Duration="0:0:2" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="rotateStoryBoard"/>
</DataTrigger.ExitActions>
</DataTrigger>
<EventTrigger RoutedEvent="Loaded">
<!--<BeginStoryboard x:Name="rotateStoryBoard">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Path.RenderTransform).(RotateTransform.Angle)" To="360" Duration="0:0:2" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>-->
</EventTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</DockPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I've finally found a solution. After trying to replace the DoubleAnimation with a ColorAnimation, using (Path.Fill).(SolidColorBrush.Color) as TargetProperty, I received an error that the path is not pointing to a DependencyProperty. This was only solved when I defined the SolidColorBrush explicitly in a Setter which led my to try the same with the RenderTransform of the Path:
<Path.Style>
<Style TargetType="Path">
<Setter Property="RotateTransform">
<Setter.Value>
<RotateTransform x:Name="gearPathTransform"/>
</Setter.Value>
</Setter>
<!-- ... -->
</Style>
Afterwards the animation works as expected. I still don't know why this is only necessary in the inner ItemsControl and it is also nasty that there is no error as is for the ColorAnimation, but at least it is working now.
I have got a ListBox.ItemTemplate that has got a ToggleButton and inside of it a checkbox and a ProgressBarEdit from devexpress.
Then I have a style that targets the checkbox. When the mouse is over the checkbox it changes its opacity.
The double animation and the binding works fine, however the listbox itemssource is bound and I would like to make all the checkboxes opacity change when the mouse is over any checkbox and not just one.
I tried to bind Storyboard.TargetProperty to my viewmodel property but it is not a dependency property so I cannot do it.
This is the animation:
<Style x:Key="FadeOutButton" TargetType="{x:Type CheckBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, ElementName=chkImport}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1"
Storyboard.TargetProperty="Opacity"
To="1" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1"
Storyboard.TargetProperty="Opacity"
To="0.02" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
This is part of the ListBox control:
<ListBox x:Name="FileDetailsListBox"
Grid.Column="2"
BorderThickness="0"
ItemsSource="{Binding FileDetailsList}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="FileToggleButton"
Margin="-1,0,-1,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
BorderThickness="0,0">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<CheckBox x:Name="chkImport"
Margin="0,0,0,3"
HorizontalContentAlignment="Center"
IsChecked="{Binding Import,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Opacity="{Binding DataContext.ImportOpacity,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ElementName=ImportView}"
Style="{StaticResource FadeOutButton}" />
<dxe:ProgressBarEdit Grid.Row="2"
Height="20"
Margin="-3,0,-3,0"
EditValue="{Binding ProgressValue}"
ShowBorder="False"
StyleSettings="{Binding IsMarquee,
Converter={StaticResource conv}}" />
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
How can I change all the checkboxes opacity from the Listbox when Control.MouseEnter is triggered?
I thought the way to go was binding the ImportOpacity property from my viewmodel in the style, but the animation does not allow it.
Thanks
Update:
I cannot post images because I am new here, but I would like to change the Opacity for all the checkboxes created by the datatemplate when the mouse enter in any checkbox. The animation works fine for individual checkboxes like the code does at the moment.
My viewmodel has got a property called "ImportOpacity" and it is bound to the checkbox.opacity (you can see it in the xaml above) My idea was to use this property to make the Opacity from 0 to 100 when the mouse is over any checkbox.
Instead of animate the Opacity property of the CheckBox and bind it to ImportOpacity with TwoWay mode, I think you should animate the ImportOpacity property in your ViewModeldirectly.
Here is a reference about how to animate property in ViewModel.
Is there any opportunity to set event handler inside xaml without using c#, powershell etc.?
For example I would like to set text of another control after click. Below is a "pseudo code" of what I want to do:
<Button Content="Set value = text1" OnClick="txt1.Text = text1" />
<Button Content="Set value = text2" OnClick="txt1.Text = text2" />
<Textbox Name="txt1" />
You can write inline c# in xaml. Altho that is just something you should rather be avoiding at all costs. If you absolutely have to, you could do something like:
<StackPanel>
<Button Content="Set value = text1" Click="InlineHandler" />
<Button Content="Set value = text2" Click="InlineHandler" />
<TextBox Name="txt1" />
<x:Code>
<![CDATA[
private void InlineHandler(object sender, RoutedEventArgs e) {
var btn = sender as Button;
if (btn == null)
return;
txt1.Text = btn.Content.ToString() == "Set value = text1" ? "text1" : "text2";
}
]]>
</x:Code>
</StackPanel>
MSDN Link - Code-Behind and XAML in WPF
In simple terms, you're just defining the event handler inline in xaml than in the code-behind.
Again do not resort to this approach unless you're proving a point.
there is a solution with EventTrigger. Though it does not work with TextBox, because the Text-Property is not animatable, you could change the text of a textblock with some buttons without any code behind.
But: This is not a nice solution, and you should either use some short codebehind (preferable in an attached behavior) or a small viewModel where you bind to some property. The last one should be the cleanest solution, the codebehind is the shortest.
for feasability, here's the template with which you can change the Text of a Control with pure xaml:
<ControlTemplate x:Key="MyTemplate" TargetType="Control">
<StackPanel Orientation="Horizontal">
<Button x:Name="buttonValueText1" Content="Set value = text1" Width="50" Height="50"/>
<Button x:Name="buttonValueText2" Content="Set value = text2" Width="50" Height="50"/>
<TextBlock x:Name="textBox" Height="30" Width="100" Margin="5"/>
</StackPanel>
<ControlTemplate.Triggers>
<EventTrigger SourceName="buttonValueText1" RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<StringAnimationUsingKeyFrames Storyboard.TargetName="textBox" Storyboard.TargetProperty="Text">
<DiscreteStringKeyFrame Value="Text1" KeyTime="0:0:0.1"/>
</StringAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger SourceName="buttonValueText2" RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<StringAnimationUsingKeyFrames Storyboard.TargetName="textBox" Storyboard.TargetProperty="Text">
<DiscreteStringKeyFrame Value="Text2" KeyTime="0:0:0.1"/>
</StringAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
To give you an idea of how you maybe could solve this
<StackPanel>
<ToggleButton Name="B1" Width="50" Height="50" Content="Text1"/>
<ToggleButton Name="B2" Width="50" Height="50" Content="Text2"/>
<TextBlock Width="50" Height="50" >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=B1, Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{Binding ElementName=B1, Path=Content}"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=B2, Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{Binding ElementName=B2, Path=Content}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
Writing the XAML handler in PowerShell is a steep cliff. Writing the whole UI isn't. Myself and Joel Bennett (aka Jaykul) merged together two wildly popular solutions for this (WPK and PowerBoots) into ShowUI.
New-StackPanel {
New-Button "Set Text Value 1" -On_Click { $textBlock.Text = 1 }
New-Button "Set Text Value 2" -On_Click { $textBlock.Text = 2 }
New-TextBlock -Name textBlock
} -show
Because PowerShell can coerce many more types than XAML, it's actually a lot more convenient for rapid development of a user interface.
I have a DataTemplate for an ItemsControl which is working fine. There is a DataTrigger in the DataTemplate which contains a BeginStoryboard EnterAction. I am trying to wire up the Completed event of the storyboard to something in code behind, specifically a method on the data object, but I can be flexible about that - at the moment I just want it to run any piece of C# code when the animation has completed.
Specifying a value for the Completed XAML attribute does not compile as the attribute is defined inside a template so there is no specific method to wire up to. So I will need to use code behind to wire up the event manually.
To this end I have looked at the application with Snoop to try to find where in the logical or visual tree the inflated template Storyboards end up. So far all I can see is a ContentControl created for each item, with its ContentTemplate set. The Content property of each ContentControl is set to its corresponding data object. The ContentTemplate property contains the Triggers collection which contain the EnterActions and ultimately the Storyboard. My question is, do all the items share a single template instance for their ContentTemplate property, or do they each get their own copy? If they share one, then where are the inflated triggers and storyboards created?
I've extracted the pertinent parts of my XAML:
<Style TargetType="{x:Type m:MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type m:MyControl}">
<Grid Name="ControlRoot" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<!-- ... -->
<ItemsControl ItemsSource="...">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type m:MyDataType}">
<Grid>
<Ellipse Name="IconHighlight1" Fill="{DynamicResource GoldRadialFade}" Width="70" Height="70" StrokeThickness="0" Opacity="0"/>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Highlighted}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard HandoffBehavior="Compose">
<Storyboard Name="ConnectToMe" Duration="0:0:2.5" FillBehavior="Stop">
<DoubleAnimation To="400" Duration="0:0:1.5" Storyboard.TargetName="IconHighlight1" Storyboard.TargetProperty="Height" FillBehavior="Stop" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In such cases, I'd normally prefer to have a bool in the DataContext of the Item that your Storyboard is applying to and say call it AnimationCompleted
Now by modifying your Storyboard to
<Storyboard x:Key="ConnectToMe" Duration="0:0:2.5" FillBehavior="Stop">
<DoubleAnimation To="400" Duration="0:0:1.5" Storyboard.TargetName="IconHighlight1" Storyboard.TargetProperty="Height" FillBehavior="Stop" />
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="DataContext.AnimationCompleted" FillBehavior="HoldEnd">
<DiscreteBooleanKeyFrame Value="False" KeyTime="0:0:0" />
</BooleanAnimationUsingKeyFrames>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="DataContext.AnimationCompleted" FillBehavior="HoldEnd">
<DiscreteBooleanKeyFrame Value="True" KeyTime="0:0:2.5" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
We toggle the bool AnimationCompleted to true at the end point of the animation. Hence in the property setter of AnimationCompleted check if the incoming value is True and trigger your corresponding function/method from there
I have a simple ListBox.ItemTemplate containing a Label and a TextBox bound to a CSLA Bindable List. When I select the TextBox the CurrentItem does not change, it only changes if I select the Label. I have IsSynchronizedWithCurrentItem='True'.
<ListBox x:Name="ItemsDataGrid"
ItemsSource="{Binding Source={StaticResource AuditItems},Path=Items}"
IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Content="{Binding Path=TypeRef}" />
<TextBox x:Name="TextBoxQty"
Grid.Column="1"
Text="{Binding Path=TaliQty}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Try adding this to your ListBox. It selects the item any time any contained element (like TextBox) gets keyboard focus. A similar method could also be used with just a simple setter in the Trigger but that tends to interfere with the CurrentItem setting on the ICollectionView:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Trigger.EnterActions>
<BeginStoryboard x:Name="SetSelected">
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
<DiscreteBooleanKeyFrame KeyTime="0:00" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="SetSelected"/>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
This is happening because the TextBox is handling the MouseDown event. As it is set to bubble up it will not reach the containing ListBoxItem. The simplest way to fix this would be to just handle the selection of the ListBoxItems in the PreviewMouseDown, which will occur and tunnel down before the actual MouseDown event bubbles up.
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="PreviewMouseDown"
Handler="ListBoxItem_PreviewMouseDown" />
</Style>
</ListBox.ItemContainerStyle>
And in the Code behind for the xaml file:
private void ListBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var item = (sender as ListBoxItem);
if (item != null)
item.IsSelected = true;
}