Search code examples
c#jsonwpfjson-serialization

How to correctly manage databinding and serialization/deserialization of a BitmapImage?


That's my basic code:

public class MyObject
{
    public decimal MyDeciaml { get; set; }
    public string? MyImageBase64
    {
        get
        {
            if (MyImageBase64 != null)
            {
                byte[] imageBytes = Convert.FromBase64String(MyImageBase64);
                using (MemoryStream stream = new MemoryStream(imageBytes))
                {
                    BitmapImage bitmapImage = new BitmapImage();
                    bitmapImage.BeginInit();
                    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                    bitmapImage.StreamSource = stream;
                    bitmapImage.EndInit();
                    bitmapImage.Freeze();
                    MyImageBitmap = bitmapImage;
                }
            }

            return MyImageBase64;
        }
        set { }
    }
    [JsonIgnore]
    public BitmapImage? MyImageBitmap { get; set; }
}

which I bind using a ViewModelData class and ObservableCollection<MyObject> myObjects = new ObservableCollection<MyObject>(); against a ListBox:

<ListBox ItemsSource="{Binding MyObjects}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <Grid>
                    <Image x:Name="myImage"
                           Source="{Binding MyImageBitmap}"
                           VerticalAlignment="Center"
                           HorizontalAlignment="Center"
                           Width="Auto"
                           Height="Auto" />
                </Grid>
                <TextBlock Text="{Binding MyDeciaml }" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

It seems to works nice on binding. Now, when I serialize it on json using Newtonsoft.Json's JsonConvert.SerializeObject(data), I see this on the json:

"MyImageBitmap": "System.Windows.Media.Imaging.BitmapImage"

How can I remove it? It seems [JsonIgnore] has no effect?

I want to remove, and just keep MyImageBase64 (on deserialization, convert it to BitmapImage, and get back the image).

Thanks for any tips on this. Maybe a better way is to bind directly the base64 string and do the conversion to BitmapImage on ListBox, if possible?


Solution

  • Use a byte array for the image in the data class.

    • Newtonsoft.Json uses a base64 converter for byte arrays by default
    • Image.Source can be bound to a byte array

    So change your class to

    public class MyObject
    {
        public decimal MyDeciaml { get; set; }
        public byte[] MyImage { get; set; }
    }
    

    and the Xaml to

    <ListBox ItemsSource="{Binding MyObjects}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <Grid>
                        <Image x:Name="myImage"
                               Source="{Binding MyImage}"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Center"
                               Width="Auto"
                               Height="Auto" />
                    </Grid>
                    <TextBlock Text="{Binding MyDeciaml}" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>