Mehrdad Kamelzadeh
Mehrdad Kamelzadeh

Reputation: 1784

Error: Must create DependencySource on same Thread as the DependencyObject even by using Dispatcher

The following is part of my View in which I have bound an Image to a property in my ViewModel:

<Image Source="{Binding Image}"  Grid.Column="2" Grid.ColumnSpan="2"/>

My ViewModel is this:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public BitmapImage Image
    {
        get { return _image; }
        set
        {
            _image = value;
            OnPropertyChanged();
        }
    }

    Action _makeScannerAlwaysOnAction;
    private BitmapImage _image;


    public MainWindowViewModel()
    {
        AddNewPersonCommand = new RelayCommand(OpenFrmAddNewPerson);
        FingerPrintScannerDevice.FingerPrintScanner.Init();
        MakeScannerAlwaysOn(null);
    }

    private void MakeScannerAlwaysOn(object obj)
    {
        _makeScannerAlwaysOnAction = MakeScannerOn;
        _makeScannerAlwaysOnAction.BeginInvoke(Callback, null);
    }

    private void Callback(IAsyncResult ar)
    {
        FingerPrintScannerDevice.FingerPrintScanner.UnInit();
        var objFingerPrintVerifier = new FingerPrintVerifier();
        objFingerPrintVerifier.StartVerifingProcess();
        var ms = new MemoryStream();
        ms.Position = 0;
        objFingerPrintVerifier.MatchPerson.Picture.Save(ms, ImageFormat.Png);
        var bi = new BitmapImage();
        bi.BeginInit();
        bi.StreamSource = ms;
        bi.EndInit();
        Thread.Sleep(2000);
        Dispatcher.CurrentDispatcher.Invoke(() => Image = bi);
        //Image = bi;

        _makeScannerAlwaysOnAction.BeginInvoke(Callback, null);
    }

    private void MakeScannerOn()
    {
        while (true)
        {
            if (FingerPrintScannerDevice.FingerPrintScanner.ScannerManager.Scanners[0].IsFingerOn)
            {
                return;
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

My Problem: The problem is when I want to bind the Image it gives me the error

Must create DependencySource on same Thread as the DependencyObject

I have googled a lot and I have seen the post in SO but neither of them worked for me.

any kind of help would be very appreciated.

Upvotes: 43

Views: 40539

Answers (2)

Andrew Myhalchuk
Andrew Myhalchuk

Reputation: 26

While bi.Freeze(); worked for me in one case, I've seen no difference from adding/removing

Dispatcher.CurrentDispatcher.Invoke(() => Image = bi);

The second time I used DataTemplate in xaml and all the same classes as in the first case, but I kept getting the same Error.

This was a thing that helped:

Application.Current.Dispatcher.Invoke(() => Image = bi);

Maybe accepted answer can be improved because Dispatcher.CurrentDispatcher don't actually give you UI thread.

Upvotes: 0

dkozl
dkozl

Reputation: 33384

BitmapImage is DependencyObject so it does matter on which thread it has been created because you cannot access DependencyProperty of an object created on another thread unless it's a Freezable object and you can Freeze it.

Makes the current object unmodifiable and sets its IsFrozen property to true.

What you need to do is call Freeze before you update Image:

bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
bi.Freeze();

Dispatcher.CurrentDispatcher.Invoke(() => Image = bi);

as pointed out by @AwkwardCoder here is Freezable Objects Overview

Upvotes: 114

Related Questions