I have 4 comboboxes bound (via an observable collection) to 4 separate folders containing about 200+ items each. When the window first loads, the filenames are stored in 4 separate observable collections, the datacontext of each combobox is set to its respective collection, then I'm using a converter to convert the uri to an image (with reduced quality to improve loading a bit) inside the ItemTemplate.
When I run the project, the splash screen shows up for 2-3 seconds max. But when I try to open each combobox, it takes 20-30 seconds to load all the items for the first time. So I'm wondering how I can move this loading to when the splash screen is showing.
Alternatively, is there a way to do something before/while the combobox is loading its items to let the user know the app didn't freeze? .. The combobox is using a wrappanel so I added a Loaded event to change a label to "Done" when it's finished loading, but I don't know which event to use to tell the user it's started loading. I tried MouseDown on the combobox but that didn't help (and I don't think it'd give the right behavior even if it worked).
Edit: Here's the code (just copying the relevant parts for one combobox for simplicity)
MainWindow, ComboBox XAML:
<Window.Resources>
<local:UriToThumbnailConverter x:Key="myThumbnailConverter" />
</Window.Resources>
<ComboBox Height="Auto" Width="Auto" x:Name="cmbLayers1" ItemsSource="{Binding}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Border Margin="3,8">
<Image Source="{Binding Path=FullPath, Converter={StaticResource myThumbnailConverter}}" Height="60">
<Image.ToolTip>
<TextBlock Text="{Binding Path=Name}"/>
</Image.ToolTip>
</Image>
<Border.Background>
<ImageBrush ImageSource="/WpfMyApplication;component/Images/ThumbnailBackground.png" Stretch="Uniform" TileMode="None" />
</Border.Background>
</Border>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
MainWindow code-behind:
Private layers1 As New ObservableCollection(Of CustomLayer)
Sub New()
InitializeComponent()
cmbLayers1.DataContext = layers1
ImportLayersFromFolder(My.Application.Info.DirectoryPath & "\Layer1", layers1)
cmbLayers1.SelectedIndex = 0
End Sub
Private Sub ImportLayersFromFolder(ByVal folder As String, ByVal layers As ObservableCollection(Of CustomLayer))
Dim files() As String = Directory.GetFiles(folder, "*.png")
Try
For Each sFile As String In files
layers.Add(New CustomLayer(sFile))
Next
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
CustomLayer Class:
Public Class mainLayer
Public Property Name As String
Public Property Path As String
Public ReadOnly Property FullPath As String
Get
Return System.IO.Path.Combine(Path, Name)
End Get
End Property
Public Overrides Function ToString() As String
Return FullPath
End Function
Public Sub New(ByVal filename As String)
Dim info As New FileInfo(filename)
Name = info.Name
Path = info.DirectoryName
End Sub
End Class
Thumbnail Converter:
Public Class UriToThumbn开发者_开发知识库ailConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
Dim bi As New BitmapImage()
bi.BeginInit()
bi.DecodePixelWidth = 60
bi.CacheOption = BitmapCacheOption.OnLoad
bi.UriSource = New Uri(value.ToString())
bi.EndInit()
Return bi
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
Throw New NotSupportedException
End Function
End Class
I didn't know where to add this but I figured posting it as an answer is better because it sorts what I was trying to do.
What I did is adding a new 'Image' property (of type BitmapImage) for the CustomLayer class; so the thumbnail is now actually part of the CustomLayer object.
The new constructor in the CustomLayer class now looks like this:
Public Sub New(ByVal filename As String)
Dim info As New FileInfo(filename)
Name = info.Name
Path = info.DirectoryName
Dim bi As New BitmapImage()
bi.BeginInit()
bi.DecodePixelWidth = 60
bi.CacheOption = BitmapCacheOption.OnLoad
bi.UriSource = New Uri(FullPath)
bi.EndInit()
Image = bi
End Sub
Also, inside the ItemTemplate of the ComboBox, the following line:
<Image Source="{Binding Path=FullPath, Converter={StaticResource myThumbnailConverter}}" Height="60">
changed to this:
<Image Source="{Binding Path=Image}" Height="60">
Now the actual creation of the thumbnails happens while the Window is loading, and when the user clicks the combobox the first time, it loads pretty quickly!
Now to figure out how I can use BackgroundWorker(s) to create all four collections at the same time rather than make them one after the other to improve loading time.
精彩评论