2009-02-20 22 views
45

Tôi có vấn đề lạ với WPF, tôi đã tải hình ảnh từ đĩa lúc chạy và thêm chúng vào vùng chứa StackView. Tuy nhiên, hình ảnh không được hiển thị. Sau một vài lần gỡ lỗi, tôi đã tìm được thủ thuật, nhưng nó thực sự không có ý nghĩa gì cả. Tôi đã thực hiện một ứng dụng demo nhỏ để xác định các vấn đề:Tải ảnh động trong WPF

Tạo một dự án WPF mới, và dán mã như sau:

XAML:

<Window x:Class="wpfBug.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300" Loaded="Window_Loaded"> 
    <StackPanel Name="sp"> 
    </StackPanel> 
</Window> 

xaml.cs, dán dưới usings mặc định :

namespace wpfBug 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
     } 

     private void Window_Loaded(object sender, RoutedEventArgs e) 
     { 
      Image i = new Image(); 
      BitmapImage src = new BitmapImage(); 
      src.BeginInit(); 
      src.UriSource = new Uri("picture.jpg", UriKind.Relative); 
      src.EndInit(); 
      i.Source = src; 
      i.Stretch = Stretch.Uniform; 
      //int q = src.PixelHeight;  // Image loads here 
      sp.Children.Add(i); 
     } 
    } 
} 

Sao chép một hình ảnh vào thư mục bin/Debug và gọi nó là 'picture.jpg'

Chương trình này không hiển thị bất cứ điều gì, trừ khi dòng chú thích không được chú ý.

Bất cứ ai có thể giải thích những gì tôi đang làm sai hay tại sao điều này xảy ra? Nếu bạn loại bỏ hình ảnh và chạy chương trình nó tạo ra một ngoại lệ trên dòng 'int q = ...'. Nếu dòng đó được nhận xét thì chương trình sẽ chạy mà không có ngoại lệ ngay cả khi không có hình ảnh nào. Chỉ tải hình ảnh nếu nessesary có ý nghĩa, nhưng sau đó hình ảnh sẽ được tải khi tôi thêm điều khiển Hình ảnh vào StackPanel.

Mọi id?

Chỉnh sửa: Nhân tiện, nếu bạn thêm hình ảnh làm tài nguyên, thì dòng 'int q = ..' là không cần thiết.

Trả lời

90

Đó là do quá trình tạo đã bị trì hoãn. Nếu bạn muốn hình ảnh được tải ngay lập tức, bạn có thể chỉ cần thêm mã này vào giai đoạn init.

src.CacheOption = BitmapCacheOption.OnLoad;

như thế này:

src.BeginInit(); 
src.UriSource = new Uri("picture.jpg", UriKind.Relative); 
src.CacheOption = BitmapCacheOption.OnLoad; 
src.EndInit(); 
+2

Tôi đã thử nghiệm điều này và nó hoạt động. Điều này tuy nhiên chứng minh rằng có một lỗi trong khuôn khổ, bởi vì nếu bạn thiết lập CacheOption để OnDemand hình ảnh không bao giờ được tải ngay cả khi nó phải được nạp trước khi beeing hiển thị trên màn hình. Cảm ơn cho tip, tôi đã không nhận thấy rằng tài sản. +1;) –

+0

Giúp tôi quá :) –

+0

... và tôi cũng vậy :) –

6

Đây là hành vi lạ và mặc dù tôi không thể nói tại sao điều này xảy ra, tôi có thể đề xuất một số tùy chọn.

Thứ nhất, quan sát. Nếu bạn bao gồm các hình ảnh như nội dung trong VS và sao chép nó vào thư mục đầu ra, mã của bạn hoạt động. Nếu hình ảnh được đánh dấu là Không có trong VS và bạn sao chép nó qua, nó không hoạt động.

Giải pháp 1: FileStream

Đối tượng BitmapImage chấp nhận UriSource hoặc StreamSource làm tham số. Hãy sử dụng StreamSource để thay thế.

 FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read); 
     Image i = new Image(); 
     BitmapImage src = new BitmapImage(); 
     src.BeginInit(); 
     src.StreamSource = stream; 
     src.EndInit(); 
     i.Source = src; 
     i.Stretch = Stretch.Uniform; 
     panel.Children.Add(i); 

