如何在更改 WPF ComboBox 的数据上下文和项目源时保留双向绑定值
How to preserve two way binded value when changing both datacontext and items source of WPF ComboBox
背景
该应用程序有一个列表视图绑定到 "Jobs" 的列表,其中的属性可由某些组合框编辑(具有双向绑定)。通过列表视图的 SelectionChanged
事件,组合框的数据上下文更改为当前选择的 job
。
组合框值绑定到作业的 属性。作业的 itemssource
在 DataContextChanged
后更改为完全不同的列表。
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。
背景
该应用程序有一个列表视图绑定到 "Jobs" 的列表,其中的属性可由某些组合框编辑(具有双向绑定)。通过列表视图的 SelectionChanged
事件,组合框的数据上下文更改为当前选择的 job
。
组合框值绑定到作业的 属性。作业的 itemssource
在 DataContextChanged
后更改为完全不同的列表。
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。