2008-10-08 16 views
12

Tôi gặp sự cố khi bỏ qua ứng dụng trình xem ảnh. Tôi sử dụng ListBox để hiển thị hình ảnh, được chứa trong ObservableCollection. Tôi ràng buộc ItemSource của ListBox với ObservableCollection.Trong Hộp danh sách WPF có hơn 1000 mục hình ảnh, hình thu nhỏ trở nên chậm

<DataTemplate DataType="{x:Type modeldata:ImageInfo}"> 
     <Image 
      Margin="6" 
      Source="{Binding Thumbnail}" 
      Width="{Binding ZoomBarWidth.Width, Source={StaticResource zoombarmanager}}" 
      Height="{Binding ZoomBarWidth.Width, Source={StaticResource zoombarmanager}}"/> 
    </DataTemplate> 

<Grid DataContext="{StaticResource imageinfolder}"> 
    <ScrollViewer 
     VerticalScrollBarVisibility="Auto" 
     HorizontalScrollBarVisibility="Disabled"> 
     <ListBox Name="PhotosListBox" 
      IsSynchronizedWithCurrentItem="True" 
      Style="{StaticResource PhotoListBoxStyle}" 
      Margin="5" 
      SelectionMode="Extended" 
      ItemsSource="{Binding}" 
      /> 
    </ScrollViewer> 

Tôi cũng ràng buộc Image'height trong ListBox bằng thanh trượt. (Giá trị của thanh trượt cũng liên kết với zoombarmanager.ZoomBarWidth.Width). Nhưng tôi thấy nếu bộ sưu tập trở nên lớn hơn, chẳng hạn như: chứa nhiều hơn 1000 hình ảnh, Nếu tôi sử dụng thanh trượt để thay đổi kích thước của iamges, nó sẽ trở thành một chút chậm. Câu hỏi của tôi là. 1. Tại sao nó trở nên Chậm? trở thành nó cố gắng thu phóng mọi hình ảnh, hoặc nó chỉ vì thông báo ("Chiều rộng") được gọi hơn 1000 lần. 2. Có phương pháp nào để giải quyết loại vấn đề này và làm cho nó nhanh hơn không.

Các PhotoListBoxStyle là như thế này:

<Style~~ TargetType="{x:Type ListBox}" x:Key="PhotoListBoxStyle"> 
     <Setter Property="Foreground" Value="White" /> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type ListBox}" > 
        <WrapPanel 
         Margin="5" 
         IsItemsHost="True" 
         Orientation="Horizontal" 
         VerticalAlignment="Top"        
         HorizontalAlignment="Stretch" /> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style~~> 

Nhưng Nếu tôi sử dụng Style ở trên, tôi phải sử dụng ScrollViewer ngoài ListBox, nếu không tôi không có ý tưởng làm thế nào để có được một scrollerbar di chuyển mượt mà và wrappanel dường như có không có thanh cuộn mặc định. Bất cứ ai giúp đỡ? Người ta nói listbox với scrollviewer có hiệu suất kém.

+0

Binding Chiều cao của mỗi hình ảnh/Width là khủng khiếp không hiệu quả, chỉ cần sử dụng một LayoutTransform trên ItemsPanel (câu trả lời thêm vào hiệu ứng này) . – user7116

Trả lời

6

Vấn đề là Bảng điều khiển bố cục mới của bạn là WrapPanel và nó không hỗ trợ ảo hóa! Nó có thể tạo riêng ảo hóa WrapPanel của bạn ... Read more here

Cũng đọc thêm về các vấn đề khác như việc thực hiện IScrollInfo here

Tôi cũng khuyên bạn không tạo ra một mẫu điều khiển mới chỉ để thay thế bảng điều khiển bố cục ... Thay vào đó hãy làm như sau:

<ListBox.ItemsPanel> 
    <ItemsPanelTemplate> 
     <WrapPanel Orientation="Horizontal"/> 
    </ItemsPanelTemplate> 
</ListBox.ItemsPanel> 

Lợi thế của việc này là bạn không cần phải bọc hộp danh sách trong trình xem ảnh!

[CẬP NHẬT] Đồng thời đọc this bài viết của Josh Smith! Để thực hiện các bọc WrapPanel ... bạn cũng phải nhớ để vô hiệu hóa cuộn ngang ...

<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" /> 
+1

Rudigrobler thân mến, bạn đã thử ứng dụng này và làm cho nó mở một thư mục chứa 10000 hình ảnh? Tôi đã cố gắng, và performace là khủng khiếp khi thay đổi kích thước cửa sổ chính. Tôi nghĩ rằng nó có thể là một giải pháp tốt cho hàng trăm hình ảnh, nhưng đối với hình ảnh số lượng lớn hơn, listbox không thể xử lý nó. – user25749

+0

Tôi thay đổi dòng robotImages.Add trong mẫu của Josh Smith thành robotImages.Add (BitmapFrame.Create (uri) .Thumbnail); và tạo thư mục chứa mười nghìn hình ảnh. Sau khi hình ảnh được tải, thay đổi kích thước là thời gian comusing. – user25749

+0

Mẫu được mô tả trong http://www.codeproject.com/KB/WPF/CustomListBoxLayoutInWPF.aspx – user25749

