WPF - using CroppedBitmap in DataTemplate

2019-03-01 17:50发布

问题:

The following xaml works ok inside a Window:

<Border Width="45" Height="55" CornerRadius="10" >
    <Border.Background>
        <ImageBrush>
            <ImageBrush.ImageSource>
                <CroppedBitmap Source="profile.jpg" SourceRect="0 0 45 55"/>
            </ImageBrush.ImageSource>
        </ImageBrush>    
    </Border.Background>
</Border>

But when I use the equivalent code in a DataTemplate I get the following error in run-time:

Failed object initialization (ISupportInitialize.EndInit). 'Source' property is not set. Error at object 'System.Windows.Media.Imaging.CroppedBitmap' in markup file.
Inner Exception:
{"'Source' property is not set."}

The only difference is that I have the CroppedBitmap's Source property data-bound:

<CroppedBitmap Source="{Binding Photo}" SourceRect="0 0 45 55"/>

What gives?

UPDATE: According to an old post by Bea Stollnitz this is a limitation of the source property of the CroppedBitmap, because it implements ISupportInitialize. (This information is down the page - do a search on "11:29" and you'll see).
Is this still an issue with .Net 3.5 SP1?

回答1:

When the XAML parser creates CroppedBitmap, it does the equivalent of:

var c = new CroppedBitmap();
c.BeginInit();
c.Source = ...    OR   c.SetBinding(...
c.SourceRect = ...
c.EndInit();

EndInit() requires Source to be non-null.

When you say c.Source=..., the value is always set before the EndInit(), but if you use c.SetBinding(...), it tries to do the binding immediately but detects that DataContext has not yet been set. Therefore it defers the binding until later. Thus when EndInit() is called, Source is still null.

This explains why you need a converter in this scenario.



回答2:

I know it's old but I thought I would complete the answer with the Converter. Now I use this converter and that seems to work, no more Source' property is not set error.

public class CroppedBitmapConverter : IValueConverter 
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    FormatConvertedBitmap fcb = new FormatConvertedBitmap();
    fcb.BeginInit();
    fcb.Source = new BitmapImage(new Uri((string)value));
    fcb.EndInit();
    return fcb;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    throw new NotImplementedException();
}
}