I have a ListView whose DataTemplate contains a ComboBox. I want to satisfy the following requirements:
- The ListView items are selectable
- When a ListView item is Selected, the ComboBox is focused, has IsDropDownOpen=false and the user rotates the mouse wheel or moves the keyboard up/down arrow, I want to disable the ability to change selection. This should only be possible when the ComboBox has IsDropDownOpen=true.
- When a ListView item is Selected and the ComboBox's IsDropDownOpen=false, I want the MouseWheel event and KeyDown event of the ComboBox to make the ListView scroll, independent of whether the ComboBox has an item selected or not and whether it has focus or doesn't have.
The following simplified XAML file and the corresponding code behind file that is based in this, show what I am trying to do
<UserControl x:Class="WpfApp.Users.UserData"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate x:Key="listViewItemTemplate">
<ComboBox Name="cb" MinWidth="150"
IsHitTestVisible="False"
PreviewMouseWheel="cb_PreviewMouseWheel"
PreviewKeyDown="cb_PreviewKeyDown">
<ComboBoxItem Name="cbi1">Item1</ComboBoxItem>
<ComboBoxItem Name="cbi2">Item2</ComboBoxItem>
</ComboBox>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType={x:Type ListViewItem}},
Path=IsSelected}" Value="True">
<Setter TargetName="cb" Property="IsHitTestVisible" Value="True"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</UserControl.Resources>
<ListView Name="lv" DockPanel.Dock="Top"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.ScrollUnit="Pixel"
VirtualizingStackPanel.VirtualizationMode="Recycling"
ScrollViewer.CanContentScroll="True"
HorizontalContentAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn
CellTemplate="{StaticResource listViewItemTemplate}"/>
</GridView>
</ListView.View>
</ListView>
private void cb_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!((ComboBox)sender).IsDropDownOpen)
{
e.Handled = true;
MouseWheelEventArgs e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
e2.RoutedEvent = UIElement.MouseWheelEvent;
lv.RaiseEvent(e2);
}
}
private void cb_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (!((ComboBox)sender).IsDropDownOpen)
{
e.Handled = true;
KeyEventArgs e2 = new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key);
e2.RoutedEvent = UIElement.KeyDownEvent;
lv.RaiseEvent(e2);
}
}
The cb_PreviewKeyDown
does exactly what I want, but the cb_PreviewMouseWheel
doesn't make the ListView scroll when a ListView item is Selected and the ComboBox's IsDropDownOpen=false, although ListView receives the raised MouseWheel event, as I found in my tests.
What is wrong with my solution? Is there another one that could do what I want?