【发布时间】:2017-11-06 04:54:27
【问题描述】:
我正在尝试使 WPF 列表框复制旧 Winforms CheckedListBox 的行为,或者在例如AnkhSVN。我看过一些示例,展示了如何使用 DataTemplate 为每次创建一个复选框(例如 Wpf CheckedListbox - how to get selected item),但与 winforms 控件相比,这感觉非常笨拙:
- 默认不存在“如果用户更改检查状态,请确保所有选定项的检查状态更改”的逻辑。
- 将项目从选中更改为未选中的点击区域是框/和/标题,而不仅仅是 Winforms 中的框
我可以通过在绑定集合中的每个项目上为 PropertyChanged 事件添加一个侦听器来处理第一个问题,如果 IsChecked 发生变化,则将 IsChecked 设置为所有当前选定项目的相同值。
但是,我找不到第二个问题的好的解决方案。通过将 DataTemplate 拆分为没有标题的 Checkbox 和带有标题的 TextBlock,我可以减少点击区域以将检查状态更改为仅所需的正方形。但是,击中 TextBlock 的所有鼠标交互都不执行任何操作 - 我希望它的行为与在普通列表框中或在 Textblock 外部的死区中的行为相同:如果用户正在按住 shift,则选择所有内容,包括此项目,如果没有,则清除选择并仅选择此项目。我可以尝试实现一些我在 TextBlock 上处理 Mouse* 事件的方法,但这似乎很脆弱且不优雅——我会尝试重新创建 ListBox 的确切行为,而不是将事件传递给列表框。
这是我目前得到的:
XAML:
<ListBox x:Name="_lstReceivers" SelectionMode="Extended" Margin="10,41,6,15"
ItemsSource="{Binding Receivers}">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}" IsHitTestVisible="True"/>
<TextBlock Text="{Binding Item}" Background="{x:Null}" IsHitTestVisible="False"/><!--Attempt to make it pass mouse events through. Doesn't work. Yuk.-->
</StackPanel>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
获取“同时更改所有检查”逻辑的代码(为清楚起见删除了一些错误处理):
private void ListBoxItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var item = sender as CheckableItem<Receiver>;
if (item == null)
return;
if (e.PropertyName == nameof(CheckableItem<Receiver>.IsChecked))
{
bool newVal = item.IsChecked;
foreach (CheckableItem<Receiver> changeItem in _lstReceivers.SelectedItems)
{
changeItem.IsChecked = newVal;
}
}
}
通过尝试 Background = "{x:Null}" 和 IsHitTestVisible="False" 的各种组合,我确实设法让整个项目不响应鼠标点击事件 - 但我不能让它只有复选框响应鼠标事件,而其他所有内容都传递给 ListBox 以进行正确的选择处理。
任何帮助将不胜感激。
【问题讨论】:
-
没有一个好的minimal reproducible example,试图让你的代码工作是不切实际的。但是,我认为如果您根本不弄乱
IsHitTestVisible属性,它应该可以正常工作。顺便说一句,RadioButton开箱即用。你不需要你写的代码隐藏。只需确保要组合在一起的所有RadioButton元素都具有相同的GroupName值。 -
您有如何使 RadioButton 工作的示例吗?因为如果我用单选按钮替换我的 StackPanel,我会得到一个完整的单选按钮列表,这些单选按钮不响应任何内容。但主要问题是单选按钮仍然对其文本上的鼠标事件不透明 - 它们拦截点击,而不是让 ListBox 处理它们。这是我不知道如何解决的主要问题,正如我的帖子的标题和文字所示。