WPF ListBoxItem 控件模板破坏了部分MouseDown/Selection

7
我有一个关于ListBoxItem的问题。 我正在尝试使ListBoxItem中的所有控件同时选择它,因此单击TextBox、Label等将选择ListBoxItem。 到目前为止还是非常简单的。
我还更改了ListBoxItem模板,将选定可视化从突出显示背景更改为仅绘制边框。 也很简单。
然而,这两者的结合似乎会导致某些非常恼人的问题,特别是在我的情况下,涉及Grid中的Label,其中一个创建了由Grid空间占用的“void”。
使用Snoop,我可以看到PreviewMouseDown事件停在ListBox内的ScrollViewer上,而不是一直到ListBoxItem。
XAML:
<Window x:Class="ListBoxClickThroughTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>
        <ListBox ItemsSource="{Binding Items}"
                 SelectionMode="Single">

            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>

                        <Label Name="VerySuperLongLabel"
                               Grid.Row="0"
                               Grid.Column="0"
                               HorizontalAlignment="Left"
                               Content="VerySuperLongLabel"
                               Padding="0" />

                        <TextBox Name="Textbox1"
                                 Grid.Row="0"
                                 Grid.Column="1"
                                 HorizontalAlignment="Stretch"
                                 HorizontalContentAlignment="Right"
                                 Text="Textbox1 Text" />


                        <Label Name="ShortLabel"
                               Grid.Row="1"
                               Grid.Column="0"
                               HorizontalAlignment="Left"
                               Content="ShortLabel"
                               Padding="0" />
                        <TextBox Name="Textbox2"
                                 Grid.Row="1"
                                 Grid.Column="1"
                                 HorizontalAlignment="Stretch"
                                 HorizontalContentAlignment="Right"
                                 Text="Textbox2 Text" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>

            <ListBox.ItemContainerStyle>
                <Style TargetType="{x:Type ListBoxItem}">
                    <EventSetter Event="PreviewMouseDown"
                                 Handler="ListBoxItem_PreviewMouseDown" />
                    <EventSetter Event="MouseDown"
                                 Handler="ListBoxItem_PreviewMouseDown" />
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                <Border x:Name="Bd"
                                        BorderThickness="1">
                                    <ContentPresenter />
                                </Border>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsSelected" Value="true">
                                        <Setter TargetName="Bd" Property="BorderBrush" Value="Gray" />
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>

    </Grid>
</Window>

代码后台:

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace ListBoxClickThroughTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            Items = new List<string>() { "1", "2" };
            InitializeComponent();
            DataContext = this;
        }

        public List<string> Items { get; set; }

        private void ListBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            var listBoxItem = (ListBoxItem)sender;
            listBoxItem.IsSelected = true;
        }
    }
}

然而,如果我移除Template的setter,一切都正常。这个模板里有些神奇的地方我没有注意到吗?我试着将边框重命名为"Bd",因为默认模板边框就是这个名字,但是没有成功。有什么想法吗?


你是想在点击第二个列表项右侧的空白处时绘制边框吗? - Aaron Thomas
@aaron,我正试图通过单击“ListBoxItem”中的_任何位置_来选择它,并通过边框显示选定内容(就像屏幕截图中的顶部选定项)。代码在除“ShortLabel”右侧的空白处外的所有位置都可以工作。 - Isaac Baker
不知道你可以使用Snoop来查看事件! - Contango
1个回答

5
如果您将标签的水平对齐方式从“左”更改为“拉伸”,这将解决问题并保持视觉格式不变。
MouseDown事件仅在元素存在的区域起作用。通过将标签设置为“左”对齐,您创建了您提到的“空白”,在该水平位置上不存在可单击的元素。为了直观地看到差异,请尝试暂时设置给您带来问题的标签元素的背景属性,您会发现该元素无法完全延伸到文本框。

太好了!这解决了我项目中长期存在的一个问题。 - Contango
非常简单。谢谢!我想ListBoxItem在这种情况下会得到MouseDown事件,因为它是空的。再次感谢! - Isaac Baker
有没有想法为什么 ListBoxItem 没有接收到事件?我觉得这是一个好的解决方案,但它并没有解释为什么这个事件似乎在 ScrollViewer 处停止了。 - Daniel Johnson
进一步回应 @DanielJohnson 的评论,如果我从 ListBoxItem 中删除 ContentTemplate,同时保留 Label 的水平对齐方式为“Left”,那么 Border 会获取事件,而不是 ScrollViewer 并且能够正确选择 ListBoxItem。WPF 发生了什么? - Isaac Baker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接