Winforms действительно не подходит для такого рода вещей ... Используя стандартные элементы управления, вам, вероятно, нужно либо подготовить все поля изображений заранее и загрузить изображения по мере их появления, либо управлять заполнителем переполнения для подходящей длины, чтобы полосы прокрутки работали.
Предполагая, что Winforms - единственный вариант, я бы посоветовал вам создать собственный элемент управления с полосой прокрутки и вручную запустить событие OnPaint .
Это позволило бы вам сохранить кэш изображений в памяти для рисования текущего вида [и нескольких с обеих сторон], в то же время предоставляя вам полный контроль над их загрузкой / выгрузкой [ну, как «всего» как вы можете получить на управляемом языке - вам все еще может понадобиться настроить сборщик мусора]
Чтобы получить некоторые детали ....
Создать новый элемент управления
namespace SO61574511 {
// Let's inherit from Panel so we can take advantage of scrolling for free
public class ImageScroller : Panel {
// Some numbers to allow us to calculate layout
private const int BitmapWidth = 100;
private const int BitmapSpacing = 10;
// imageCache will keep the images in memory. Ideally we should unload images we're not using, but that's a problem for the reader
private Bitmap[] imageCache;
public ImageScroller() {
//How many images to put in the cache? If you don't know up-front, use a list instead of an array
imageCache = new Bitmap[100];
//Take advantage of Winforms scrolling
this.AutoScroll = true;
this.AutoScrollMinSize = new Size((BitmapWidth + BitmapSpacing) * imageCache.Length, this.Height);
}
protected override void OnPaint(PaintEventArgs e) {
// Let Winforms paint its bits (like the scroll bar)
base.OnPaint(e);
// Translate whatever _we_ paint by the position of the scrollbar
e.Graphics.TranslateTransform(this.AutoScrollPosition.X,
this.AutoScrollPosition.Y);
// Use this to decide which images are out of sight and can be unloaded
var current_scroll_position = this.HorizontalScroll.Value;
// Loop through the images you want to show (probably not all of them, just those close to the view area)
for (int i = 0; i < imageCache.Length; i++) {
e.Graphics.DrawImage(GetImage(i), new PointF(i * (BitmapSpacing + BitmapWidth), 0));
}
}
//You won't need a random, just for my demo colours below
private Random rnd = new Random();
private Bitmap GetImage(int id) {
// This method is responsible for getting an image.
// If it's already in the cache, use it, otherwise load it
if (imageCache[id] == null) {
//Do something here to load an image into the cache
imageCache[id] = new Bitmap(100, 100);
// For demo purposes, I'll flood fill a random colour
using (var gfx = Graphics.FromImage(imageCache[id])) {
gfx.Clear(Color.FromArgb(255, rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255)));
}
}
return imageCache[id];
}
}
}
И загрузите его в свою форму, закрепляя, чтобы заполнить экран ....
public Form1() {
InitializeComponent();
this.Controls.Add(new ImageScroller {
Dock = DockStyle.Fill
});
}
Вы можете увидеть это в действии здесь: https://www.youtube.com/watch?v=ftr3v6pLnqA (извините за следы мыши, я захваченный площадь за окном)