当绑定到CompositeCollection时,ComboBox未选择正确的项目

4
我有一个绑定到动物集合的ComboBox。我从中选择我的最爱动物。我需要在绑定的项上方添加一个静态的null项。我使用CompositeCollection声明它。当ComboBox绑定时,它不能选择我的初始最爱动物。如何解决这个问题?类似的问题可以在这里找到,但仍未解决。
观察结果:
  • 绑定到静态项是有效的,即如果我没有最喜欢的动物,静态项将被选中。
  • 如果删除静态项,则该问题消失。当然,这将使CompositeCollection和整个问题都变得无用。
我已经采取了以下措施:
  • 此处所述,CollectionContainer无法直接绑定到属性。
  • 此处建议,复合集合也已移至静态资源。
以下是演示此问题的完整C#代码和XAML:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication1
{
    public class Animal
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Zoo
    {
        private IEnumerable<Animal> _animals = new Animal[]
        {
            new Animal() { Id = 1, Name = "Tom" },
            new Animal() { Id = 2, Name = "Jerry" }
        };

        public Zoo(int initialId)
        {
            FavouriteId = initialId;
        }

        public int FavouriteId { get; set; }
        public IEnumerable<Animal> Animals { get { return _animals; } }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void BindComboBox(object sender, RoutedEventArgs e)
        {
            // Selecting the static item by default works.
            //DataContext = new Zoo(-1);

            // Selecting "Jerry" by default does not work.
            DataContext = new Zoo(2);
        }
    }
}

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">

    <Window.Resources>
        <CollectionViewSource x:Key="AnimalsBridge" Source="{Binding Path=Animals}" />

        <CompositeCollection x:Key="AnimalsWithNullItem">
            <local:Animal Id="-1" Name="Pick someone..."/>
            <CollectionContainer Collection="{Binding Source={StaticResource AnimalsBridge}}" />
        </CompositeCollection>
    </Window.Resources>

    <StackPanel>
        <Button Content="Bind" Click="BindComboBox"/>

        <ComboBox x:Name="cmbFavourite"
            SelectedValue="{Binding Path=FavouriteId}"
            SelectedValuePath="Id" DisplayMemberPath="Name"
            ItemsSource="{StaticResource AnimalsWithNullItem}"/>
    </StackPanel>
</Window>
1个回答

4
我没有解决你问题的方法,但我可以提供一个替代方案。我个人会为每个视图创建专门的视图模型。然后,在视图模型上添加属性以添加所需的空值。我更喜欢这种方法,因为它可以更好地测试我的视图模型。
对于你的例子,请添加:
public class ZooViewModel
{
    .....


    public IEnumerable<Animal> Animals { get { return _animals; } }
    public IEnumerable<Animal> AnimalsWithNull { get { return _animals.WithDefault(new Animal() { Id = -1, Name = "Please select one" }); } }
}

神奇的组件

public static class EnumerableExtend {

    public static IEnumerable<T> WithDefault<T>(this IEnumerable<T> enumerable,T defaultValue) {
        yield return defaultValue;
        foreach (var value in enumerable) {
            yield return value;     
        }
    }
}

然后在您的XAML中,只需绑定到
ComboBox x:Name="cmbFavourite"
        SelectedValue="{Binding Path=FavouriteId}"
        SelectedValuePath="Id" DisplayMemberPath="Name"
        ItemsSource="{Binding AnimalsWithNull }"/>

现在,您正在直接绑定到源,并可以像平常一样控制绑定。请注意,因为我们使用了“yield”,所以我们没有创建新的枚举,而只是遍历现有的列表。


+1 用于黑魔法的 yield。但是,我仍然需要使用转换器才能将 ListViewItem 的属性正确地设置为 ComboBox 的选定值。 - helloserve
将其标记为答案,因为似乎不存在解决方案。 也可以通过内置方法高效地在前面添加项:new[] { new Animal() { ... } }.Concat(_animals) - idilov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接