43

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.

4
  • 3
    try bi.Freeze() after you create it and before you update Image Commented Oct 14, 2014 at 12:45
  • 2
    oh thanks. it worked like a magic. what does it do? I thought it might be a threading problem. try post the answer to be accepted Commented Oct 14, 2014 at 12:49
  • 1
    msdn.microsoft.com/en-us/library/ms750509(v=vs.110).aspx should give you the info about Freezing you require. Commented Oct 14, 2014 at 12:53
  • What we can't see, is who is creating the image and how is the property being set. Here's my thoughts, you should spin off a task like this. Task.Run(( //do image stuff here )=>); When the task completes it will automatically join the GUI thread if it was spun off there. Plus it will be about 5 times faster too. Commented Oct 14, 2014 at 13:11

2 Answers 2

114

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

Sign up to request clarification or add additional context in comments.

2 Comments

very useful for Video streaming from ImageSource creating drivers, especially since running acquisition on the UI's synchronization context is very costly and causes UI to freeze. +1 mate!
What if I don't want to update an Image where the Freeze method is availabel but for example a property of type ObservableCollection<T>? The Freeze method is not available in this type...
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.