1

我正在创建一个使用画布的垂直滚动游戏。虽然目前还没有性能问题,但我预计会有,因为我不相信画布本身就提供虚拟化。是否有类似于 VirtualStackPanel 的 VirtualCanvas 之类的东西?我想要相同的功能,它只绘制当前显示的内容。

现在我的结构看起来像这样

<canvas Name="GameCanvas">
   <canvas Name="StaticBG">

   </canvas>
   <canvas Name="DynamIcBG">

   </canvas>
   <canvas Name="CollidableObjects">

   </canvas>
   <canvas Name="Hud">

   </canvas>
</canvas>

我想虚拟化 DynamicBG 和 CollidableObjects 画布

编辑:我可以把我所有的东西都放在 VirtualStackPanel 里面吗?那行得通吗?

<Canvas>
    <Canvas>

    <VirtualizingStackPanel>
            <Canvas Name="Collidables">
                <TextBlock>HOMES IT WORKS</TextBlock>
            </Canvas>
    </VirtualizingStackPanel>

    </Canvas>
    <Canvas>

        <VirtualizingStackPanel>
            <Canvas Name="DynamicBG">
                <TextBlock>IT WORKS HOMES</TextBlock>
            </Canvas>
        </VirtualizingStackPanel>
    </Canvas>
</Canvas>
4

2 回答 2

2

不是虚拟化的Canvas——至少,不是你通常定义虚拟化的方式。

以下 LINQPad-ready 工具将显示这一点 - 即使“错误”在窗口范围之外,包含的错误将继续呈现。

void Main()
{
    var bugCount = 4;
    var window = System.Windows.Markup.XamlReader.Parse(someXaml) 
            as System.Windows.Window;
    window.Show();
    var canvas = window.FindName("canvas") 
            as System.Windows.Controls.Canvas;
    var bugs = new List<Bug>();
    var r = new Random();
    if(canvas != null)
    {
        for(int i=0; i < bugCount; i++)
        {
            var bug = new Bug();
            bug.Height = 50;
            bug.Width = 50;
            bug.Location = new System.Windows.Point(
                r.Next(0, (int)canvas.Width), 
                r.Next(0, (int)canvas.Height));
            canvas.Children.Add(bug);
            bugs.Add(bug);
        }
    }
    var dt = new System.Windows.Threading.DispatcherTimer();
    dt.Tick += (o,e) => MoveIt(bugs);
    dt.Interval = TimeSpan.FromMilliseconds(100);
    dt.Start();

}

public void MoveIt(List<Bug> bugs)
{
    var r = new Random();
    foreach (var bug in bugs)
    {
        var dir = r.Next(0,4);
        switch (dir)
        {
            case 0: 
                bug.Location = 
                    new System.Windows.Point(bug.Location.X + 1, bug.Location.Y); 
                break;
            case 1: 
                bug.Location = 
                    new System.Windows.Point(bug.Location.X - 1, bug.Location.Y); 
                break;
            case 2: 
                bug.Location = 
                    new System.Windows.Point(bug.Location.X, bug.Location.Y + 1); 
                break;
            case 3: 
                bug.Location = 
                    new System.Windows.Point(bug.Location.X, bug.Location.Y - 1); 
                break;
        }
    }
}

public class Bug : System.Windows.Controls.UserControl
{
    private static int _bugCounter = 0;
    public Bug()
    {
        this.BugId = _bugCounter++;
    }
    public int BugId {get; private set;}     
    private System.Windows.Point _location;
    public System.Windows.Point Location 
    {
        get { return _location; }
        set 
        { 
            _location = value; 
            System.Windows.Controls.Canvas.SetLeft(this, value.X);
            System.Windows.Controls.Canvas.SetTop(this, value.Y);
            InvalidateVisual();            
        }
    }

    protected override void OnRender(System.Windows.Media.DrawingContext ctx)
    {
        base.OnRender(ctx);
        Console.WriteLine("Yo, bug #{0} is rendering!", BugId);
        ctx.DrawRectangle(
            System.Windows.Media.Brushes.Red, 
            new System.Windows.Media.Pen(System.Windows.Media.Brushes.White, 1), 
            new System.Windows.Rect(Location, this.RenderSize));
        var formattedText = new System.Windows.Media.FormattedText(
            this.BugId.ToString(), 
            System.Globalization.CultureInfo.CurrentCulture, 
            System.Windows.FlowDirection.LeftToRight, 
            new System.Windows.Media.Typeface("Arial"), 
            12, 
            System.Windows.Media.Brushes.White);
        ctx.DrawText(
            formattedText, 
            new System.Windows.Point(Location.X + 10, Location.Y + 10));
    }
}

string someXaml =
@"
<Window
    xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
    xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
    Width=""320""
    Height=""240""
>
    <Canvas 
        x:Name=""canvas""
        Width=""640""
        Height=""480""
        Background=""LightGray""
    />
</Window>        
";
于 2013-03-05T00:11:16.107 回答
1

这个问题的答案是 Canvas 伪造了虚拟化。如果您在画布上加载一堆对象并且不需要在屏幕上绘制它们,则它们会被忽略。我说假虚拟化是因为这来自我自己的调查和研究。我还没有找到与该主题相关的单篇文章。

但是,如果您要将 200 个 100x100 的图像加载到画布上屏幕内外各个位置的画布上。您会注意到,当您移动画布时,您不会遇到任何延迟。

于 2013-03-04T23:28:32.513 回答