Мне нужен был WrapPanel, который может растягивать его содержимое, поэтому на основе https://stackoverflow.com/a/7747002/121122 и некоторой тряски я придумал это:
public class AlignableWrapPanel : Panel
{
public HorizontalAlignment HorizontalContentAlignment
{
get => (HorizontalAlignment)GetValue(HorizontalContentAlignmentProperty);
set => SetValue(HorizontalContentAlignmentProperty, value);
}
public static readonly DependencyProperty HorizontalContentAlignmentProperty = DependencyProperty.Register(
nameof(HorizontalContentAlignment),
typeof(HorizontalAlignment),
typeof(AlignableWrapPanel),
new FrameworkPropertyMetadata(HorizontalAlignment.Left, FrameworkPropertyMetadataOptions.AffectsArrange));
protected override Size MeasureOverride(Size constraint)
{
var curLineSize = new Size();
var panelSize = new Size();
var children = InternalChildren;
for (var i = 0; i < children.Count; i++)
{
var child = children[i];
// flow passes its own constraint to children
child.Measure(constraint);
var sz = child.DesiredSize;
if (curLineSize.Width + sz.Width > constraint.Width) // need to switch to another line
{
panelSize.Width = Math.Max(curLineSize.Width, panelSize.Width);
panelSize.Height += curLineSize.Height;
curLineSize = sz;
if (sz.Width > constraint.Width) // if the element is wider then the constraint - give it a separate line
{
panelSize.Width = Math.Max(sz.Width, panelSize.Width);
panelSize.Height += sz.Height;
curLineSize = new Size();
}
}
else // continue to add to the line
{
curLineSize.Width += sz.Width;
curLineSize.Height = Math.Max(sz.Height, curLineSize.Height);
}
}
// the last line size, if any need to be added
panelSize.Width = Math.Max(curLineSize.Width, panelSize.Width);
panelSize.Height += curLineSize.Height;
return panelSize;
}
protected override Size ArrangeOverride(Size arrangeBounds)
{
var firstInLine = 0;
var curLineSize = new Size();
var accumulatedHeight = 0D;
var children = InternalChildren;
for (var i = 0; i < children.Count; i++)
{
var desiredSize = children[i].DesiredSize;
if (curLineSize.Width + desiredSize.Width > arrangeBounds.Width) // need to switch to another line
{
ArrangeLine(accumulatedHeight, curLineSize, arrangeBounds.Width, firstInLine, i);
accumulatedHeight += curLineSize.Height;
curLineSize = desiredSize;
if(
desiredSize.Width > arrangeBounds.Width ||
children[i] is FrameworkElement element && element.HorizontalAlignment == HorizontalAlignment.Stretch)
{
// the element is wider then the constraint or it stretches - give it a separate line
ArrangeLine(accumulatedHeight, desiredSize, arrangeBounds.Width, i, ++i);
accumulatedHeight += desiredSize.Height;
curLineSize = new Size();
}
firstInLine = i;
}
else // continue to add to the line
{
curLineSize.Width += desiredSize.Width;
curLineSize.Height = Math.Max(desiredSize.Height, curLineSize.Height);
}
}
if (firstInLine < children.Count)
{
ArrangeLine(accumulatedHeight, curLineSize, arrangeBounds.Width, firstInLine, children.Count);
}
return arrangeBounds;
}
private void ArrangeLine(double y, Size lineSize, double boundsWidth, int start, int end)
{
var children = InternalChildren;
var x = 0D;
if (HorizontalContentAlignment == HorizontalAlignment.Center)
{
x = (boundsWidth - lineSize.Width) / 2;
}
else if (HorizontalContentAlignment == HorizontalAlignment.Right)
{
x = boundsWidth - lineSize.Width;
}
var stretchChildren = new List();
for (var i = start; i < end; i++)
{
var child = children[i];
if (child is FrameworkElement element && element.HorizontalAlignment == HorizontalAlignment.Stretch)
{
stretchChildren.Add(child);
}
}
var spaceAvailableForStretchChildren = boundsWidth - lineSize.Width;
var spaceAvailablePerStretchChild = 0D;
if (stretchChildren.Any())
{
x = 0; // all available space will be filled so start at 0
spaceAvailablePerStretchChild = spaceAvailableForStretchChildren / stretchChildren.Count;
spaceAvailablePerStretchChild = spaceAvailablePerStretchChild >= 0 ? spaceAvailablePerStretchChild : 0;
}
for (var i = start; i < end; i++)
{
var child = children[i];
double itemWidth;
if(stretchChildren.Contains(child))
{
itemWidth = child.DesiredSize.Width + spaceAvailablePerStretchChild;
}
else
{
itemWidth = child.DesiredSize.Width;
}
child.Arrange(new Rect(x, y, itemWidth, lineSize.Height));
x += itemWidth;
}
}
}
Определенно найдите хорошую службу доставки. Наиболее известен Akamai.
Если вы действительно хотите сделать это самостоятельно, забудьте об Apache / IIS. гораздо более подходящими являются «легкие» веб-серверы. Два очень хороших - это lighthttp и NginX ( wiki ). В частности, NginX имеет действительно солидную производительность.
Править : Сети распространения контента (CDN) процветают в последние несколько лет, и гораздо проще найти более простые и дешевые. В частности, довольно просто разместить статический контент в Amazon S3 и использовать CloudFront .
Если вы хотите создать самый быстрый веб-сервер статических файлов с наименьшей задержкой, вот как я бы это сделал.
По сути, это порты завершения ввода-вывода без кэширования файлов. Эта модель доступна в Windows и Solaris.
http://technet.microsoft.com/en-us/sysinternals/bb963891.aspx
(источник: microsoft.com )
С таким количеством клиентов, вы можете изучить возможность использования сети доставки контента (например, Akamai). На первый взгляд это может показаться дорогим, но если вы действительно посмотрите на стоимость обслуживания оборудования и, в частности, на стоимость полосы пропускания, это начинает иметь экономический смысл.
Как подавать изображения? Изображения генерируются на лету? или они статичны и хранятся в файловой системе как .jpg или другой формат?
В любом случае, я бы использовал ASP.NET .ashx (общие обработчики) и классы System.Drawing.
Вы будете также хотите настроить балансировку сетевой нагрузки TCP / IP для http://support.microsoft.com/kb/323431