3
  1. Tôi không quen với thành phần này, nhưng nói chung sẽ có giới hạn về số lượng mục mà một hộp danh sách có thể hiển thị cùng một lúc.

  2. Phương pháp giải quyết loại sự cố này là giữ số lượng hình ảnh được tải trong điều khiển trong số điều khiển có thể hiển thị ở mức hiệu suất được chấp nhận. Hai kỹ thuật để làm điều này là phân trang hoặc tải động.

Trong phân trang, bạn thêm điều khiển để chuyển đổi giữa các khối riêng biệt của ảnh, ví dụ: 100 tại một thời điểm, với mũi tên tiến và lùi, tương tự như điều hướng các bản ghi cơ sở dữ liệu.

Với tải động, bạn thực hiện phân trang đằng sau hậu trường theo cách mà khi người dùng cuộn đến cuối, ứng dụng sẽ tự động tải trong loạt ảnh tiếp theo và thậm chí có thể xóa hàng loạt cũ để giữ đáp ứng hợp lý. Có thể có một tạm dừng nhỏ vì điều này xảy ra và có thể có một số công việc liên quan đến việc giữ quyền kiểm soát tại điểm cuộn thích hợp, nhưng điều này có thể là một sự cân bằng chấp nhận được.

+0

Cảm ơn bạn Tôi nghĩ rằng phương pháp này hoạt động nhưng có lẽ rất nhiều công việc cần được thực hiện. Cảm ơn bạn! – user25749

0

Phong cách PhotoListBoxStyle của bạn trông như thế nào? Nếu nó thay đổi ItemPanelTemplate của ListBox thì có một cơ hội tốt là ListBox của bạn không sử dụng VirtualizingStackPanel làm bảng danh sách cơ bản của ListBox. Các ListBox không được ảo hóa sẽ chậm hơn rất nhiều với nhiều mục.

+0

Tôi thêm nó ngay bây giờ, bạn có một số ý tưởng làm thế nào để cải thiện nó? Cảm ơn bạn! – user25749

1

cố gắng ảo hóa stackpael của bạn với thuộc tính đính kèm VirtualizingStackPanel.IsVirtualizing = "True". điều này sẽ tăng hiệu suất.

sử dụng hộp danh sách có nhiều mục trong trình xem cuộn là một vấn đề hiệu suất đã biết khác trong wpf. nếu bạn có thể, hãy cố gắng loại bỏ scrollviewer.

nếu mục hàng của bạn phức tạp, bạn nên cân nhắc sử dụng Mã hóa tái chế. điều này sẽ cho hộp danh sách của bạn sử dụng lại các đối tượng hiện có và không tạo các đối tượng mới mọi lúc.

1

Một phần của sự cố là nó đang tải hình ảnh đầy đủ trong mỗi.Bạn phải sử dụng IValueConverter để mở từng hình ảnh ở kích thước hình thu nhỏ bằng cách đặt thuộc tính DecodePixelWidth hoặc DecodePixelHeight trên số BitmapImage. Dưới đây là một ví dụ tôi sử dụng trong một dự án của tôi ...

class PathToThumbnailConverter : IValueConverter { 
    public int DecodeWidth { 
     get; 
     set; 
    } 

    public PathToThumbnailConverter() { 
     DecodeWidth = 200; 
    } 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { 
     var path = value as string; 

     if (!string.IsNullOrEmpty(path)) { 

      FileInfo info = new FileInfo(path); 

      if (info.Exists && info.Length > 0) { 
       BitmapImage bi = new BitmapImage(); 

       bi.BeginInit(); 
       bi.DecodePixelWidth = DecodeWidth; 
       bi.CacheOption = BitmapCacheOption.OnLoad; 
       bi.UriSource = new Uri(info.FullName); 
       bi.EndInit(); 

       return bi; 
      } 
     } 

     return null; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { 
     throw new NotImplementedException(); 
    } 

} 
2

tôi sẽ khuyên bạn không ràng buộc tài sản Width/Height của mỗi hình ảnh cá nhân, mà là bạn liên kết một LayoutTransform trên ListBox của ItemsPanel. Một cái gì đó như:

<ListBox.ItemsPanel> 
    <ItemsPanelTemplate> 
     <StackPanel> 
     <StackPanel.LayoutTransform> 
      <ScaleTransform 
       ScaleX="{Binding Path=Value, ElementName=ZoomSlider}" 
       ScaleY="{Binding Path=Value, ElementName=ZoomSlider}" /> 
     </StackPanel.LayoutTransform> 
     </StackPanel> 
    </ItemsPanelTemplate> 
</ListBox.ItemsPanel> 
+0

Cảm ơn bạn sixlettervariables, tôi nghĩ rằng từ của bạn có ý nghĩa! Tôi sẽ thử nó! – user25749

+0

Tôi thấy nó vẫn còn rất chậm. – user25749

+0

Kết hợp sáu bản biến và câu trả lời của rudigrobler, vấn đề được giải quyết! Cảm ơn! Tôi đã phạm sai lầm trước đây, giải pháp của bạn là đúng! Cảm ơn bạn! – user25749