【问题标题】:MVVM ComboBox SelectedIndex vs. SelectedItemMVVM ComboBox SelectedIndex 与 SelectedItem
【发布时间】:2016-09-25 02:12:12
【问题描述】:

我试图让多个 ComboBoxes 填充来自特定记录的数据。我可以让其中一个正常工作,但我认为一个概念错误正在阻止我让第二个正常工作。我已经在各种线程中搜索了 SelectedItem、SelectedValue 和 SelectedIndex,并尝试在提供的指导之后修改我的代码。显然我做错了什么,但不确定是什么。我是一个新手,我所学到的一切都是从互联网上自学的。

我正在使用 Entity Framework 6 Database First 数据模型。我有一个表(Master),它有一个外键链接到 Shift 和另一个用于 Personnel 表。 Shift 表具有 ShiftId (PK) 字段,其 Identity 设置为 true,而 Shift 字段只是一个字符串。 Personnel 表的 PersonnelId (PK) 的 Identity 设置为 false(我从其他地方手动填充 ID)以及名字和姓氏字段。

我的项目所需的流程是:1) 获取当前记录,2) 填充 Shift ComboBox,3) 显示与当前记录关联的班次,4) 填充 Personnel ComboBox,5) 显示与当前记录,6) 保存对记录的任何更改(通过为任一组合框选择不同的值来建立更改)。

我的 ViewModel 正在使用 INotifyPropertyChanged,我认为我已经正确地实现了这一点,因为 Shift ComboBox 可以正常工作。

1) 获得所需的记录工作正常。然后将其存储为“CurrentRecord”

2) 填充 Shift ComboBox 可以正常工作。
在我的模型中,我有:

    private ICollection<Gen_All_Shift> shiftList;
    public ICollection<Gen_All_Shift> GetShiftList()
    {
        shiftList = context.Gen_All_Shift.OrderBy(p => p.ShiftId)
                                             .ToArray();
        return shiftList;
    }

在我的 ViewModel 中,我有:

    public ICollection<Gen_All_Shift> ShiftList
    {
        get { return context.GetShiftList(); }
    }

    private Gen_All_Shift selectedShift;
    public Gen_All_Shift SelectedShift
    {
        get { return selectedShift; }
        set
        {
            if (value != selectedShift)
            {
                selectedShift = value;
                NotifyPropertyChanged("SelectedShift");
            }
        }
    }

那么XAML就是:

        <ComboBox x:Name="cboShift" 
             ItemsSource="{Binding ShiftList}"
             DisplayMemberPath="Shift"
             SelectedIndex="{Binding CurrentRecord.ShiftIdFk,
                             UpdateSourceTrigger=PropertyChanged}" />

3) 显示当前班次只要我绑定了 SelectedIndex。如果我使用 SelectedItem 或 SelectedValue,当屏幕加载时 ComboBox 是空白的。 (我也尝试绑定到 SelectedShift.ShiftId 但这并没有给我想要的结果。) SelectedIndex 将允许我更改选择并允许我正确地将更改保存到实际数据库。我不确定我做错了什么会阻止 SelectedItem 或 SelectedValue 工作。不理解这是导致我对人员组合框有疑问的原因。

4) 填充 Personnel ComboBox 有效。

在我的模型中,我有:

    private ICollection<Personnel_All_PersonnelList> personnelList;
    public ICollection<Personnel_All_PersonnelList> GetPersonnelList()
    {            
            personnelList = context.Personnel_All_PersonnelList.Where(p=>p.Active == true)
                                                               .OrderBy(p => p.LastName)
                                                               .ThenBy(p => p.FirstName)
                                                               .ToArray();
            return personnelList;
    }

在我的 ViewModel 中,我有:

    public ICollection<Personnel_All_PersonnelList> PersonnelList
    {
        get
        {
                return context.GetPersonnelList();
        }
    }

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

