带单选按钮的 RadioListBox(WPF 版本)






4.64/5 (7投票s)
如何实现一个带有单选按钮而不是标准选择高亮的模板化列表框。
|
|
引言
这是我之前文章的 WPF 版本:CRadioListBox:一个带单选按钮的列表框 (MFC 版本) 和 RadioListBox:一个带单选按钮的列表框 (WinForms 版本)。正如那些文章所解释的,RadioListBox
具有与常规 ListBox
相同的功能,但外观和感觉不同。无论如何,RadioListBox
控件提供了一些优势
- 使用单选按钮可以更清楚地表明选项是互斥的。
- 它是单选按钮组的良好替代方案,因为您只需要维护一个控件,从而减少内存使用。
- 它继承了一些有用的功能,如滚动、排序、数据绑定和多列。
- 动态更改选项将更容易,如演示应用程序所示。
- 管理选择事件也将更容易,同样在演示应用程序中显示。
Using the Code
要在您的项目中实现 RadioListBox
,您只需要执行几个步骤
- 将 RadioListBox.xaml 和 RadioListBox.xaml.cs 包含到您的项目中。
- 将一个
RadioListBox
对象放入您的 XAML 窗体中,或手动操作。System.Windows.Controls.Custom
命名空间的别名将很有用。 - 更改控件的标准属性,就像对于
ListBox
一样。 - 使用
IsTransparent
属性来模仿一组RadioButton
。
就这样!现在您可以将单选按钮集合用作常规 ListBox
。您可以使用 Items.Add()
方法、ItemsSource
属性,或直接在 XAML 中添加项目。最后,使用 SelectedIndex
属性查询用户选择。不再需要逐个评估。
RadioListBox 内部
RadioListBox
类派生自 WPF 的 ListBox
类,带有一个自定义的 ControlTemplate
,用于删除所有不需要的 ListBox 功能,如所选项目的背景。为了与单选按钮模型保持一致,已禁用多选。 摘要 XAML 实现如下所示
<ListBox x:Class="System.Windows.Controls.Custom.RadioListBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib" >
<ListBox.Resources>
<Style x:Key="{x:Type ListBoxItem}" TargetType="ListBoxItem">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<RadioButton x:Name="radio" Click="ItemRadioClick">
<RadioButton.Content>
<ContentPresenter ... />
</RadioButton.Content>
</RadioButton>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.Template>
<ControlTemplate>
<Border BorderThickness="0"
Padding="1,1,1,1"
Background="Transparent"
Name="theBorder"
SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}"
Focusable="False">
<ItemsPresenter
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers ... />
</ControlTemplate>
</ListBox.Template>
</ListBox>
由于 ControlTemplate
内部的单选按钮不会更改选择,因此必须在 ItemRadioClick
事件内部手动完成。在这里,ItemContainerGenerator
属性通过在 ListBox
的项目内容和 ListBoxItem
呈现对象之间进行转换而扮演重要角色。以下是简要的 C# 源代码
namespace System.Windows.Controls.Custom
{
public partial class RadioListBox : ListBox
{
public RadioListBox() { ... }
public new SelectionMode SelectionMode { ... }
public bool IsTransparent { ... }
private void ItemRadioClick(object sender, RoutedEventArgs e)
{
ListBoxItem sel = (e.Source as RadioButton).TemplatedParent as ListBoxItem;
int newIndex = this.ItemContainerGenerator.IndexFromContainer(sel); ;
this.SelectedIndex = newIndex;
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
CheckRadioButtons(e.RemovedItems, false);
CheckRadioButtons(e.AddedItems, true);
}
private void CheckRadioButtons(System.Collections.IList radioButtons, bool isChecked)
{
foreach (object item in radioButtons)
{
ListBoxItem lbi =
this.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
if (lbi != null)
{
RadioButton radio = lbi.Template.FindName("radio", lbi) as RadioButton;
if (radio != null)
radio.IsChecked = isChecked;
}
}
}
}
}
历史
- 2009年9月6日:第一个版本。