【发布时间】:2022-01-06 19:37:55
【问题描述】:
我有一个组合框,其中包含一个值列表,后跟一个静态“添加新”项。当我选择该项目时,它会加载图像并将图像的文件名添加到值列表中。但是,当我这样做时,WPF 底层代码会引发“集合已修改”异常。
XAML:
<StackPanel Orientation="Vertical">
<ComboBox x:Name="selector">
<ComboBoxItem IsEnabled="False" Content="---" />
<ComboBoxItem FontStyle="Italic" Content="Add New" Selected="New_Selected" />
</ComboBox>
</StackPanel>
代码:
public partial class MainWindow : Window
{
List<string> files = new List<string>();
public MainWindow()
{
InitializeComponent();
}
private void RepopulateResourceSelector()
{
// Remove all but the bottom 2 items
while (selector.Items.Count > 2)
{
selector.Items.RemoveAt(0);
}
int index = 0;
// Add all strings in the list to combo box
foreach (var file in files)
{
selector.Items.Insert(index, file);
index++;
}
}
private void New_Selected(object sender, RoutedEventArgs e)
{
var dlg = new OpenFileDialog();
dlg.Filter = "Image Files (.bmp, .jpg, .gif, .png, .tiff)|*.bmp;*.jpg;*.gif;*.png;*.tiff";
if (dlg.ShowDialog(this) == true)
{
// Add selected file to the list
string name = System.IO.Path.GetFileNameWithoutExtension(dlg.FileName);
files.Add(name);
RepopulateResourceSelector();
}
// Deselect `Add New` item
selector.SelectedIndex = -1;
}
}
堆栈跟踪:
System.InvalidOperationException occurred
HResult=0x80131509
Message=Collection was modified; enumeration operation may not execute.
Source=<Cannot evaluate the exception source>
StackTrace:
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at System.Windows.Controls.Primitives.Selector.SelectionChanger.CreateDeltaSelectionChange(List`1 unselectedItems, List`1 selectedItems)
at System.Windows.Controls.Primitives.Selector.SelectionChanger.End()
at System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(ItemInfo info, Boolean assumeInItemsCollection)
at System.Windows.Controls.ComboBox.NotifyComboBoxItemMouseUp(ComboBoxItem comboBoxItem)
at System.Windows.Controls.ComboBoxItem.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at WpfApp1.App.Main()
【问题讨论】:
-
这是因为您无法同时从
selector中删除它 -
@jamiedanq 我不会经历它。这是
while循环,而不是for。 -
@jamiedanq 就像我在问题中所说的那样,我的代码中的任何地方都没有发生异常。它发生在 WPF 代码中的某处在我的代码完成之后。
-
异常堆栈跟踪中的前六个条目,它们告诉您什么?如果选择只是在改变,我不知道你为什么要尝试改变选择;但是,您可以在 Selected 和 SelectionChanged 事件结束后尝试修改选择。例如,通过调度调度器的事件队列(BeginInvoke 或 InvokeAsync)上的相应工作
-
异常是否由于这一行
RepopulateResourceSelector();或这一行selector.SelectedIndex = -1;而发生(即先注释掉其中一个,然后注释掉另一个,看看是哪个导致的)?可能是前者,但我只是想在给出建议之前检查一下。