对于任何可以帮助或向我展示更好方法的人。我尝试使用可观察的集合、基于自定义类的列表、全局/非全局集合、使用列表框的 itemssource、同步锁定,最后清空并手动输入项目来做到这一点。
它往往工作正常,但每隔一段时间我就会收到错误“集合已修改;枚举操作可能无法执行”。这似乎发生在 System.Collections.ArrayList.ArrayListEnumeratorSimple.MoveNext()
在过去的几周里,我尝试了一些不同的事情,有时我可以避免它,但我可以在不同的区域重现它。
本质上,我有三个列表框 Parent、Current、Children。这些都有标题图像。选择图像后,父、当前和子中的图像将清空并根据所选图像重新加载。
我已经用 vb 编写了它,但如果有帮助的话,我可以将它转换为 C#。代码已更改多次,因此最新的代码中有很多注释代码。任何帮助或建议将不胜感激。任何简化它、让它工作或性能增强的东西都会很棒。
想象一下一式三份的代码。除了名称之外,代码几乎相同。
<Page.Resources>
<CollectionViewSource
Source="{Binding Source={x:Static Application.Current}, Path=CurrentList}"
x:Key="CurrentList" />
</Page.Resources>
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Disabled" PanningMode="VerticalOnly" FlowDirection="RightToLeft" HorizontalScrollBarVisibility="Auto"
>
<ListBox Name="CurrentListbox" VerticalAlignment ="Stretch" Margin=" 8" Background="Transparent"
Height="Auto" BorderThickness="0" HorizontalContentAlignment="Center" FlowDirection="LeftToRight" HorizontalAlignment="Center"
ItemsSource="{Binding CurrentList}">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="ListBoxItem.Selected" Handler="CurrentListBoxItem_Selected" HandledEventsToo="false"/>
</Style>
</ListBox.Resources>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="#FF0000AC" Style="{StaticResource ResourceKey=ThumbnailBorder}">
<!--<Viewbox MaxWidth ="100" >-->
<StackPanel>
<Grid>
<Border Name="ItemBorder" Style="{StaticResource ResourceKey=ThumbnailInnerBorder}"/>
<Image Name="PersonImage" MaxHeight ="200" MaxWidth ="200" Source="{Binding ProfileImagePath}"
HorizontalAlignment="Center" >
<Image.OpacityMask>
<VisualBrush Visual="{Binding ElementName=ItemBorder}"/>
</Image.OpacityMask>
</Image>
</Grid>
<Viewbox MaxWidth ="190" Margin="5,0,5,0" MaxHeight="15">
<TextBlock Name="Person" Text="{Binding ProfileName}" Tag="{Binding UserID}" HorizontalAlignment="Center" />
</Viewbox>
</StackPanel>
<!--</Viewbox>-->
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
集合存储在全局变量中,并使用 SQlCe 命令填充。
Public Shared CurrentPeopleList As New CollectionViewSource
Public Shared Current_People_List As New ObservableCollection(Of Currents)()
Public Shared Property CurrentList() As ObservableCollection(Of Currents)
Get
Return Current_People_List
End Get
Set(ByVal value As ObservableCollection(Of Currents))
Current_People_List = value
End Set
End Property
电流的自定义类别:
Public Class Currents
Implements INotifyPropertyChanged
Private ProfileNameValue As String
Private UserIDValue As Integer
Private ProfileImagePathValue As String
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
#Region "Properties Getters and Setters" Public Property ProfileName() As String Get Return Me.ProfileNameValue End Get Set(ByVal value As String) Me.ProfileNameValue = value OnPropertyChanged("ProfileName") End Set End Property
Public Property UserID() As Integer
Get
Return Me.UserIDValue
End Get
Set(ByVal value As Integer)
If value < 0 Then
Throw New ArgumentException("User ID must be greater than 0 ")
End If
Me.UserIDValue = value
OnPropertyChanged("UserID")
End Set
End Property
Public Property ProfileImagePath() As String
Get
Return Me.ProfileImagePathValue
End Get
Set(ByVal value As String)
Me.ProfileImagePathValue = RelativeProgramPath() & "Media\Pictures\" & value
OnPropertyChanged("ProfileImagePath")
End Set
End Property
#End Region
Public Sub New(ByVal UserID As Integer, ByVal ProfileName As String, ByVal ProfileImagePath As String)
Me.ProfileNameValue = ProfileName
Me.UserIDValue = UserID
Me.ProfileImagePathValue = If(ProfileImagePath Like "pack://*", ProfileImagePath, RelativeProgramPath() & "Media\Pictures\" & ProfileImagePath)
End Sub
Protected Sub OnPropertyChanged(ByVal name As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
End Sub
End Class
最后,填充这些的方式是使用一个通用函数
Private Sub Reload(ByVal CurrentID As Integer)
Try
Try
ParentList = Nothing
CurrentList = Nothing
ChildrenList = Nothing
Catch
End Try
Try
Me.ParentListbox.ItemsSource = Nothing
Me.CurrentListbox.ItemsSource = Nothing
Me.ChildListbox.ItemsSource = Nothing
Catch
End Try
Try
CurrentPersonID = CurrentID
'Load the Images Based on the people.
Dim Ch = Load_Children_People(CurrentID)
Dim C = Load_Current_People(CurrentID)
Dim P = Load_Parent_People(CurrentID)
ParentList = If(P.Count > 0, P, Nothing)
CurrentList = If(C.Count > 0, C, Nothing)
ChildrenList = If(Ch.Count > 0, Ch, Nothing)
Catch
End Try
Try
If ParentList IsNot Nothing Then _
Me.ParentListbox.ItemsSource = CollectionViewSource.GetDefaultView(ParentList)
If CurrentList IsNot Nothing Then _
Me.CurrentListbox.ItemsSource = CollectionViewSource.GetDefaultView(CurrentList)
If ChildrenList IsNot Nothing Then _
Me.ChildListbox.ItemsSource = CollectionViewSource.GetDefaultView(ChildrenList)
Catch
End Try
Catch
End Try
'For some reason this will not work without a pause. Not sure why.
'FIXME Remove Pause Delay When able.
'Thread.Sleep(200)
End Sub
我使用了很多 try-catch 来尝试捕获错误,但到目前为止都没有成功。我怀疑错误发生在我似乎无法确定的 UI 线程期间。正如我之前提到的。任何帮助都会很棒。