В WPF ListBox больше чем с 1 000 Объектов Изображения Изображения Масштабирования становятся медленными

В PowerPoint презентации мастер назван так, как его тема. Мы можем получить все мастера, используя XMLSlideShow.getSlideMasters . XSLFSlideMaster расширяется XSLFSheet. Таким образом, мы можем получить тему каждого мастера, используя XSLFSheet.getTheme . Как только у нас есть XSLFTheme , для имени появляются геттеры и сеттеры.

Пример:

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.xslf.usermodel.*;

public class XSLFRenameMasterTheme {

 public static void main(String[] args) throws Exception {

  XMLSlideShow slideshow = new XMLSlideShow(new FileInputStream("Presentation.pptx"));

  for (XSLFSlideMaster master : slideshow.getSlideMasters()) {
   XSLFTheme theme = master.getTheme();
   String name = theme.getName();
System.out.println(name);
   theme.setName(name + " renamed");
System.out.println(theme.getName());
  }

  FileOutputStream out = new FileOutputStream("PresentationRenamedMaster.pptx");
  slideshow.write(out);
  out.close();
  slideshow.close();
 }
}

Для HSLFSlideShow кажется, что нет доступа к поддерживаемым именам мастеров. Можно получить HSLFSlideMaster с, но не их имена.

Так что, если, тем не менее, нужно это сделать, то нужно знать о внутренностях двоичной файловой системы *.ppt. Это описано в [MS-PPT]: формат двоичных файлов PowerPoint (.ppt) . Имена листов находятся в SlideNameAtom . Обладая знаниями о внутренностях, можно создать класс для такой записи. Это может обеспечить методы для получения и установки имени.

Пример:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.ByteArrayOutputStream;

import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RecordAtom;

import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;

public class HSLFRenameMaster {

 // method for get SlideNameAtom out of the master
 private static SlideNameAtom getSlideNameAtom(HSLFSlideMaster master) throws Exception {
  SlideNameAtom slideNameAtomRecord = null;
  Record record = master.getSheetContainer().findFirstOfType(0x0FBA);
  if (record != null) { // SlideNameAtom exists
   // get present data
   ByteArrayOutputStream out = new ByteArrayOutputStream();
   record.writeOut(out);
   out.flush();
   byte[] data = out.toByteArray();
   out.close();
   // create new SlideNameAtom from data
   slideNameAtomRecord = new SlideNameAtom(data);
   // replace old record with new SlideNameAtom
   master.getSheetContainer().addChildBefore(
    slideNameAtomRecord,
    record
   );
   master.getSheetContainer().removeChild(record);
  } 
  return slideNameAtomRecord;
 }


 public static void main(String[] args) throws Exception {

  HSLFSlideShow slideshow = new HSLFSlideShow(new FileInputStream("Presentation.ppt"));

  for (HSLFSlideMaster master : slideshow.getSlideMasters()) {
   SlideNameAtom slideNameAtomRecord = getSlideNameAtom(master);
   if (slideNameAtomRecord != null) {
    String name = slideNameAtomRecord.getName();
System.out.println(name);
    slideNameAtomRecord.setName(name + " renamed");
System.out.println(slideNameAtomRecord.getName());
   }
  }

  FileOutputStream out = new FileOutputStream("PresentationRenamedMaster.ppt");
  slideshow.write(out);
  out.close();
  slideshow.close();
 }

 //class SlideNameAtom 
 //having methods for manipulating the [SlideNameAtom](https://msdn.microsoft.com/en-us/library/dd906297(v=office.12).aspx)
 private static class SlideNameAtom extends RecordAtom {

  private byte[] data;
  private String name;

  public SlideNameAtom() {
   this.name = "Office";
   setName(name);
  }

  public SlideNameAtom(byte[] data) {
   this.data = data;
   this.name = getName();
  }

  public void setName(String name) {
   this.name = name;
   int length = 8;
   length += StringUtil.getToUnicodeLE(name).length;
   this.data = new byte[length];
   data[0] = (byte)0x20; data[1] = (byte)0x00; 
   data[2] = (byte)0xBA; data[3] = (byte)0x0F; //MUST be 0x0fba = RT_CString (little endian)
   LittleEndian.putInt(data, 4, StringUtil.getToUnicodeLE(name).length);
   StringUtil.putUnicodeLE(name, data, 8);
  }

