如何在更改 WPF ComboBox 的数据上下文和项目源时保留双向绑定值

How to preserve two way binded value when changing both datacontext and items source of WPF ComboBox

背景

该应用程序有一个列表视图绑定到 "Jobs" 的列表,其中的属性可由某些组合框编辑(具有双向绑定)。通过列表视图的 SelectionChanged 事件,组合框的数据上下文更改为当前选择的 job

组合框值绑定到作业的 属性。作业的 itemssourceDataContextChanged 后更改为完全不同的列表。

Layout of widgets

问题

更改 DataContext 时,链接到作业组合框的绑定 属性 设置为空。

通过单击作业列表,绑定到任何组合框的所有属性都设置为空。

假设问题

我这个假设可能不正确...

随着 datacontext 切换,旧选择的 Job 或新选择的 Job 设置为空,因为项目源不包含存储在其中一个的值选择新的或旧的 Job.

调试尝试(编辑)

我注意到 Job 的 属性 的值在更改作业列表的 SelectedItem 之前设置为空。

问题

将ComboBox的数据上下文切换到不包含SelectedValue的项目源时,如何保留Job的绑定属性的值?

相关代码(删节 - 绑定到其他小部件按预期工作)

<ComboBox x:Name="ContactField" Grid.Column="1"  Grid.Row="3" Margin="2,1" Grid.ColumnSpan="3" DisplayMemberPath="Value" SelectedValuePath="Id" SelectedValue="{Binding Contact,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectionChanged="ContactField_SelectionChanged"/>

隐藏代码 - 更改项目来源

private void UpdateCustomerDependancies() 
{

    imprintDataSetTableAdapters.CustomerContactsTableTableAdapter rpcdtta = new imprintDataSetTableAdapters.CustomerContactsTableTableAdapter();
    IList<ComboData> customers = new List<ComboData>();

    if (LeftFieldPanel.DataContext != null) //Where LeftFieldPanel contains all comboboxes
    {
        Job currentJob = (Job)LeftFieldPanel.DataContext;

        foreach (DataRow item in rpcdtta.GetDataBy(currentJob.CustomerCode).Rows)
        {
            customers.Add(new ComboData() { Id = item.ItemArray[0].ToString(), Value = item.ItemArray[1].ToString() });
        }
        ContactField.ItemsSource = customers;

    }
}

代码隐藏 - 更改数据上下文

private void jobTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        if (jobTree.SelectedItem.GetType() == typeof(Job))
        {
            DelGrid.Visibility = Visibility.Hidden;


            Job j = (Job)jobTree.SelectedItem;


            MessageBox.Show(j.Contact);

            LeftFieldPanel.DataContext = j; //Switch datacontext
            RightFieldPanel.DataContext = j; //switchdata context

        }


    }

根据 this answer 和我自己的研究,不可能简单地绑定并希望达到最佳状态。因此,我对该解决方案的工作如下。我已经概括了代码以使其适用于其他情况。

1) 更改数据上下文后,将新项目添加到列表中,而不删除旧项目:

private void ListView1_SelectedItemChanged(...) {
    List<ComboData> comboitems = ((IList<ComboData>)ComboBox1.ItemsSource).ToList(); 
    //Add new items to comboitems here
    ComboBox1.ItemsSource = comboitems; //Rebind
}

2) 打开组合框的下拉列表后,获取项目源并仅删除旧项目

private void ComboBox1_DropDownOpened(...) {
    List<ComboData> comboitems = ((IList<ComboData>)ComboBox1.ItemsSource).ToList(); 
    //Remove old items from comboitems here
    ComboBox1.ItemsSource = comboitems; //Rebind
}

抱歉,如果这还不够清楚,我觉得发布真正的代码会让人很难理解。

这已经解决了我自己的问题。

备用解决方案

参见上文并添加项目而不删除旧项目。然后仅在 dropdownopened 事件中替换整个 itemssource。