Sự cố: luồng vẫn mở. Nếu bạn đóng nó ở cuối của phương pháp này, hình ảnh sẽ không hiển thị. Điều này có nghĩa là tập tin vẫn được ghi khóa trên hệ thống.

Giải pháp 2: MemoryStream

này về cơ bản là giải pháp 1 nhưng bạn đọc các tập tin vào một dòng bộ nhớ và vượt qua mà dòng bộ nhớ như là đối số.

 MemoryStream ms = new MemoryStream(); 
     FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read); 
     ms.SetLength(stream.Length); 
     stream.Read(ms.GetBuffer(), 0, (int)stream.Length); 

     ms.Flush(); 
     stream.Close(); 

     Image i = new Image(); 
     BitmapImage src = new BitmapImage(); 
     src.BeginInit(); 
     src.StreamSource = ms; 
     src.EndInit(); 
     i.Source = src; 
     i.Stretch = Stretch.Uniform; 
     panel.Children.Add(i); 

Bây giờ bạn có thể sửa đổi tệp trên hệ thống, nếu đó là thứ bạn yêu cầu.

0

Bạn có thể thử gắn xử lý các sự kiện khác nhau của BitmapImage:

Họ có thể cho bạn biết một chút về những gì đang xảy ra, càng xa càng hình ảnh có liên quan.

+0

Tôi đã thử rằng, không có sự kiện nào được kích hoạt. Tôi đang sử dụng cùng một hình ảnh cho tất cả các bài kiểm tra, vì vậy không có gì vặn vẹo với hình ảnh btw;) –

9

Trong mã để tải tài nguyên trong lắp ráp thực hiện nơi hình ảnh của tôi 'Freq.png' là trong thư mục "biểu tượng" và định nghĩa là "tài nguyên".

 this.Icon = new BitmapImage(new Uri(@"pack://application:,,,/" 
      + Assembly.GetExecutingAssembly().GetName().Name 
      + ";component/" 
      + "Icons/Freq.png", UriKind.Absolute)); 

tôi cũng thực hiện một chức năng nếu ai muốn nó ...

/// <summary> 
/// Load a resource WPF-BitmapImage (png, bmp, ...) from embedded resource defined as 'Resource' not as 'Embedded resource'. 
/// </summary> 
/// <param name="pathInApplication">Path without starting slash</param> 
/// <param name="assembly">Usually 'Assembly.GetExecutingAssembly()'. If not mentionned, I will use the calling assembly</param> 
/// <returns></returns> 
public static BitmapImage LoadBitmapFromResource(string pathInApplication, Assembly assembly = null) 
{ 
    if (assembly == null) 
    { 
     assembly = Assembly.GetCallingAssembly(); 
    } 

    if (pathInApplication[0] == '/') 
    { 
     pathInApplication = pathInApplication.Substring(1); 
    } 
    return new BitmapImage(new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component/" + pathInApplication, UriKind.Absolute)); 
} 

Cách sử dụng:

 this.Icon = ResourceHelper.LoadBitmapFromResource("Icons/Freq.png"); 
+0

giải pháp của bạn là cảm ơn chuyên nghiệp hơn –

0

Đây là phương pháp khuyến nông để tải một hình ảnh từ URI:

public static BitmapImage GetBitmapImage(
    this Uri imageAbsolutePath, 
    BitmapCacheOption bitmapCacheOption = BitmapCacheOption.Default) 
{ 
    BitmapImage image = new BitmapImage(); 
    image.BeginInit(); 
    image.CacheOption = bitmapCacheOption; 
    image.UriSource = imageAbsolutePath; 
    image.EndInit(); 

    return image; 
} 

Mẫu sử dụng:

Uri _imageUri = new Uri(imageAbsolutePath); 
ImageXamlElement.Source = _imageUri.GetBitmapImage(BitmapCacheOption.OnLoad); 

Đơn giản như vậy!

Các vấn đề liên quan