  public String getName() {
   return StringUtil.getFromUnicodeLE(this.data, 8, (this.data.length-8)/2);
  }

  @Override
  public void writeOut(OutputStream out) throws IOException {
   out.write(data);
  }

  @Override
  public long getRecordType() { return 0x0FBA; }
 }

}

Вопрос в том, стоит ли переименование мастера.

12
задан user25749 8 October 2008 в 14:24
поделиться

6 ответов

Проблема состоит в том, что Вашей новой Панелью Расположения является WrapPanel, и это не поддерживает Виртуализацию! Возможно создать Ваш собственный Виртуализированный WrapPanel... Читайте больше здесь

Также считайте больше о других проблемах как реализация IScrollInfo здесь

Я также настоятельно рекомендую, чтобы Ваш не создавали новый шаблон управления только для замены панели расположения... Скорее сделайте следующее:

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

Преимущество выполнения этого состоит в том, что Вы не должны переносить свое поле списка в scrollviewer!

[ОБНОВЛЕНИЕ] Также прочитало эту статью Josh Smith! Чтобы заставить WrapPanel перенести... Вас также должны не забыть отключать горизонтальную прокрутку...

<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
6
ответ дан 2 December 2019 в 21:24
поделиться

попытайтесь виртуализировать свой stackpael с VirtualizingStackPanel. IsVirtualizing = "Истинное" приложенное свойство. это должно увеличить производительность.

использование поля списка со многими объектами в scrollviewer является другой известной проблемой производительности в wpf., если Вы можете, попытаться избавиться от scrollviewer.

если Ваши itemtemplates являются видом комплекса, необходимо рассмотреть использование Переработки VirtualizationMode., это говорит полю списка снова использовать существующие объекты и не создавать новые все время.

1
ответ дан 2 December 2019 в 21:24
поделиться

Часть проблемы - то, что она загружает полный образ в каждом. Необходимо использовать IValueConverter открыть каждое изображение в размере миниатюры путем установки любого DecodePixelWidth или DecodePixelHeight свойства на BitmapImage. Вот пример, который я использую в одном из моих проектов...

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();
    }

}
1
ответ дан 2 December 2019 в 21:24
поделиться

Я рекомендовал бы не связать свойство Width/Height каждого отдельного изображения, а скорее Вы связываете LayoutTransform на ItemsPanel ListBox. Что-то как:

<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>
2
ответ дан 2 December 2019 в 21:24
поделиться

На что похож Ваш стиль PhotoListBoxStyle? Если это изменяет ItemsPanelTemplate ListBox затем существует хороший шанс, Ваш ListBox не использует VirtualizingStackPanel в качестве своей базовой панели списка. Невиртуализированные ListBoxes намного медленнее со многими объектами.

0
ответ дан 2 December 2019 в 21:24
поделиться
  1. Я не знаком с этим компонентом, но в целом там будет ограничениями на количество объектов, которые поле списка может отобразить когда-то.

  2. Метод для решения этого вида проблемы должен сохранить количество изображений загруженным в управлении в числе, которое управление может отобразить на приемлемых уровнях производительности. Два метода, чтобы сделать это - подкачка страниц или динамическая загрузка.

В подкачке страниц Вы добавляете средства управления для переключения между дискретными блоками изображений, например, 100 за один раз, с вперед и стрелки назад, подобные перешедшим записям базы данных.

С динамической загрузкой Вы реализуете подкачку страниц негласно таким способом, которым, когда пользователь прокручивает в конец, приложение автоматически загружается в следующем пакете изображений и потенциально даже удаляет пакет старых для хранения скорости отклика разумной. Может быть маленькая пауза, поскольку это происходит и может быть некоторая работа, включенная для удержания контроль в надлежащей точке прокрутки, но это может быть приемлемым компромиссом.

3
ответ дан 2 December 2019 в 21:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: