Search code examples
c#wpfxamlimagesource

Bound Image with converter not displaying in WPF


I'm trying to make a window display some playing cards--simply a textblock with 'A'-'K' and a suit Image. I have the images stored in Resources.resx as Resources.Spades, Resources.Hearts, etc.

In my Window.Resources xaml, I have

<ResourceDictionary x:Name="HighCardsResources">
    <c:SuitToImageConverter x:Key="SuitConverter" />
    <DataTemplate x:Key="CardTemplate" DataType="{x:Type c:Card}">
        <Border CornerRadius="10" Width="50" Height="50" BorderBrush="Black" BorderThickness="2">
            <Grid Width="50" Height="50">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="18"/>
                    <ColumnDefinition Width="32"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding RankText}" Grid.Column="0" FontSize="24" />
                <Image Source="{Binding Suit, Converter={StaticResource SuitConverter}}" Grid.Column="1" />
            </Grid>
        </Border>
    </DataTemplate>
</ResourceDictionary>

My SuitToImageConverter code is

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    switch ((Suit)value)
    {
        case Suit.Spades:
            return Resources.Spades;
        case Suit.Hearts:
            return Resources.Hearts;
        case Suit.Clubs:
            return Resources.Clubs;
        case Suit.Diamonds:
            return Resources.Diamonds;

        default:
            return null;
    }
}

I'm dynamically adding ContentPresenters to a grid.

int col = 0;
foreach (Card card in hand.Cards)
{
    DataTemplate template = FindResource("CardTemplate") as DataTemplate;
    ContentPresenter cp = new ContentPresenter();
    cp.ContentTemplate = template;
    cp.SetValue(Grid.RowProperty, 0);
    cp.SetValue(Grid.ColumnProperty, col);
    cp.Width = 50;
    cp.Height = 50;
    cp.Content = card;
    grdHand.Children.Add(cp);

    col++;
}

I know that the card is binding correctly because the TextBlock gets the correct string. I also know that the SuitToImageConverter is being used, and that the correct image resource is being returned (via debugging). For some reason, the image just isn't being displayed. Ideas?


Solution

  • I figured it out thanks to this link. Resx images are of type Bitmap, while Image.Source requires type BitmapImage.

    I changed SuitToImageConverter to look like:

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch ((Suit)value)
        {
            case Suit.Spades:
                return ConvertToBitmapImage(Resources.Spades);
            case Suit.Hearts:
                return ConvertToBitmapImage(Resources.Hearts);
            case Suit.Clubs:
                return ConvertToBitmapImage(Resources.Clubs);
            case Suit.Diamonds:
                return ConvertToBitmapImage(Resources.Diamonds);
    
            default:
                return null;
        }
    }
    
    private static BitmapImage ConvertToBitmapImage(Bitmap bitmap)
    {
        BitmapImage img = new BitmapImage();
        img.BeginInit();
    
        MemoryStream stream = new MemoryStream();
        bitmap.Save(stream, ImageFormat.Bmp);
        stream.Seek(0, SeekOrigin.Begin);
    
        img.StreamSource = stream;
        img.EndInit();
    
        return img;
    }
    

    and now everything works.