然后在我的 XAML 我有:

    <ComboBox x:Name="cboTechnician" 
             ItemsSource="{Binding PersonnelList}"
             DisplayMemberPath="LastName"
             SelectedIndex="{Binding CurrentRecord.PersonnelIdFk,
                             UpdateSourceTrigger=PropertyChanged}" />

5) 无论我尝试哪种方式(SelectedIndex、SelectedItem、SelectedValue),都无法显示当前人员。我猜 SelectedIndex 不能像 shift 那样工作的原因是因为索引号没有与 PersonnelId 正确对齐,所以系统不知道实际选择了哪个。

6) 如果我仅更改 Shift,则保存对记录的更改有效。如果我在人员组合框中选择一个人并尝试保存,我会收到系统空异常。我认为这是由阻止 SelectedIndex 使用人员组合框的同一问题引起的。

我想如果有人能指出正确的方向,说明为什么我无法使与 SelectedItem 的绑定正常工作,我将能够弄清楚如何修复 Personnel ComboBox。

【问题讨论】:

    标签: c# wpf mvvm combobox


    【解决方案1】:

    您尝试的第一件事实际上是正确的,但是有几件事让您失望。

    例如:

    get { return context.GetShiftList(); }
    

    通常,这不是一个好主意。任何调用此属性的人都会每次调用数据库调用,这会损害性能并且根本不需要。

    一个更好的主意是调用一个方法来加载 ShiftList 属性,例如:

    public void ReloadShiftList()
    {
        //TODO: Your logic here
    
        ShiftList = ...
    }
    

    注意:请务必在您的 ShiftList 属性上实现 INotifyPropertyChanged,以便在此属性更改时更新视图。

    对于您的ComboBox,绑定到SelectedItem 肯定是首选方法。首次加载时所选项目为 blank 的原因是 SelectedShift 设置为 null。要解决此问题,您只需在加载 ShiftList 后设置 SelectedShift

    ShiftList = ...
    SelectedShift = ShiftList.FirstOrDefault();
    

    通过将SelectedShift 设置为ShiftList.FirstOrDefault(),您将保证在ComboBox(除非ShiftList 中没有项目。

    最后,您的绑定将如下所示:

    <ComboBox ItemsSource="{Binding ShiftList}"
              SelectedItem="{Binding SelectedShift}"
              ... />
    

    【讨论】:

      【解决方案2】:

      @Mike Eason - 谢谢,这给了我需要的东西!

      Shift 的 ViewModel 现在如下所示:

          private ICollection<Gen_All_Shift> shiftList;
          public ICollection<Gen_All_Shift> ShiftList
          {
              get { return shiftList; }
              set { shiftList = value; NotifyPropertyChanged("ShiftList"); }
          }
      
          private Gen_All_Shift selectedShift;
          public Gen_All_Shift SelectedShift
          {
              get { return selectedShift; }
              set { selectedShift = value; NotifyPropertyChanged("SelectedShift"); }
          }
      
          public void LoadShiftList()
          {
              ShiftList = context.GetShiftList();
              SelectedShift = ShiftList.Where(p => p.ShiftId == CurrentRecord.ShiftIdFk)
                                       .FirstOrDefault();
          }
      

      在 ViewModel 构造函数中调用 LoadShiftList()。

      然后 XAML 现在已根据需要将绑定设置为 SelectedItem:

              <ComboBox x:Name="cboShift" 
                   ItemsSource="{Binding ShiftList}"
                   DisplayMemberPath="Shift"
                   SelectedItem="{Binding SelectedShift}" /> 
      

      以前我一直在尝试设置 SelectedShift.ShiftId == CurrentRecord.ShiftIdfk。这一直给我一个空异常。指出使用 .FirstOrDefault() 让我回到了正确的道路上。再次感谢。

      【讨论】:

        猜你喜欢
        • 2012-06-19
        • 1970-01-01
        • 2017-02-20
        • 2015-03-13
        • 2014-03-18
        • 1970-01-01
        • 2013-11-07
        • 2018-08-04
        • 2010-10-14
        相关资源
        最近更新 更多