2008-08-31 31 views

Trả lời

3

Giả sử bạn đang sử dụng ràng buộc dữ liệu, hãy đặt thuộc tính Binding.IsAsync thành True có vẻ là cách tiêu chuẩn để đạt được điều này. Nếu bạn đang tải bitmap trong code-behind file sử dụng sợi nền + đối tượng Dispatcher là một cách phổ biến để cập nhật giao diện người dùng đồng bộ

+3

các BitmapImage phải được tạo ra trên UI chủ đề: điều này sẽ ném một ngoại lệ ... –

+1

@ Jmix90: nó không phải là rõ ràng những gì một phần của câu trả lời này, bạn đang đề cập đến. Tuy nhiên: sử dụng 'Binding.IsAsync' cho phép một đường dẫn Uri/được chỉ định trong' Image.Source' và tải hình ảnh một cách không đồng bộ một cách tự động. WPF sẽ xử lý bất kỳ vấn đề nào về chuỗi chéo trong kịch bản này. Nếu một người đang tạo bitmap trong một chủ đề nền, một trong những nhu cầu đơn giản là gọi 'Freeze()' trên đối tượng bitmap trước khi đưa nó vào chuỗi giao diện người dùng. Nó chỉ ném một ngoại lệ nếu bạn làm điều đó sai. –

0

Sử dụng hoặc mở rộng System.ComponentModel.BackgroundWorker:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Cá nhân, Tôi thấy đây là cách dễ nhất để thực hiện các hoạt động không đồng bộ trong ứng dụng khách. (Tôi đã sử dụng điều này trong WinForms, nhưng không WPF. Tôi giả định điều này sẽ làm việc trong WPF là tốt.)

Tôi thường mở rộng Backgroundworker, nhưng bạn không phải làm.

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 */ 
     } 
    } 
} 

Đây là cách bạn sẽ sử dụng nó trong hình thức của bạn:

//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

Để xây dựng lên câu trả lời aku của, đây là một ví dụ nhỏ như là nơi để thiết lập IsAsync:

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

Đó là những gì bạn sẽ làm trong XAML.

+0

Tôi không hiểu tại sao câu trả lời này có -1, vì đó chỉ là những gì tôi đang tìm kiếm! Không thể tìm ra cách thực hiện chuyển đổi async. Hóa ra bạn _just_ phải đưa vào IsAsync = Đúng trong ràng buộc của bạn. Cảm ơn nhiều! – Rasive

7

Tôi chỉ xem xét điều này và phải ném vào hai xu của mình, mặc dù một vài năm sau bài đăng gốc (chỉ trong trường hợp bất kỳ ai khác tìm kiếm cùng một thứ mà tôi đang xem).

Tôi có một ảnh kiểm soát mà cần phải có nó hình ảnh nạp trong nền sử dụng một Stream là, và sau đó hiển thị.

Vấn đề mà tôi vẫn tiếp tục chạy vào đó là các BitmapSource, nó Suối nguồn và ảnh kiểm soát tất cả phải được trên cùng một sợi.

Trong trường hợp này, bằng cách sử dụng một ràng buộc và thiết lập nó IsAsynch = true sẽ ném một ngoại lệ chủ đề chéo.

Một BackgroundWorker là tuyệt vời cho WinForms, và bạn có thể sử dụng trong WPF, nhưng tôi muốn tránh sử dụng các hội đồng WinForm trong WPF (bloating của một dự án không được khuyến khích, và nó là một nguyên tắc tốt quá). Điều này sẽ ném một ngoại lệ tham chiếu chéo không hợp lệ trong trường hợp này quá, nhưng tôi đã không kiểm tra nó.

Chỉ ra rằng một dòng mã sẽ làm cho bất kỳ các công việc:

//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 được định nghĩa trong System.ComponentModel không gian tên của System.dll, không phải trong Windows Forms, vì vậy nó là tốt để sử dụng nó cho WPF. –

+0

Sử dụng BackgroundWorker hoặc ThreadStart sử dụng quá nhiều mã. Chỉ cần ném một 'ThreadPool.QueueUserWorkItem (_ => {...})' và có chủ đề của bạn; – 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

này sẽ cho phép bạn tạo ra các BitmapImage trên thread UI bằng HttpClient để làm tải async:

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; 
    } 
} 
Các vấn đề liên quan