Patrick Ryan
Patrick Ryan

Reputation: 33

Can't update Image binding from BackgroundWorker

I am getting:

"An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll

Additional information: Must create DependencySource on same Thread as the DependencyObject."

XAML:

  <ListBox x:Name="AutoListBox" ItemsSource="{Binding AutoList}" Visibility="{Binding AutoListVisibility}">
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                   <EventSetter Event="MouseDoubleClick" Handler="EventSetter_OnHandler"></EventSetter>
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition Width="5"/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <Image Source="{Binding ImgSource}"></Image>
                        <Label Content="{Binding Name}"></Label>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

ViewModel:

    private Visibility isBusyVisibility;

    public Visibility IsBusyVisibility
    {
        get { return isBusyVisibility; }
        set
        {
            isBusyVisibility = value;
            RaisePropertyChanged("IsBusyVisibility");
        }
    }

    private ObservableCollection<GenericPictureName> autoList;

    public ObservableCollection<GenericPictureName> AutoList
    {
        get { return autoList; }
        set
        {
            autoList = value;
            RaisePropertyChanged("AutoList");
        }
    }
public AutoAlbumTrackAssociationViewModel()
    {
        _bwArtist = new BackgroundWorker();
        _bwArtist.DoWork += bwArtist_DoWork;
    }

private void bwArtist_DoWork(object sender, DoWorkEventArgs e)
    {
        AutoList = new ObservableCollection<GenericPictureName>(LastFMLookup.ArtistQuery(e.Argument.ToString()));

        RaisePropertyChanged("AutoList");
        RaisePropertyChanged("IsBusyVisibility");
    }

Model:

public class GenericPictureName
{
    private string name;

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
        }
    }

    private ImageSource imgSource;

    public ImageSource ImgSource
    {
        get { return imgSource; }
        set
        {
            imgSource = value;
        }
    }


    public GenericPictureName()
    {

    }

    public GenericPictureName(string name, string image)
    {
        Name = name;
        var bitmapImage = new BitmapImage();
        bitmapImage.BeginInit();
        bitmapImage.UriSource = new Uri(image); ;
        bitmapImage.EndInit();
        ImgSource = bitmapImage;
    }

}

If I remove the binding of the image from the XAML file, I get back a list in the UI that displays the names fine. I also did a test method that didn't use a backgroundworker to verify that it worked correctly. I also tried invoking the main thread and still got the same error. I am unsure of what to try next.

Upvotes: 0

Views: 496

Answers (2)

Clemens
Clemens

Reputation: 128136

If the image parameter refers to a local file, it should be sufficient to specify that the BitmapImage is loaded immediately by setting BitmapCacheOption.OnLoad, and then freeze it.

public GenericPictureName(string name, string image)
{
    Name = name;
    var bitmapImage = new BitmapImage();
    bitmapImage.BeginInit();
    bitmapImage.UriSource = new Uri(image);
    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
    bitmapImage.EndInit();
    bitmapImage.Freeze();
    ImgSource = bitmapImage;
}

In case it's a remote resource you may first download the image buffer and put it into a MemoryStream, from which you finally load the image:

public GenericPictureName(string name, string image)
{
    Name = name;
    var bitmapImage = new BitmapImage();
    var imageBuffer = new WebClient().DownloadData(image);
    using (var ms = new MemoryStream(imageBuffer))
    {
        bitmapImage.BeginInit();
        bitmapImage.StreamSource = ms;
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.EndInit();
    }
    bitmapImage.Freeze();
    ImgSource = bitmapImage;
}

Upvotes: 1

Ewan
Ewan

Reputation: 1310

try setting EnableCollectionSynchronization on your collection

BindingOperations.EnableCollectionSynchronization(AutoList, _itemsLock);

and then clear() and Add() to it in your worker method instead of recreating it

Upvotes: 1

Related Questions