MVVM ComboBox SelectedIndex与SelectedItem

时间:2016-05-26 21:49:19

标签: c# wpf mvvm combobox

我正在尝试使用特定记录中的数据填充多个ComboBox。我可以让其中一个正常运行,但我认为一个概念错误阻止我让第二个正常工作。我搜索了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)填充人员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,则保存对记录的更改。如果我在Personnel ComboBox中选择一个人并尝试保存,我会收到System Null Exception。我认为这是由于阻止SelectedIndex使用人员组合框的相同问题引起的。

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

2 个答案:

答案 0 :(得分:1)

你尝试过的第一件事实际上是正确的,但有一些事情会让你失望。

例如:

get { return context.GetShiftList(); }

一般来说,这是一个好主意。任何调用此属性的人都会调用数据库调用每次,这会影响性能并且根本不需要。

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

public void ReloadShiftList()
{
    //TODO: Your logic here

    ShiftList = ...
}

注意:请确保在INotifyPropertyChanged属性上实施ShiftList,以便在更改此属性时更新视图。

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

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

通过将SelectedShift设置为.FirstOrDefault()的{​​{1}},您可以保证始终 选择ShiftList中(除非ComboBox中没有项目。)

最后,你的绑定看起来像这样:

ShiftList

答案 1 :(得分:0)

@ 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()让我回到了正确的道路上。再次感谢。