El hilo de llamada no puede acceder a este objeto porque un hilo diferente lo posee

¿Por qué no puedo crear CroppedBitmap en el siguiente código? Tengo una excepción:

El hilo de llamada no puede acceder a este objeto porque lo posee un hilo diferente.

Si cambio el código a

CroppedBitmap cb = new CroppedBitmap(new WriteableBitmap(bf), new Int32Rect(1, 1, 5, 5)); 

la excepción se ha ido? por qué ?

Código 1, una excepción en cb.Freeze() :

 public MainWindow() { InitializeComponent(); ThreadPool.QueueUserWorkItem((o) => { //load a large image file var bf = BitmapFrame.Create( new Uri("D:\\1172735642.jpg"), BitmapCreateOptions.None, BitmapCacheOption.None); bf.Freeze(); Dispatcher.BeginInvoke( new Action(() => { CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5)); cb.Freeze(); //set Image's source to cb.... }), DispatcherPriority.ApplicationIdle); } ); } 

Código 2, funciona:

  ThreadPool.QueueUserWorkItem((o) => { var bf = BitmapFrame.Create( new Uri("D:\\1172740755.jpg"), BitmapCreateOptions.None, //BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); bf.Freeze(); var wb = new WriteableBitmap(bf); wb.Freeze(); this.Dispatcher.Invoke( new Action(() => { var r = new Int32Rect(1, 1, 5, 5); CroppedBitmap cb = new CroppedBitmap(wb, r); cb.Freeze(); //set Image's source to cb.... Image.Source = cb; }), DispatcherPriority.ApplicationIdle); } ); 

Código 3, funciona sin WritableBitmap:

 ThreadPool.QueueUserWorkItem((o) => { var bf = BitmapFrame.Create( new Uri("D:\\1172735642.jpg"), BitmapCreateOptions.None, //BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); bf.Freeze(); var bf2 = BitmapFrame.Create(bf); bf2.Freeze(); this.Dispatcher.Invoke( new Action(() => { var r = new Int32Rect(1, 1, 5, 5); BitmapSource cb = new CroppedBitmap(bf2, r); cb.Freeze(); //set Image's source to cb.... Image.Source = cb; }), DispatcherPriority.ApplicationIdle); } ); 

Puedes mirar a través de estas clases en el reflector. La excepción boostá en cb.Freeze (). En

 CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5)); 

case constructor hizo algo como esto:

 this.this.Source = source; 

Por lo tanto, la fuente no se creó en el hilo actual, por lo que la excepción boostá. En

 new WriteableBitmap(bf) 

caso, el constructor se sincroniza con el objeto bf y el nuevo origen se crea con el hilo actual, por lo tanto, no surgirán excepciones. Si está interesado en los detalles de In Depth, siempre puede reflejar las bibliotecas base con Reflector 🙂

El siguiente código puede ayudarlo a resolver el problema de actualizar un elemento gui de otro hilo:

Nivel de módulo

 delegate void updateCallback(string tekst); 

Este es el método para actualizar su elemento:

 private void UpdateElement(string tekst) { if (element.Dispatcher.CheckAccess() == false) { updateCallback uCallBack = new updateCallback(UpdateElement); this.Dispatcher.Invoke(uCallBack, tekst); } else { //update your element here } } 

Cuando trabaje con WPF, tenga en cuenta que si crea un objeto UI en un hilo, no podrá acceder a él desde otro hilo. Sus objetos de interfaz de usuario deben (normalmente) crearse el subproceso de interfaz de usuario, y luego necesita el subproceso de interfaz de usuario para acceder a ellos más tarde. Ningún otro subproceso podrá acceder a los objetos creados en el subproceso de interfaz de usuario.

Si necesita acceder a un objeto UI desde otro hilo, necesita el despachador de hilos de interfaz de usuario, y luego puede usar esto para invocar llamadas en el hilo de la interfaz de usuario.

Pasé muchas horas frustrado por problemas similares a esto, créanme … Miren esta pregunta , me dio mucha información útil sobre el tema.

Tuve el mismo problema y solucioné el problema creando mi UIElement en el hilo de la interfaz de usuario utilizando su despachador (al que se puede acceder mediante Application.Current.Dispatcher ).

Antes de:

 public static UIElement CreateUIElement() { UIElement element = new UIElement(); //Initialized the UIElement here return element; } 

Este código provocó una XamlParseException como se llamó en un subproceso diferente al subproceso de la interfaz de usuario.

Mi solución de trabajo:

 public static UIElement CreateUIElement() { UIElement element = null; Application.Current.Dispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Normal, new Action( delegate() { element = new UIElement(); // Initialize your UIElement here })); return element; } 

Puede encontrar más información sobre el despachador aquí http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher

Buena suerte