在 ObservableCollection 上插入会导致 Win32Exception
Insert on ObservableCollection causes Win32Exception
我想 Insert
一个项目到一个 ObservableCollection
中,它在调度程序线程上使用 ComboBox
绑定(通过使用 DispatcherTimer
确保)。如果在 ComboBox
中选择了一个项目,插入调用将导致应用程序崩溃并出现不可调试的 Win32Exception
(看起来像 this)。当项目被 Add
ed 而不是 Insert
ed 时,代码将按预期 运行。
最小代码示例:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" Margin="77,59,0,0" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Data}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="202,58,0,0" VerticalAlignment="Top" Click="button_Click"/>
</Grid>
</Page>
后面的代码:
public class MyData
{
public string Text { get; set; }
}
public sealed partial class MainPage : Page
{
public ObservableCollection<MyData> Data { get; set; }
public MainPage()
{
DataContext = this;
Data = new ObservableCollection<MyData>()
{
new MyData { Text = "Lorem" }
};
this.InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += (_, __) => { Data.Insert(0, new MyData { Text = "Ipsum" }); /* crash */ };
timer.Start();
}
}
有没有办法在不导致应用程序崩溃的情况下插入项目?
一旦您尝试 'touch' selected 项目,问题似乎就会出现 - ObservableCollection 使用 List.Insert 方法,正如您在 reference 看到的那样,它使用 Array.Copy。 selected 项目被复制,然后在旧索引处用新项目替换,这可能不是由 Combobox 处理并导致异常。
请注意,当您 select 项目位于 0 位置,然后在第 1 个索引处插入项目时,不会出现异常。类似 - 如果没有项目被 selected,则在任何位置插入时都不会出现异常。因此,作为一种解决方法,如果适用,您可以尝试在开始插入之前将 Combobox.Selected 项目设置为 null,这可能会起作用。
我想 Insert
一个项目到一个 ObservableCollection
中,它在调度程序线程上使用 ComboBox
绑定(通过使用 DispatcherTimer
确保)。如果在 ComboBox
中选择了一个项目,插入调用将导致应用程序崩溃并出现不可调试的 Win32Exception
(看起来像 this)。当项目被 Add
ed 而不是 Insert
ed 时,代码将按预期 运行。
最小代码示例:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" Margin="77,59,0,0" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Data}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="202,58,0,0" VerticalAlignment="Top" Click="button_Click"/>
</Grid>
</Page>
后面的代码:
public class MyData
{
public string Text { get; set; }
}
public sealed partial class MainPage : Page
{
public ObservableCollection<MyData> Data { get; set; }
public MainPage()
{
DataContext = this;
Data = new ObservableCollection<MyData>()
{
new MyData { Text = "Lorem" }
};
this.InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += (_, __) => { Data.Insert(0, new MyData { Text = "Ipsum" }); /* crash */ };
timer.Start();
}
}
有没有办法在不导致应用程序崩溃的情况下插入项目?
一旦您尝试 'touch' selected 项目,问题似乎就会出现 - ObservableCollection 使用 List.Insert 方法,正如您在 reference 看到的那样,它使用 Array.Copy。 selected 项目被复制,然后在旧索引处用新项目替换,这可能不是由 Combobox 处理并导致异常。
请注意,当您 select 项目位于 0 位置,然后在第 1 个索引处插入项目时,不会出现异常。类似 - 如果没有项目被 selected,则在任何位置插入时都不会出现异常。因此,作为一种解决方法,如果适用,您可以尝试在开始插入之前将 Combobox.Selected 项目设置为 null,这可能会起作用。