2014-02-18 1 views
0

У меня есть страница с большим количеством компонентов, для загрузки которой требуется несколько секунд.WPF Toolkit DataGrid, отображаемый с неправильной шириной столбца

Моя проблема заключается в том, что страница отображается перед Компоненты DataGrid подсчитали ширину столбца, и пользователь может видеть рендеринг на экране.

Я построил очень простой пример: DataGrid имеет 3 столбцов, первый столбец имеет Width="*" и другие столбцы имеют фиксированную ширину. Столбцы с фиксированной шириной правильно визуализации с самого начала, но колонна звезда оказывается с шириной 20.

enter image description here

После секунду DataGrid вычисляет правильную ширину столбца звезды и делает сетку правильно:

enter image description here

Мой пример XAML:

<ScrollViewer> 
    <Controls:DataGrid Name="mainTable" AutoGenerateColumns="False"> 
     <Controls:DataGrid.Columns> 
      <Controls:DataGridTemplateColumn Header="col 0" Width="*"> 
       <Controls:DataGridTemplateColumn.CellTemplate> 
        <DataTemplate> 
         <TextBlock Text="{Binding Col0}" /> 
        </DataTemplate> 
       </Controls:DataGridTemplateColumn.CellTemplate> 
      </Controls:DataGridTemplateColumn> 

      <Controls:DataGridTextColumn Header="col 1" Binding="{Binding Col1}" Width="150" /> 
      <Controls:DataGridTextColumn Header="col 2" Binding="{Binding Col2}" Width="150" /> 
     </Controls:DataGrid.Columns> 
    </Controls:DataGrid> 

И код позади:

public MainWindow() 
{ 
    InitializeComponent(); 

    var rows = new List<RowObj>(); 
    for (int i = 0; i < 5000; i++) 
    { 
     rows.Add(new RowObj 
     { 
      Col0 = "col0," + i, 
      Col1 = "col1," + i, 
      Col2 = "col2," + i, 
      Col3 = "col3," + i, 
      Col4 = "col4," + i, 
     }); 
    } 

    mainTable.ItemsSource = rows; 
} 

Как примечание: Я использую WpfToolkit (последний выпуск, начиная с 2010 года) и .NET 3.5 И я не могу перейти к компонентам WPF4.

Любая идея, как устранить проблему с загрузкой?

+0

Попробуйте переместить логику генерации списка строк, прежде чем 'InitializeComponent()'. –

+0

@RohitVats: не помогает, в большинстве случаев он будет генерировать исключение, так как элементы управления еще не созданы. Фактический рендеринг не возникает во время привязки, поэтому установка данных действительно может быть выполнена в событиях инициализации или загрузки с тем же результатом. –

+0

Я имел в виду только перемещение части списка, а не назначение - 'mainTable.ItemsSource = rows;'. Это должно быть ниже 'InitializeComponent()' только. –

ответ

0

Мое решение было создать новый DataGrid, который наследует Toolkit DataGrid, и переопределить MeasureOverride метод и установить Widths вручную. Таким образом, при первом рендеринге ширина вычисляется правильно.

protected override Size MeasureOverride(Size availableSize) 
{ 
    double totalWidth = availableSize.Width; 
    double absoluteWidth = 0.0; 

    DataGridColumn star = null; 
    foreach (var col in Columns) 
    { 
     if (col.Width.IsAbsolute) 
     { 
      absoluteWidth += col.Width.Value; 
      col.MinWidth = col.Width.Value; 
     } 
     else if (col.Width.IsAuto) 
     { 
      absoluteWidth += col.Width.DisplayValue; 
     } 
     else if (col.Width.IsStar) 
     { 
      if (null == star) 
      { 
       star = col; 
      } 
      else 
      { 
       // This method only handles one star column 
       star = null; 
       break; 
      } 
     } 
    } 

    if (null != star) 
    { 
     double diff = totalWidth - absoluteWidth - 4.0; 
     if (diff > 0.0) 
      star.MinWidth = diff; 
     else 
      star.MinWidth = 10.0; 
    } 

    return base.MeasureOverride(availableSize); 
} 

ПРЕДУПРЕЖДЕНИЕ: это больше HACK/Обход, поскольку она накладывает некоторые ограничения на тип ширины столбцов можно использовать и на операции я могу сделать на них (например, связывание ширин вопрос с этим решением).

ПРИМЕЧАНИЕ: для тех, кто может загрузить данные до создания страницы, ответ Rohit Vats, скорее всего, будет работать.

0

Попробуйте поставить код в Диспетчере

Application.Current.Dispatcher.BeginInvoke(new Action(() => { 

       var rows = new List<RowObj>(); 
       for (int i = 0; i < 5000; i++) 
       { 
        rows.Add(new RowObj 
        { 
         Col0 = "col0," + i, 
         Col1 = "col1," + i, 
         Col2 = "col2," + i, 
         Col3 = "col3," + i, 
         Col4 = "col4," + i, 
        }); 
       } 

       mainTable.ItemsSource = rows; 

      }), System.Windows.Threading.DispatcherPriority.Background); 
+0

Не помогает, теперь таблица показана частично пустой и имеет размер. –

1

Переместить логику генерации списка выше InitializeComponent() и просто установить ItemsSource впоследствии:

public MainWindow() 
{ 
    var rows = new List<RowObj>(); 
    for (int i = 0; i < 5000; i++) 
    { 
     rows.Add(new RowObj 
     { 
      Col0 = "col0," + i, 
      Col1 = "col1," + i, 
      Col2 = "col2," + i, 
      Col3 = "col3," + i, 
      Col4 = "col4," + i, 
     }); 
    } 
    InitializeComponent(); 

    mainTable.ItemsSource = rows; 
} 
+1

+1 Это будет работать для тех, кому не нужно загружать данные после создания страницы. Если бы я мог изменить рабочий процесс моего приложения, это также будет принятым ответом. –