R
@μ: Super danke:
Durch rumpropieren bin ich jetzt schließlich auf:
Label tile = new Label();
tile.AutoScrollOffset = new Point(position.X * 256, position.Y * 256 );
tile.Location = new Point(position.X * 256 + AutoScrollPosition.X, position.Y * 256 + AutoScrollPosition.Y);
gekommen und es funktioniert.
So mein Beispielcode (ein klein wenig komplizierter wegen Cache:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
namespace Test
{
public partial class Form1 : Form
{
private readonly PointCache<Label> cache;
public Form1()
{
AutoScroll = true;
AutoScrollMinSize = new System.Drawing.Size(10000, 10000);
cache = new PointCache<Label>(ctor, dtor);
cache.Enabled = true;
InitializeComponent();
Scroll += new ScrollEventHandler(FormScrolled);
Resize += new EventHandler(FormResized);
UpdateCache();
}
private void FormResized(object sender, EventArgs e)
{
UpdateCache();
}
private Point lastAutoScrollPosition = Point.Empty;
private void FormScrolled(object sender, ScrollEventArgs e)
{
if (AutoScrollPosition != lastAutoScrollPosition)
{
UpdateCache();
lastAutoScrollPosition = AutoScrollPosition;
}
}
private void UpdateCache()
{
// Basd scho
Size client = ClientSize;
Point scroll = AutoScrollPosition;
scroll = new Point(-scroll.X, -scroll.Y);
int vx = scroll.X / 256, vy = scroll.Y / 256;
Point offset = new Point(scroll.X % 256, scroll.Y % 256);
int vw = (client.Width + offset.X + 255) / 256, vh = (client.Height + offset.Y + 255) / 256;
Rectangle rect = new Rectangle(vx, vy, vw, vh);
if (cache.Bounds != rect)
{
Console.WriteLine("= {0} : {1} ; {2} : {3}", vx, vy, vw, vh);
cache.Bounds = rect;
Console.WriteLine("#{0}", Controls.Count);
}
}
// Wird aufgerufen, wenn eine Kachel an diesem Punkt erstellt werden soll.
Label ctor(Point position)
{
Label tile = new Label();
tile.AutoScrollOffset = new Point(position.X * 256, position.Y * 256 );
tile.Location = new Point(position.X * 256 + AutoScrollPosition.X, position.Y * 256 + AutoScrollPosition.Y);
tile.BackColor = SystemColors.ControlDarkDark;
tile.BorderStyle = BorderStyle.Fixed3D;
tile.Text = position.ToString();
tile.Size = new Size(256, 256);
tile.TextAlign = ContentAlignment.MiddleCenter;
Console.WriteLine("+ Key: " + position);
Controls.Add(tile);
return tile;
}
void dtor(Point p, Label l)
{
Console.WriteLine("- Key: " + p);
Controls.Remove(l);
}
}
public class PointCache<T> : IDisposable, IEnumerable<KeyValuePair<Point, T>>
{
private Func<Point, T> ctor;
private Action<Point, T> dtor;
private readonly IDictionary<Point, T> cache = new Dictionary<Point, T>();
private Rectangle cacheBounds = Rectangle.Empty;
private bool enabled;
public PointCache(Func<Point, T> initializer, Action<Point, T> deinitializer)
{
if (initializer == null)
throw new ArgumentNullException("initializer");
if (deinitializer == null)
throw new ArgumentNullException("deinitializer");
ctor = initializer;
dtor = deinitializer;
}
public Boolean Enabled
{
get
{
return enabled;
}
set
{
if (enabled != value)
{
enabled = value;
if (!enabled)
Clear();
else
{
// recalculate all Elements
Rectangle r = cacheBounds;
cacheBounds = Rectangle.Empty;
Bounds = r;
}
}
}
}
private void CheckObjectDisposed()
{
if (ctor == null || dtor == null)
throw new ObjectDisposedException("RegionCache");
}
public Rectangle Bounds
{
get
{
return cacheBounds;
}
set
{
CheckObjectDisposed();
if (!Enabled)
return;
if (value != cacheBounds)
{
Rectangle i = Rectangle.Intersect(cacheBounds, value);
// Das ginge bestimmt besser
for (int y = cacheBounds.Top; y < cacheBounds.Bottom; y++)
for (int x = cacheBounds.Left; x < cacheBounds.Right; x++)
{
Point v = new Point(x, y);
if (!i.Contains(v))
{
T result = cache[v];
cache.Remove(v);
dtor(v, result);
}
}
for (int y = value.Top; y < value.Bottom; y++)
for (int x = value.Left; x < value.Right; x++)
{
Point v = new Point(x, y);
if (!i.Contains(v))
{
cache[v] = ctor(v);
}
}
cacheBounds = value;
}
}
}
public T this[Point index]
{
get
{
return Enabled ? cache[index] : default(T);
}
}
public void Clear()
{
CheckObjectDisposed();
foreach (var entry in cache)
{
dtor(entry.Key, entry.Value);
}
cache.Clear();
cacheBounds = Rectangle.Empty;
}
#region IDisposable Member
public void Dispose()
{
Clear();
Enabled = false;
if (ctor != null)
ctor = null;
if (dtor != null)
dtor = null;
}
#endregion
#region IEnumerable<KeyValuePair<Vector2i,T>> Member
public IEnumerator<KeyValuePair<Point, T>> GetEnumerator()
{
return cache.GetEnumerator();
}
#endregion
#region IEnumerable Member
IEnumerator IEnumerable.GetEnumerator()
{
return cache.GetEnumerator();
}
#endregion
}
}
(Dieses Projekt läuft als Konsolenanwendung, Console.WriteLine für Debugausgaben (finde ich ebsser als das Konsolenfenster von VS)
falls Fragen bitte stellen, Verbesserungsvorschläge werden gerne genommen