WPF中的数据绑定单选按钮列表

Sco*_* O. 18 wpf databound radio-button

我有一个数据对象的选项列表,我想使用一个单选按钮列表,以允许用户选择一个,只有一个.功能类似于数据绑定组合框,但采用单选按钮格式.

愚蠢的我,我以为这将是内置的,但没有.你怎么做呢?

Sco*_* O. 30

基本上,在查看谷歌搜索结果之后,我开始使用MSDN讨论主题中的信息,其中WPF博士提供了一个答案,其中讨论了将ListBox设置为正确的样式.然而,当列表框被禁用时,背景是一个讨厌的颜色,我无法得到我的生活摆脱,直到我读列表框控件模板的MSDN例子,这表明了踢我的后台秘密Border元素屁股.

所以,这里的最终答案是这种风格:

<Style x:Key="RadioButtonList" TargetType="{x:Type ListBox}">
    <!-- ControlTemplate taken from MSDN http://msdn.microsoft.com/en-us/library/ms754242.aspx -->
    <Setter Property="SnapsToDevicePixels" Value="true"/>
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="MinWidth" Value="120"/>
    <Setter Property="MinHeight" Value="95"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBox">
                <Border Name="Border" Background="Transparent"
                        BorderBrush="Transparent"
                        BorderThickness="0"
                        CornerRadius="2">
                    <ScrollViewer Margin="0" Focusable="false">
                        <StackPanel Margin="2" IsItemsHost="True" />
                    </ScrollViewer>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter TargetName="Border" Property="Background"
                                Value="Transparent" />
                        <Setter TargetName="Border" Property="BorderBrush"
                                Value="Transparent" />
                    </Trigger>
                    <Trigger Property="IsGrouping" Value="true">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}" >
                <Setter Property="Margin" Value="2" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <Border Name="theBorder" Background="Transparent">
                                <RadioButton Focusable="False" IsHitTestVisible="False"
                                             IsChecked="{TemplateBinding IsSelected}">
                                    <ContentPresenter />
                                </RadioButton>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)

它为ListBox和Items提供了ControlTemplate和样式.它被这样使用:

<ListBox Grid.Column="1" Grid.Row="0" x:Name="TurnChargeBasedOnSelector" Background="Transparent"
    IsEnabled="{Binding Path=IsEditing}"
    Style="{StaticResource RadioButtonList}"
    ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MainForm}}, Path=DataContext.RampTurnsBasedOnList}"
    DisplayMemberPath="Description" SelectedValuePath="RampTurnsBasedOnID"
    SelectedValue="{Binding Path=RampTurnsBasedOnID, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"/>
Run Code Online (Sandbox Code Playgroud)

我花在WPF上的时间越多,我就越认为它使得琐碎的疯狂困难和疯狂的琐事.请享用.斯科特

  • 对于WPF的评论+1会使琐碎的问题变得困难,反之亦然.我认为我们在这里遇到了一些严重的早期采用者问题.来自另一个讨论的这篇文章有一个非常好的解决方案来绑定到枚举.它可以很好地解决这个问题:<http://stackoverflow.com/questions/58743/databinding-an-enum-property-to-a-combobox-in-wpf/98464#98464> (7认同)
  • @PaulPrewett nope - 那些问题仍然存在;-) (2认同)

小智 15

将列表框绑定到ListBox的ItemsSource,其中包含具有属性Name的对象列表(这可以更改)

<ListBox Name="RadioButtonList">
   <ListBox.ItemTemplate >
        <DataTemplate >
             <RadioButton GroupName="radioList" Tag="{Binding}" Content="{Binding Name}"/>
         </DataTemplate>
                                                    </ListBox.ItemTemplate>
                                                </ListBox>
Run Code Online (Sandbox Code Playgroud)

重要的GroupName ="radioList"


小智 8

超级简单,MVVM友好,利用DataTemplates进行类型化.XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">

<Window.Resources>
    <DataTemplate DataType="{x:Type local:Option}">
        <RadioButton Focusable="False"
                IsHitTestVisible="False"
                Content="{Binding Display}"
                IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}">
        </RadioButton>
    </DataTemplate>
</Window.Resources>

<Grid>
    <ListBox ItemsSource="{Binding Options}" SelectedItem="{Binding SelectedOption}"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)

查看模型等:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new Vm();
    }
}

public class Vm
{
    public Option[] Options { get { return new Option[] { 
        new Option() { Display = "A" }, 
        new Option() { Display = "B" }, 
        new Option() { Display = "C" } }; } }
    public Option SelectedOption { get; set; }
}

public class Option
{
    public string Display { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如果将选项包装到特定类型(或者可能已经存在).您只需为该类型设置DataTemplate,WPF将自动使用它.(在ListBox资源中定义DataTemplate以限制将应用DataTemplate的范围).

如果需要,还可以在DataTemplate中使用组名来设置组.

这比更改控件模板简单得多,但它确实意味着您在所选项目上获得蓝线.(再一次,没有一点造型无法修复).

当你知道如何时,WPF很简单.


Ant*_*ien 7

我通过将a ValueConverter转换enum为a来完成此操作bool.通过传递单选按钮表示的枚举值,ConverterParameter转换器将返回是否应检查此单选按钮.

<Window.Resources>
    <Converters:EnumConverter x:Key="EnumConverter" />
</Window.Resources>

<RadioButton IsChecked="{Binding Path=MyEnum, Mode=TwoWay, 
                                 Converter={StaticResource EnumConverter}, 
                                 ConverterParameter=Enum1}"}
             Content="Enum 1" />
<RadioButton IsChecked="{Binding Path=MyEnum, Mode=TwoWay, 
                                 Converter={StaticResource EnumConverter}, 
                                 ConverterParameter=Enum2}"}
             Content="Enum 2" />
Run Code Online (Sandbox Code Playgroud)

EnumConverter 定义如下:

public class EnumConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType.IsAssignableFrom(typeof(Boolean)) && targetType.IsAssignableFrom(typeof(String)))
                throw new ArgumentException("EnumConverter can only convert to boolean or string.");
            if (targetType == typeof(String))
                return value.ToString();

            return String.Compare(value.ToString(), (String)parameter, StringComparison.InvariantCultureIgnoreCase) == 0;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType.IsAssignableFrom(typeof(Boolean)) && targetType.IsAssignableFrom(typeof(String)))
                throw new ArgumentException("EnumConverter can only convert back value from a string or a boolean.");
            if (!targetType.IsEnum)
                throw new ArgumentException("EnumConverter can only convert value to an Enum Type.");

            if (value.GetType() == typeof(String))
            {
                return Enum.Parse(targetType, (String)value, true);
            }

            //We have a boolean, as for binding to a checkbox. we use parameter
            if ((Boolean)value)
                return Enum.Parse(targetType, (String)parameter, true);

            return null;
        }
    }
Run Code Online (Sandbox Code Playgroud)

请注意,我没有数据绑定到枚举列表以生成单选按钮,我已经手动完成了它们.如果你想通过绑定填充单选按钮列表,我认为你需要将IsChecked绑定更改为绑定到MultiBinding当前值和无线电的枚举值的绑定,因为你不能使用绑定ConverterParameter.