tags:

views:

83

answers:

1

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 UriToThumbnailConverter
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
A: 

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.

Mike