Did you override MeasureOverride in your custom Canvas? Canvas will always report a DesiredSize of (0, 0), so the ScrollViewer will never think it needs to scroll.
See this StackOverflow answer which suggests using a Grid instead of a Canvas and using the Margin property for positioning. The Grid will report its size based on the size and position of its children, so the ScrollViewer will know it needs to scroll.
Update:
ScrollViewer will give its child ask much size as it asks for, and will only need to scroll if the child is larger than the ScrollViewer. In order to have it scroll properly, you'll need to report a DesiredSize that is large enough to include all of your child controls. You can do that by overriding MeasureOverride like this:
protected override Size MeasureOverride(Size constraint)
{
base.MeasureOverride(constraint);
var desiredSize = new Size();
foreach (UIElement child in Children)
{
desiredSize = new Size(
Math.Max(desiredSize.Width, GetLeft(child) + child.DesiredSize.Width),
Math.Max(desiredSize.Height, GetTop(child) + child.DesiredSize.Height));
}
return desiredSize;
}
An easier solution, however, is to take advantage of the fact that the Grid class will already measure like this. You can use the Margin property of the child elements to position them exactly instead of the Canvas.Left and Canvas.Top properties. If you are currently doing
Canvas.SetLeft(item, 100);
Canvas.SetTop(item, 200);
for an item in the Canvas, you could instead do
item.Margin = new Thickness(100, 200, 0, 0);
to position it in the same place within a one-cell Grid.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…