Создание сетки прокрутки ячеек разной ширины - PullRequest
0 голосов
/ 14 января 2012

Я новичок в разработке на c # и WinPhone7 и мне нужно немного советов, если кто-то может быть так добр, поэтому, пожалуйста, извините за мое невежество.

Проблема, с которой я столкнулся, заключается в том, что мне нужно создать представление Grid дляTV Guide, где у вас есть вертикальный список логотипов каналов слева, который прокручивается вверх и вниз, а справа - горизонтальная и вертикальная сетка прокрутки.Горизонтальная прокрутка не перемещает логотипы каналов, которые зафиксированы на экране, но вертикальная сетка прокрутки также прокручивает логотипы, как и следовало ожидать.

Должен ли я продолжать пытаться делать это с использованием XAML и Silverlight или просто делать эточерез XNA?

Я спрашиваю, потому что я пробовал несколько разных методов через Silverlight, чтобы перейти к двум основным проблемам, которые у меня есть:

Производительность

Когда я получаю данные из нашего API с помощью запросов ASync, я создаю фоновый рабочий поток, который анализирует JSON и создает ячейки программы в представлении таблицы «canvas» с помощью Dispatch.Invoke.Поскольку это происходит, постепенная обратная связь отсутствует, все это ждет, пока все не будет сделано, и затем внезапно появляется сетка.Я хотел бы, чтобы ячейки отображались по каналам или по каждой ячейке, не блокируя пользовательский интерфейс, поэтому прокрутка по-прежнему работает хорошо, но, похоже, этого не происходит.

У меня проблемы, как и у любого другогоТакая работа с использованием UIElements выполняется в потоке пользовательского интерфейса, который в WinPhone7 является основным потоком (я полагаю), включая синтаксический анализ XAML или создание / изменение UIElements, даже если они не добавляются ни к чему на экране или не видны.Это означает, что я не могу улучшить вещи, предварительно создав или повторно использовав элементы.

Я попытался сделать как можно больше в рабочем потоке, и лишь крошечная часть работы пользовательского интерфейса отправлялась в поток пользовательского интерфейса, чтобы свести к минимумублокировка, и это, кажется, не помогает.

Память

Ясно, что я не могу создать «программные ячейки» для каждого телевизионного события программы потенциально для сотен (мы поддерживаем более650 каналов) в течение 7 дней, так как телефон очень быстро исчерпает память;поэтому я хотел бы создать виртуальную сетку, в которой ячейки создаются и загружаются в вид холста только для видимой области.

У меня есть две проблемы с этим:

  1. theБлокировка пользовательского интерфейса при выполнении любой пользовательской работы останавливает любую прокрутку, как описано выше, поэтому создание новых ячеек в фоновом режиме, которые должны быть прокручены, не может происходить без блокировки пользовательского интерфейса
  2. , так как никакие события прокрутки не отправляются представлением прокрутки,Я экспериментировал с привязкой к полосам прокрутки в обзоре прокрутки, чтобы получить значения смещения, но это не очень хорошо работает, так как он просто обновляется по частям и запускается, поэтому, если вы делаете много прокрутки, ничего не отправляется, пока не останется пауза или OnIdle, я думаю.

Это я все испортил и должен ли я поэтому продолжать, или я делаю что-то, что не могу сделать, и я должен попробовать другой такт, например, делать это через XNA?

Любой советбудет принята с благодарностью.

Редактировать: немного больше информации и пример кода

У меня есть класс Program, который содержит такие вещи, как время начала и заголовок, класс Channel с именем и логотипом и т. Д., А также массив программ.

Когда я получаю свои данные API, я создаюобъект канала и добавить его в массив каналов, затем я добавляю программы в массив программ Каналы.Когда все программы для канала добавлены в массив, я отправляю его в прослушиватель событий ChannelProgrammesComplete для обновления пользовательского интерфейса.

<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 Ответ

1 голос
/ 14 января 2012

Прежде всего, использование большого Canvas должно быть только последним средством - в большинстве случаев комбинации Grid или StackPanel (иногда в других StackPanel с) и элементы с Margin будутнамного быстрее (с ними будет немного сложнее работать).

Чтобы приложение могло реагировать, вы могли бы

  1. Загружать только небольшие порции данных одновременно (как, например,две страницы. Это значительно уменьшит объем данных, отображаемых одновременно).Затем вы можете загрузить следующий блок либо сразу, либо когда пользователь прокручивает данные в конце списка.
  2. Ускорение обработки результатов.Если вы подождете 100 мс после вставки каждого элемента (или 1 секунду после каждого канала, если вы хотите, чтобы канал был загружен сразу), влияние на скорость отклика должно почти исчезнуть, в то время как слишком не окажет большого влияния на загрузкувремя.Упомянутое время является лишь приблизительным, если оно слишком большое / маленькое, не стесняйтесь настраивать его в соответствии с вашими потребностями, чтобы обеспечить бесперебойную работу пользователей.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...