Silverlight Image Loading Question
- by Matt
I'm playing around with Silverlight Images and a listbox. Here's the scenario.
Using WCF I grab some images out of my database and, using a custom class, add items to a listbox. It's working great right now. The images load and appear in the listbox, just like I want them to. I want to refine and improve my control just a little more so here's what I've done.
<ListBox x:Name="lbMedia" Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<c:WrapPanel></c:WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<im:MediaManagerItem></im:MediaManagerItem>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
Just a simple listbox. The datatemplate is a custom control and literally it contains a contentpresenter, nothing more.
Now the class that I use as the ItemSource has a Source property. Here's what it looks like.
private UIElement _LoadingSource;
private UIElement _Source;
public UIElement Source
{
get
{
if( _Source == null )
{
LoadMedia();
return new LoadingElement();
}
return _Source;
}
set
{
if( !( value is Image ) && !( value is MediaElement ) )
throw new Exception( "Media Source must be an Image or MediaElement" );
_Source = value;
NotifyPropertyChanged( "Source" );
}
}
Essentially, on the get I check if the image/video has been loaded from the server. If it hasn't I return a loading control, then I proceed to load my image. Here's the code for my LoadMedia method.
private void LoadMedia()
{
if( _Media != null && _Media.MediaId > 0 )
{
//load the media
BackgroundWorker mediaLoader = new BackgroundWorker();
mediaLoader.DoWork += mediaLoader_DoWork;
mediaLoader.RunWorkerCompleted += mediaLoader_RunWorkerCompleted;
mediaLoader.RunWorkerAsync();
}
}
void mediaLoader_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e )
{
if(_LoadingSource != null)
Source = _LoadingSource;
}
void mediaLoader_DoWork( object sender, DoWorkEventArgs e )
{
string url = App.siteUrl + "download.ashx?MediaId=" + _Media.MediaId;
SmartDispatcher.BeginInvoke( () =>
{
Image img = new Image();
img.Source = new BitmapImage( new Uri( url, UriKind.Absolute ) );
_LoadingSource = img;
} );
}
So as the code goes, I create a new image element, and set the Uri. The images that I'm downloading take about 2-5 seconds to download.
Now for the problem / fine tuning.
Right now my code will check if the source is null and if it is, return a loading element, and run the background worker to get the image. Once the background worker finishes, set the source to the new downloaded image.
I want to be able to set the Source property AFTER the image has fully downloaded. Right now my loading element appears for a brief second, then there's nothing for 2-5 seconds until the image finishes downloading. I want the loading elements to stick around until the image is completely ready but I'm having troubles doing this.
I've tried adding a a listener to the ImageOpened event and update the Source property then, but it doesn't work.
Thanks in advance.