我遇到ComboBox
与ObservableCollection
绑定的问题,我想知道是否有人可以指出我错过的内容。
我有一个ComboBox
绑定到一个简单的ObservableCollection<string>
。我还将SelectedIndex
OneWay
绑定到某个属性。
在我的应用程序中,我想要清除集合并使用不同的数据重新填充它并将SelectedIndex
设置为新值。由于某种原因,SelectedIndex
绑定不起作用。
我附上了一个问题的重复:
public partial class Window1 : Window, INotifyPropertyChanged
{
private int j;
public event PropertyChangedEventHandler PropertyChanged;
public Window1()
{
InitializeComponent();
DataContext = this;
Tables = new ObservableCollection<string>();
}
public ObservableCollection<string> Tables { get; set; }
private int _TheIndex;
public int TheIndex
{
get { return _TheIndex; }
set
{
_TheIndex = value;
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("TheIndex"));
}
}
}
private void aaaa(object sender, RoutedEventArgs e)
{
j = (j + 1)%10;
Tables.Clear();
for(int i = 0; i < 10 ; i++)
{
Tables.Add(i.ToString());
}
TheIndex = j;
}
}
xaml是:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel>
<ComboBox x:Name="TablesCombobox"
ItemsSource="{Binding Tables}"
SelectedIndex="{Binding TheIndex, Mode=OneWay}"/>
<Button Content="asdasd" Click="aaaa"/>
</StackPanel>
</Grid>
</Window>
答案 0 :(得分:4)
问题完全是由Tables.Clear()
方法中的aaaa()
行引起的。由于Tables
是一个可观察的集合,因此擦除集合的所有内容会导致WPF使用新的空列表更新显示。然后它尝试使用SelectedIndex
选择当前活动的项目,该项目不存在(因为列表现在为空)。结果,绑定引擎留下了一个无法应用的值,并决定停用和分离绑定逻辑:
System.Windows.Data Warning: Got PropertyChanged event from Window1 for TheIndex
System.Windows.Data Warning: GetValue at level 0 from Window1 using DependencyProperty(TheIndex): '1'
System.Windows.Data Warning: TransferValue - got raw value '1'
System.Windows.Data Warning: TransferValue - using final value '1'
System.Windows.Data Warning: Deactivate
System.Windows.Data Warning: Replace item at level 0 with {NullDataItem}
System.Windows.Data Warning: Detach
到达'TheIndex = j;'时line,绑定不再有效,并且看不到对TheIndex的更改,这意味着不再选择所需的索引。
有几种解决方案可以解决这个问题:
TwoWay
绑定。这是有效的,因为现在ComboBox参与绑定;你清除Tables
,绑定试图设置但无法找到索引,因此ComboBox重置为-1的特殊“无索引”位置,然后写回TheIndex
(两个 - 方式部分),这是一个有效的值,因此绑定逻辑不会分离。 清除集合前不选择索引(-1)。如果清除Tables
时未选择索引(-1),则ComboBox不会尝试应用SelectedItem
,这意味着它不会“看到”清空和重新填充的集合,因此不会分离。
private void aaaa(object sender, RoutedEventArgs e)
{
TheIndex = -1;
j = (j + 1)%10;
Tables.Clear();
for (int i = 0; i < 10; i++)
{
Tables.Add(i.ToString());
}
TheIndex = j;
}
出于性能,体系结构和清晰度的原因,我强烈推荐选项1,但我意识到您的实际情况可能更复杂,需要3行。
<强>旁注:强>
在使用上面发布的绑定跟踪时,找到这样的绑定问题背后的原因相当容易。通过声明System.Diagnostics命名空间并将PresentationTraceSources.TraceLevel=High
添加到导致问题的绑定来打开它们以进行单个绑定:
<Window xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase" />
...
<TextBlock Text="{Binding Path=x, diag:PresentationTraceSources.TraceLevel=High}" />
调试WPF绑定的更多方法是here。
答案 1 :(得分:0)
我知道这是一个古老的问题,但我自己刚刚遇到过这个问题,所以根据@Nicholas Armstrong的答案1的答案编写了一个辅助方法,我想我会分享它,希望有人能找到它有用:
public void refreshDropdownOptions(ObservableCollection<object> OldOptions, ObservableCollection<object> NewOptions)
{
MainWindow application = Application.Current.MainWindow as MainWindow;
int highestCount = 0;
if(OldOptions.Count() > NewOptions.Count())
{
highestCount = OldOptions.Count();
}
else
{
highestCount = NewOptions.Count();
}
for (int i = 0; i < highestCount; i++)
{
if(i < OldOptions.Count() && i < NewOptions.Count())
{// If we have not exceeded the count of either list, copy the new value over the old
application.Dispatcher.Invoke((Action)(() => OldOptions[i] = NewOptions[i]));
}
else if (i < OldOptions.Count() && i >= NewOptions.Count())
{// If we have no more new options remove the old option
application.Dispatcher.Invoke((Action)(() => OldOptions.RemoveAt(i)));
highestCount = OldOptions.Count();
i--;
}
else if (i >= OldOptions.Count() && i < NewOptions.Count())
{// if we have no more old options to replace, add the new option to the end of the collection
application.Dispatcher.Invoke((Action)(() => OldOptions.Add(NewOptions[i])));
}
}
}