【问题标题】:Combobox binding itemsource to custom list and selecteditem to an instance of that list doesn't work组合框将 itemsource 绑定到自定义列表并将 selecteditem 绑定到该列表的实例不起作用
【发布时间】:2014-01-05 21:54:05
【问题描述】:

我尝试了很多不同的方法来让我的组合框工作,但我仍然卡住了:(

这是我的应用程序的一个非常简化的版本:(刚刚编辑,有错误请见谅)

<ListView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson}"/>
<ComboBox ItemsSource="{Binding Grades}" SelectedItem="{Binding SelectedPerson.MyGrade}" 
     DisplayMemberPath="Name"/>

以及后面的代码:

public class Person
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }

    private Grade myGrade;
    public Grade MyGrade
    {
        get { return myGrade; }
        set
        {
            if (myGrade != value)
            {
                myGrade = value;
                NotifyPropertyChanged("MyGrade");
            }
        }

    }

    //-- INotifyPropertyChanged implementation
}
public class Grade
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }

    private int prop;
    public int Prop
    {
        get { return prop; }
        set
        {
            if (prop != value)
            {
                prop = value;
                NotifyPropertyChanged("Prop");
            }
        }

    }

    //-- INotifyPropertyChanged implementation
}
public partial class MainWindow : Window
{
    public ObservableCollection<Person> People { get; set; }
    public ObservableCollection<Grade> Grades { get; set; }

    private Person selectedPerson;
    public Person SelectedPerson
    {
        get { return selectedPerson; }
        set
        {
            if (selectedPerson != value)
            {
                selectedPerson = value;
                NotifyPropertyChanged("SelectedPerson");
            }
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;

        People = new ObservableCollection<Person>();
        Grades = new ObservableCollection<Grade>();

        Grades.Add(new Grade() { Name = "Grade 1", Prop = 1 });
        Grades.Add(new Grade() { Name = "Grade 2", Prop = 2 });

        People.Add(new Person() { Name = "guy 1", MyGrade = Grades[0] });
        People.Add(new Person() { Name = "guy 2", MyGrade = Grades[0] });
        People.Add(new Person() { Name = "guy 3", MyGrade = Grades[1] });
    }

    //-- INotifyPropertyChanged implementation
}

问题是当我在列表视图中选择一个项目时,组合框仍然是空的。 itemsource 没问题(如果我点击组合框,我可以看到“grade 1”和“grade 2”)。 我认为缺少一些东西可以告诉“Person.GradeGrades 列表的一部分”,但我找不到什么。

希望你能帮助我;)

【问题讨论】:

  • SelectedItem 在内存中的引用是否与ItemsSource 中的项目完全相同?默认情况下,WPF 将通过引用比较项目,所以这可能是您的问题。如果它们不同,我建议使用SelectedValue 或可能覆盖.Equals()。有关示例,请参见 here :)
  • 我认为问题来自类似的东西,我不认为 selecteditem 和 itemssource 来自相同的参考。我今晚会测试一下,让你知道;)
  • 真的非常感谢!! equals 覆盖方法救了我 :) :)
  • 很高兴为您解决问题 :) 我将其发布为下面的答案,以防其他人正在寻求解决同样的问题

标签: c# wpf data-binding combobox selecteditem


【解决方案1】:

SelectedItem 在内存中的引用是否与ItemsSource 中的项目完全相同?

默认情况下,WPF 会将SelectedItemItemsSource 中的项通过引用进行比较,如果它们在内存中不是同一个引用,它将不返回匹配项。

如果您无法在代码中执行此操作,最常见的解决方法是:

  • SelectedValue绑定到值类型而不是引用类型,并设置SelectedValuePath

    <ComboBox ItemsSource="{Binding Grades}" 
              SelectedValue="{Binding SelectedPerson.MyGrade.GradeId}" 
              SelectedValuePath="GradeId"
              DisplayMemberPath="Name"/>
    
  • 或覆盖.Equals() 以确保两个对象在特定属性匹配时被视为相等,而不是在内存中的引用匹配时被视为相等。

    public override bool Equals(object obj) 
    { 
        if (obj == null || !(obj is Grade)) 
            return false; 
    
        return ((Grade)obj).GradeId == this.GradeId); 
    }
    

【讨论】:

    【解决方案2】:

    请首先确保您没有绑定错误。您可以通过在 Visual Studio 中打开输出窗口来验证这一点,并检查是否有与绑定表达式相关的错误消息。

    您应该能够轻松发现这些,因为错误消息将包含以下文本:BindingExpression 路径错误

    作为一种替代方法,您为什么不尝试将 ComboBox 选定项直接与 ListView 中的选定项绑定。

    以下是如何实现这一目标的示例 sn-p:

    <ListView
        x:Name="listView"
        ItemsSource="{Binding People}"
        DisplayMemberPath="Name" />
    <ComboBox 
        ItemsSource="{Binding Grades}" 
        SelectedItem="{Binding SelectedItem.MyGrade, ElementName=listView}" 
        DisplayMemberPath="Name"/>
    

    【讨论】:

    • 感谢您的回答,但我没有绑定错误。没看到直接绑定listview项的意义oO?
    • 上一个回复是尝试完全绕过该属性,并检查从列表视图中选择项目时组合框是否会更新。如果是这种情况,那么视图模型中就会出现问题。我设法使用提供的代码复制了您的场景。您从类定义中省略了接口 INotifyPropertyChanged。我不知道你是否为了简洁而省略了这些,但如果这些被删除,你会得到你的确切问题。
    • 改变你的类定义如下:public class Person : INotifyPropertyChangedpublic class Grade : INotifyPropertyChangedpublic partial class MainWindow : Window, INotifyPropertyChanged
    【解决方案3】:

    有几件事,首先您绑定到Grade,您的属性称为MyGrade。其次,您在Grades 列表中为等级实例化不同的对象,并使用不同的对象分配给每个人,如果您希望它们正确映射,您希望使用相同的对象,如下所示:

    Grades.Add(new Grade() { Name = "Grade 1", Prop = 1 });
    Grades.Add(new Grade() { Name = "Grade 2", Prop = 2 });
    
    People.Add(new Person() { Name = "guy 1", MyGrade = Grades[0] });
    People.Add(new Person() { Name = "guy 2", MyGrade = Grades[0] });
    People.Add(new Person() { Name = "guy 3", MyGrade = Grades[1] });
    

    最后,如果要将 Grades 集合绑定到 UI,您可能还希望将其设为 ObservableCollection。此外,您的RaisePropertyChanged 没有包含该属性的名称似乎有点奇怪。

    可能还有其他错误,但这就是我马上想到的。

    【讨论】:

    • 是的,您希望Grades(在MainWindow 中成为ObservableCollection)。此外,您还需要为此引发 INotifyPropertyChanged 事件。 Grades 属性 正在 被设置,但没有通知绑定寻找新集合。
    • 感谢您的错误 :) 我写的“简化应用程序”太快了……不幸的是,问题仍然存在。我将使用更正编辑我的帖子
    猜你喜欢
    • 1970-01-01
    • 2014-03-16
    • 2011-02-16
    • 2015-07-23
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    相关资源
    最近更新 更多