WPF: Как быстро загрузить много больших изображений в оболочку? - PullRequest
6 голосов
/ 01 июля 2010

У меня есть около 45 прилично больших изображений (около 680x1000), которые нужно загрузить в простой пользовательский элемент управления (закругленный задний край с заливкой, изображением, текстовым блоком и 2 боковыми прямоугольниками), а затем отобразить в виде обертки. Виртуализация не очень поможет, так как все изображения должны быть видны при загрузке программы.

Я знаю, что внутри инициализации BitmapImage я могу установить ширину decodepixel, что немного помогает, однако я хотел бы загрузить их все в полном размере, так как я хочу иметь возможность изменять размер изображений с помощью ползунка без потери качества (это часть работает быстро по большей части). Я знаю, что одна возможность - установить ширину декодирования, равную некоторому числу, которое я могу установить, поскольку максимальный видимый размер может помочь.

Я попробовал многопоточный подход, найденный в Как загрузить изображения в фоновом режиме? (первый ответ), однако это привело к тому, что программа загружалась намного дольше!

Есть идеи?

Текущий код загрузки:

BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
//bmp.DecodePixelWidth = 400;
bmp.UriSource = new Uri(file.FullName);
bmp.EndInit();
bmp.Freeze();
images.Add(bmp);

Пример кода XAML:

        <Border x:Name="backBorder" Background="Black" Padding="2" Margin="3" CornerRadius="3,3,4,4" 
            BorderBrush="Black" BorderThickness="1"
            MouseEnter="backBorder_MouseEnter" MouseLeave="backBorder_MouseLeave" MouseLeftButtonUp="backBorder_MouseLeftButtonUp" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="16" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="15" />
        </Grid.ColumnDefinitions>
        <Image x:Name="imageBox" Stretch="Fill" Width="{Binding Path=ImageWidth, ElementName=me}" Height="{Binding Path=ImageHeight, ElementName=me}" />
        <Border x:Name="backRatingBorder" Grid.Column="1" Margin="3,0,0,0" BorderBrush="Blue" Background="White" BorderThickness="1"/>
        <Border x:Name="frontRatingBorder" Grid.Column="1" Margin="3,0,0,0" BorderBrush="Blue" Background="LightBlue" BorderThickness="1" VerticalAlignment="Bottom" Height="50"/>
        <TextBlock x:Name="textBlock" Grid.Row="1" Grid.ColumnSpan="2" TextAlignment="Center" Background="Transparent" Foreground="White" FontFamily="Segoe UI" FontWeight="SemiBold" FontSize="12" />
   </Grid>
</Border>

.

UPDATE:

Что ж, в итоге я сделал его более отзывчивым, запустив цикл загрузки изображения в одном фоновом режиме. После загрузки каждого изображения вызывается Dispacher.Invoke для создания элемента обтекания. Поработав с ним некоторое время, я заставил его показать каждый элемент, созданный в то же время, что и раньше.

1 Ответ

1 голос
/ 01 июля 2010

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

В качестве альтернативы, если вы загружаете все ваши изображения в цикле, вы можете попробовать улучшенную версию метода Windows Forms DoEvents (прокрутите вниз до примера). Вы бы назвали это после загрузки каждого изображения, и это даст интерфейсу возможность обновляться (процесс взаимодействия с пользователем и т. Д.). Именно этот подход я использовал при загрузке фрагментов карты для своего проекта, и он проще, чем первый.

...