【问题标题】:How to data-bind to a property of a composite object in a collection?如何将数据绑定到集合中复合对象的属性?
【发布时间】:2014-04-06 04:36:49
【问题描述】:

我需要允许从这个预定义列表中选择几个项目:

public enum QuarkType{
    Up,
    Down,
    [Description("Magical Being")] Charm,
    [Description("Quite Odd")] Strange,
    Top,
    Bottom
}

所以我使用CheckComboBox,并在需要使用自定义描述的地方使用DescriptionAttribute。我使用MarkupExtension 提供CheckComboBox,它返回给定enum 的所有值的列表作为IEnumerable<EnumDescriptionPair>,其中EnumDescriptionPair 是:

public class EnumDescriptionPair{
    public object Value { get; set; }
    public string Description { get; set; }
}

现在的问题是如何将这个列表的Values 传递给代码隐藏列表:

public ObservableCollection<QuarkType> SelectedQuarksList { get; set; }

我的意思是,对于所选列表的每个项目,如何从 EnumDescriptionPair 中只取出 Value

这是我迄今为止所拥有的。它显然不起作用(意味着它在CheckComboBox 中显示正确的字符串,并允许选择多个项目,但没有反映在上面提到的SelectedQuarksList 中):

<Window x:Class="MyEditor.MainWindow"
        xmlns:loc="clr-namespace:MyEditor"
        xmlns:toolKit="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">

    <StackPanel>
        <toolKit:CheckComboBox x:Name="Ccb" Delimiter=","
                               ItemsSource="{loc:EnumItemsValueConverter {x:Type loc:QuarkType}}"
                               DisplayMemberPath="Description"
                               SelectedItemsOverride="{Binding SelectedQuarksList}" />

        <ListBox ItemsSource="{Binding SelectedQuarksList}" />
    </StackPanel>
</Window>

【问题讨论】:

  • 既然列表是预定义的,那么需要绑定复选框列表吗?我之前使用 XAML 中声明的所有选项并绑定到枚举,但不是您描述的方式。 +1 提出一个很好的问题。
  • @LordTakkera - 我不确定我是否理解你的建议,但我愿意接受建议
  • 我试图解释我的建议在我的回答中,希望它们对你有用。
  • @LordTakkera - 我不能使用你的答案,因为 enum 可能会发生变化 - 整个想法是我们可以经常更改它

标签: c# wpf data-binding wpftoolkit


【解决方案1】:

要完全按照您的问题进行操作,您可以尝试在 SelectedQuarksList 绑定上使用转换器,该转换器在 ConvertBack 函数中执行“.Select(q => q.Value)”。

为了获得你想要的行为,我过去已经成功地做到了这一点(例如你的 2 个值),这将枚举设置为“标志”,因此值序列变为 0、1、2、4.. .:

<StackPanel Orientation="Horizontal">
<Checkbox Content="Up" IsChecked="{Binding Path=SelectedQuarksFlags, Converter={Static Resource HasFlagToBoolConverter}, ConverterParamater={x:Static Quarks.Up}}"
<Checkbox Content="Magical Being" IsChecked="{Binding Path=SelectedQuarksFlags, Converter={Static Resource HasFlagToBoolConverter}, ConverterParamater={x:Static Quarks.Charm}}"
</StackPanel>

转换器看起来像:

 Quark _lastSeenValue;
 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Quark paramQuark = (Quark)parameter;
        Quark currentQuark = (Quark)value;

        _lastSeenValue = currentQuark;
        return currentQuark.HasFlag(paramQuark);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Quark newQuark = _lastSeenValue;
        Quark paramQuark = (Quark)parameter;

        if ((bool)value)
        {
            newQuark |= paramQuark; 
        }
        else
        {
            newQuark &= ~paramQuark;
        }

        _lastSeenValue = newQuark;
        return newQuark;
    }

这可以相对容易地转换为从列表中添加或删除,但我知道上面的代码有效。

【讨论】:

  • 您上面的XAML 代码应该进入CheckComboBox.ItemTemplate 标签?
  • 但现在我想我理解了你对我的问题的评论......那么答案是这个enum 是定义上的瞬态 - 整个想法是我们将能够改变它以后不用改代码
  • 不,您在我的 XAML 示例中没有项目模板,看起来您已经明白了。就更改而言,除非它是数据驱动的,否则无论如何您都将更改代码:)。也就是说,您是否尝试过使用带有 .Select 的转换器?