创建不同宽度单元格的滚动网格

时间:2012-01-13 21:27:57

标签: c# silverlight windows-phone-7

我是c#和WinPhone7开发的新手,如果有人可以如此友善,需要一些指导,所以请原谅我的无知。

我遇到的问题是我需要为电视指南创建一个网格视图,其中左侧有一个垂直的通道标识列表,可以向上和向下滚动,右侧我们有一个水平和垂直滚动的网格。水平滚动不会移动固定在屏幕上的频道徽标,但垂直滚动网格也会按照您的预期滚动徽标。

我是否应继续尝试使用XAML和Silverlight进行此操作,还是应该通过XNA进行此操作?

我问,因为我已经通过Silverlight尝试了几种不同的方法来解决我遇到的两个主要问题:

性能

当我使用ASync请求从API接收数据时,我创建了一个后台工作线程,该线程解析JSON并使用Dispatch.Invoke在网格“画布”视图上创建程序单元。当这种情况发生时,没有渐进的反馈,整个事情等待一切都完成然后突然出现网格。我希望单元格逐个通道或逐个单元地显示,而不会阻止UI,因此滚动仍然可以正常工作,但这似乎不会发生。

我遇到问题,因为使用UIElements的任何工作都是在UI线程上完成的,在WinPhone7上是主线程(我相信),这包括解析XAML或创建/修改UIElements,即使它们没有被添加到任何东西上 - 屏幕或可见。这意味着我无法通过预先创建或重新使用元素来改进。

我已尝试在工作线程中尽可能多地执行操作,并且只是将一小部分UI工作分派到UI线程以最小化阻塞,并且它似乎没有帮助。

内存

很明显,我不能为每个电视节目活动创建'节目单元',因为手机内存很快就会耗尽数百天(我们支持650多个频道)。所以我想创建一个虚拟网格,其中创建单元格并将其加载到画布视图中,仅用于当前看到的视口。

我有两个问题:

  1. 执行任何UI工作的UI阻止会停止上面的任何滚动,因此在后台创建要滚动到视图中的新单元,而不会阻止UI
  2. 滚动视图没有发送滚动事件,我已尝试绑定到scrollview中的滚动条以获取偏移值,但这并不能很好地工作,因为它只是更新了适合和开始所以如果你做了很多滚动,没有任何东西被发送,直到暂停或OnIdle我猜。
  3. 是不是搞砸了,我是否应该坚持下去,或者我正在做一些无法完成的事情,我应该尝试不同的机智,比如通过XNA做这件事?

    非常感谢任何建议。

    编辑:更多信息和一些示例代码

    我有一个Program类,其中包含开始时间和标题,具有名称和徽标等的Channel类,以及一系列程序。

    当我检索我的API数据时,我创建了一个通道对象并将其添加到一个通道数组中,然后我将程序添加到通道程序数组中。将通道的所有程序添加到数组后,我将其发布到ChannelProgrammesComplete事件侦听器,以便更新UI。

    <ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Visible">
        <Canvas x:Name="ProgGrid" 
                        Height="55" Width="393" 
                        VerticalAlignment="Top" HorizontalAlignment="Left">
        </Canvas>
    </ScrollViewer>
    
    
    public void ChannelProgrammesComplete( object sender, EventArgs e )
    {
      var bw = new BackgroundWorker();
      bw.WorkerReportsProgress = true;
      bw.DoWork += ( doWorkSender, args ) =>
      {
        Dispatch( (Channel)sender );
      };
      bw.RunWorkerAsync();
    }
    
    private void Dispatch( BackgroundWorker bw, object param )
    {
      Channel channel = (Channel)param;
    
      int progCount = 0;
      foreach( Programme programme in channel.Programmes )
      {
        double left = ( ( programme.StartSecsFromToday / 60 ) * PixelsPerMinute );  // turn it into seconds
    
        if( progCount == 0 && left < 0 )
        {
          // If first prog starts before 6am, shrink the cell so it starts at the 6am start point
          programme.UIWidth = ( ( programme.Duration - ( ( programme.StartSecsFromToday / 60 ) * -1 ) ) * PixelsPerMinute ) - _cellPadding;
          left = 0;
        }
        else
        {
          programme.UIWidth = ( programme.Duration * PixelsPerMinute ) - _cellPadding;  // Multiply by zoom level which is 3 for now, and take off the amount we use for right margin grid separator
        }
        Debug.Assert( programme.UIWidth > 0 );
    
        programme.UITop = channel.SortIndex * ( _rowHeight + _cellPadding );
        programme.UILeft = left;
        programme.UIHeight = _rowHeight;
    
        object[] invokeArgs = new object[ 1 ];
        invokeArgs[ 0 ] = programme;
    
        // Do as much work as possible in the thread before dispatching to the UI thread for the simple UI work
        Dispatcher.BeginInvoke( new InvokeProgrammeCellDelegate( AddProgrammeCellDelegate ), invokeArgs );
      }
    }
    
    
    public delegate void InvokeProgrammeCellDelegate( Programme prog );
    public void AddProgrammeCellDelegate( Programme prog )
    {
      Rectangle progCell = new Rectangle();
      progCell.Fill = new SolidColorBrush( Color.FromArgb( 0xFF, (byte)( 0x13 ), (byte)( 0x45 ), (byte)( 0x70 ) ) );
      progCell.Height = prog.UIHeight;
      progCell.Width = prog.UIWidth;
    
      progCell.SetValue( Canvas.TopProperty, prog.UITop );
      progCell.SetValue( Canvas.LeftProperty, prog.UILeft );
    
      ProgGrid.Children.Add( progCell );
      ProgGrid.Width = Math.Max( ProgGrid.Width, prog.UIWidth + prog.UILeft );
    }
    

1 个答案:

答案 0 :(得分:1)

首先,使用大Canvas应该只是最后的选择 - 在大多数情况下,GridStackPanel的组合(有时在其他StackPanel内)和具有Margin的项目会快得多(虽然它们会稍微难以处理)。

要让应用程序保持响应,您可以

  1. 一次只加载小块数据(例如,两页。这将大大减少同时呈现的数据量)。然后,您可以立即加载下一个块,也可以在用户滚动列表末尾时加载。
  2. 降低结果处理速度。如果你在插入每个项目后等待100ms(或者每个频道后1秒钟,如果你想一次加载频道),对响应性的影响应该几乎消失,而对影响不大加载时间。所提到的时间只是估计,如果它们太大/太小,可以根据您的需求自由调整它们以提供顺畅的用户体验。