2008-08-31 14 views

Respuesta

3

Suponiendo que está usando el enlace de datos, el establecimiento de Binding.IsAsync propiedad a True parece ser una forma estándar para lograrlo. Si va a cargar el mapa de bits en el archivo usando hilo de fondo + objeto Dispatcher es una forma común de actualizar la interfaz de usuario asíncrono

+3

la BitmapImage se deben crear en el hilo de interfaz de usuario: esto va a lanzar una excepción ... –

+1

@ Jmix90: no está claro qué parte de esta respuesta que usted se refiere. Sin embargo, el uso de 'Binding.IsAsync' permite que se especifique una Uri/ruta en' Image.Source' y que la imagen se cargue de forma asíncrona automáticamente. WPF se ocupa de cualquier problema de cruce de hilos en este escenario. Si uno está creando bitmaps en un hilo de fondo, uno simple necesita llamar 'Freeze()' en el objeto de mapa de bits antes de pasarlo al hilo de UI. Solo arroja una excepción si lo haces mal. –

0

uso o ampliar System.ComponentModel.BackgroundWorker de código subyacente:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Personalmente, Encuentro que esta es la forma más fácil de realizar operaciones asíncronas en aplicaciones de clientes. (He usado esto en WinForms, pero no en WPF. Supongo que esto también funcionará en WPF.)

Normalmente extiendo Backgroundworker, pero no es necesario.

public class ResizeFolderBackgroundWorker : BackgroundWorker 
{ 

    public ResizeFolderBackgroundWorker(string sourceFolder, int resizeTo) 
    { 
     this.sourceFolder = sourceFolder; 
     this.destinationFolder = destinationFolder; 
     this.resizeTo = resizeTo; 

     this.WorkerReportsProgress = true; 
     this.DoWork += new DoWorkEventHandler(ResizeFolderBackgroundWorker_DoWork); 
    } 

    void ResizeFolderBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     DirectoryInfo dirInfo = new DirectoryInfo(sourceFolder); 
     FileInfo[] files = dirInfo.GetFiles("*.jpg"); 


     foreach (FileInfo fileInfo in files) 
     { 
      /* iterate over each file and resizing it */ 
     } 
    } 
} 

Esta es la forma en que lo utilizaría en su forma:

//handle a button click to start lengthy operation 
    private void resizeImageButtonClick(object sender, EventArgs e) 
    { 
     string sourceFolder = getSourceFolderSomehow(); 
     resizer = new ResizeFolderBackgroundWorker(sourceFolder,290); 
     resizer.ProgressChanged += new progressChangedEventHandler(genericProgressChanged); 
     resizer.RunWorkerCompleted += new RunWorkerCompletedEventHandler(genericRunWorkerCompleted); 

     progressBar1.Value = 0; 
     progressBar1.Visible = true; 

     resizer.RunWorkerAsync(); 
    } 

    void genericRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     progressBar1.Visible = false; 
     //signal to user that operation has completed 
    } 

    void genericProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     progressBar1.Value = e.ProgressPercentage; 
     //I just update a progress bar 
    } 
1

Elaborar en la respuesta de aku, aquí es un pequeño ejemplo en cuanto a dónde establecer el isAsync:

ItemsSource="{Binding IsAsync=True,Source={StaticResource ACollection},Path=AnObjectInCollection}" 

Eso es lo que harías en XAML.

+0

No entiendo por qué esta respuesta obtuvo un -1, ¡ya que era justo lo que estaba buscando! No se pudo averiguar cómo hacer conversión asíncrona. Resulta que _solo_ tiene que poner IsAsync = True en su enlace. ¡Muchas gracias! – Rasive

7

que solo estaba buscando en esto y tuvieron que tirar mis dos centavos, aunque unos pocos años después de la publicación original (sólo en caso de cualquier otra persona viene buscando este mismo que yo estaba investigando).

que tienen un control dede imagen que necesita tener es la imagen cargada en el fondo utilizando una corriente , y luego se muestran.

El problema que seguí corriendo en es que el BitmapSource, es corriente fuente y el control de imagen todos tenían que estar en el mismo hilo.

En este caso, el uso de una encuadernación y el establecimiento Es IsAsynch = true lanzará una excepción hilo cruzado.

Un BackgroundWorker es ideal para WinForms, y puede usarlo en WPF, pero prefiero evitar el uso de los ensamblados de WinForm en WPF (no se recomienda la hinchazón de un proyecto, y también es una buena regla general). Esto también arrojaría una excepción de referencia cruzada no válida en este caso, pero no lo probé.

Resulta que una línea de código hará que cualquiera de estos trabajos:

//Create the image control 
Image img = new Image {HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, VerticalAlignment = System.Windows.VerticalAlignment.Stretch}; 

//Create a seperate thread to load the image 
ThreadStart thread = delegate 
    { 
     //Load the image in a seperate thread 
     BitmapImage bmpImage = new BitmapImage(); 
     MemoryStream ms = new MemoryStream(); 

     //A custom class that reads the bytes of off the HD and shoves them into the MemoryStream. You could just replace the MemoryStream with something like this: FileStream fs = File.Open(@"C:\ImageFileName.jpg", FileMode.Open); 
     MediaCoder.MediaDecoder.DecodeMediaWithStream(ImageItem, true, ms); 

     bmpImage.BeginInit(); 
     bmpImage.StreamSource = ms; 
     bmpImage.EndInit(); 

     //**THIS LINE locks the BitmapImage so that it can be transported across threads!! 
     bmpImage.Freeze(); 

     //Call the UI thread using the Dispatcher to update the Image control 
     Dispatcher.BeginInvoke(new ThreadStart(delegate 
       { 
         img.Source = bmpImage; 
         img.Unloaded += delegate 
           { 
             ms.Close(); 
             ms.Dispose(); 
           }; 

          grdImageContainer.Children.Add(img); 
        })); 

    }; 

//Start previously mentioned thread... 
new Thread(thread).Start(); 
+7

BackgroundWorker se define en el espacio de nombres System.ComponentModel de System.dll, no en Windows Forms, por lo que está bien usarlo para WPF. –

+0

Usar BackgroundWorker o ThreadStart usa demasiado código. Solo eche un 'ThreadPool.QueueUserWorkItem (_ => {...})' y allí está su hilo; – SandRock

2
BitmapCacheOption.OnLoad 

var bmp = await System.Threading.Tasks.Task.Run(() => 
{ 
BitmapImage img = new BitmapImage(); 
img.BeginInit(); 
img.CacheOption = BitmapCacheOption.OnLoad; 
img.UriSource = new Uri(path); 
img.EndInit(); 
ImageBrush brush = new ImageBrush(img); 

} 
1

Esto le permitirá crear la BitmapImage en el hilo de interfaz de usuario mediante el uso de la HttpClient a hacer la descarga asíncrona:

private async Task<BitmapImage> LoadImage(string url) 
{ 
    HttpClient client = new HttpClient(); 

    try 
    { 
     BitmapImage img = new BitmapImage(); 
     img.CacheOption = BitmapCacheOption.OnLoad; 
     img.BeginInit(); 
     img.StreamSource = await client.GetStreamAsync(url); 
     img.EndInit(); 
     return img; 
    } 
    catch (HttpRequestException) 
    { 
     // the download failed, log error 
     return null; 
    } 
} 
Cuestiones relacionadas