WPF Toolkit DataGrid呈现的列宽不正确

时间:2014-02-18 14:13:46

标签: c# wpf wpfdatagrid wpftoolkit

我有一个包含大量组件的页面需要几秒钟才能加载。

我的问题是页面在 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组件。

知道如何解决加载问题吗?

3 个答案:

答案 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 :(得分:0)

尝试将代码放入Dispatcher

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);

答案 2 :(得分:0)

我的解决方案是创建一个继承Toolkit DataGrid的新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的答案很可能会有效。