Binding RadioButtons可从ListBox中显示的集合中选择一项

本文关键字:一项 选择 可从 RadioButtons ListBox 显示 Binding 集合 | 更新日期: 2023-09-27 17:57:33

我的模型中有一个ObservableCollection,显示在视图中的ListBox中。每个ListBoxItem都显示一个单选按钮,该按钮应允许用户选择其中一个项目。ViewModel的属性应通过保留对所选项的引用来记录此选择。

如何设置双向绑定来执行此操作?

IValueConverter应该允许我将RadioButton.IsChecked绑定到VM属性,其中发生单选按钮的实际项目作为参数或IMultiValueConverter中的值传递给转换器。我可以这样做:

  1. 基于VM属性与单选按钮关联的项目的比较,为Convert()返回true/false
  2. 如果为IsChecked==true,则返回该项;如果为ConvertBack(),则返回Binding.DoNothing

但是,ValueConverter参数不能绑定到,因为它们不是依赖属性(因此我不能绑定到要用作ValueConverter参数的项),并且我不能使用MultiConverter,因为尽管Convert()将接收两个感兴趣的值,但ConvertBack()将只接收IsChecked的值。

票据

  1. 内置的ListBox选择机制已用于其他目的
  2. 感兴趣的集合嵌套在另一个集合中,并显示在包含的ListBox中
  3. ListBox绑定到模型中的集合。出于显而易见的原因,我希望不要在Model集合中实现告诉VM如何在View中记录事件的事件

Binding RadioButtons可从ListBox中显示的集合中选择一项

我设法解决了这个问题:

  1. ItemsPanel的资源节点上包括一个转换器,它封装每个ListBoxItem(或树的重复部分中的其他地方),因此每个项有一个转换器实例
  2. 为每个转换器所连接的项目向转换器添加一个属性(在我的示例中为Host),并在创建每个ListBoxItem时以某种方式初始化它
  3. IsChecked绑定到需要使用转换器填充的ViewModel属性

*我尝试将Host属性作为绑定到DataContext的DP(它应该是ListBox在转换器所在点绑定到的集合的一个成员),但我根本无法将其用于我的嵌套ListBoxes。我求助于containing元素的Initialized事件和一些代码隐藏(这确实允许Host恢复为普通属性;DP是多余的,但对于绑定来说是必要的)。

DataTemplate:

<StackPanel Initialized="StackPanel_Initialized">
    <StackPanel.Resources>
        <!-- ExlcusionRadioConverter.Host is initialised in code behind -->
        <local:ExclusionRadioConverter x:Key="ExclusionRadio" />
    </StackPanel.Resources>
    <RadioButton
        GroupName="Exclusion"
        IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}, Converter={StaticResource ExclusionRadio}, Path=DataContext.ExclusionCriterion}" />
    <Label Content="{Binding Description}" />
</StackPanel>

Panel Initialized事件(NB此答案最初在Loaded事件处理程序中有此代码,但这导致了一些问题):

private void StackPanel_Initialized(object sender, EventArgs e)
{
    StackPanel panel = (StackPanel)sender;
    ExclusionRadioConverter converter = (ExclusionRadioConverter)panel.FindResource("ExclusionRadio");
    converter.Host = panel.DataContext as OptionListMember;
}

转换器:

[ValueConversion(typeof(object), typeof(bool))]
public class ExclusionRadioConverter : IValueConverter
{
    public OptionListMember Host { get; set; }
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ReferenceEquals(value, Host);
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((bool)value) ? Host : Binding.DoNothing;
    }
}