BitmapImage.UriSource binding doesn't work ...
For whatever reason, WPF/XAML doesn't support direct binding of a Uri object to the UriSource of a BitmapImage object. When run, the application fails with an error, "Property 'UriSource' or property 'StreamSource' must be set." (Here's a complaint about this on MSDN Forums).
This makes easy displays of image items with a source or Uri property more challenging than it should be. I've found one work-around for now (it's not as snappy as I'd like though if the images are large). As with any binding of images, binding to large images may have a negative impact on application performance as Bitmap's must be created on the UI thread.
Here's how to use my new UriToImageConverter value converter:
First, create, in the appropriate Resources, an instance of the new ValueConverter.
<local:UriToImageConverter x:Key="LocalUriToImageConverter"/>
Of course, you'll need to declare the new xml namespace (usually in the root element in XAML, such as the Window or Page):
xmlns:local="clr-namespace:MyApplicationNamespace"
Then, in the DataTemplate (which is likely where you'd use this), you'll need to use the converter, not as a converter to a Uri, but to the ImageSource itself:
<Image x:Name="imgPhoto" Width="80" Height="60" Grid.Row="0"
Source="{Binding Path=FilenameUri,
Converter={StaticResource LocalUriToImageConverter}}">
Finally, add the C# code below to your project.
The Path in this instance can be either a string or a Uri. The trick is that this converter returns a new ImageSource:
1: public class UriToImageConverter : IValueConverter
2: { 3: 4: public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
5: {6: if (value == null)
7: {8: return null;
9: } 10: 11: if (value is string)
12: {13: value = new Uri((string)value);
14: } 15: 16: if (value is Uri)
17: { 18: BitmapImage bi = new BitmapImage();
19: bi.BeginInit(); 20: bi.DecodePixelWidth = 80; 21: //bi.DecodePixelHeight = 60; 22: bi.UriSource = (Uri)value;
23: bi.EndInit();24: return bi;
25: } 26: 27: return null;
28: } 29: 30: public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
31: {32: throw new Exception("The method or operation is not implemented.");
33: } 34: 35: }
Note that once the value is converted to a Uri (if necessary), a new BitmapImage object is created [line 18]. Then, within the appropriate Begin/End Init block [lines 19-23], the UriSource (and an example DecodePixelWidth is set). The new ImageSource (BitmapImage) is returned to the converter. So, the Uri is converted directly to the BitmapImage, with WPF being none-the-wiser!
Comments
Worked like a charm. Dropped my app from taking up 300+ mb to around 34 of memory loading around 2000 300k files. Many, many thanks.
Posted by: Will | July 29, 2007 4:07 PM