【问题标题】:WPF Toolkit DataGrid rendered with incorrect column widthsWPF Toolkit DataGrid 以不正确的列宽呈现
【发布时间】:2014-02-18 14:13:46
【问题描述】:

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

我的问题是页面在 DataGrid 组件计算其列宽之前渲染,用户可以在屏幕上看到渲染。

我构建了一个非常简单的示例:DataGrid 有 3 列,第一列有 Width="*" 其他列具有固定宽度。 固定宽度的列从一开始就正确渲染,但星型列以20的宽度渲染。

一秒钟后,DataGrid 会计算出星形列的正确宽度并正确呈现网格:

我的示例 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 组件。

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

【问题讨论】:

  • 尝试将行列表生成的逻辑移到InitializeComponent()之前。
  • @RohitVats:没有帮助,在大多数情况下它实际上会抛出异常,因为尚未创建控件。实际渲染不会发生在绑定时,因此设置数据实际上可以在 init 或加载事件中完成,结果相同。
  • 我的意思是只移动列表部分而不是分配 - mainTable.ItemsSource = rows;。这必须低于InitializeComponent()
  • @RohitVats:你说得对,它确实有帮助,我还必须用我的真实程序对其进行测试,但如果它有效,这是一个正确的答案,比我的 hack 好得多。
  • @RohitVats:很遗憾,由于当前的工作流程,我无法在我的应用程序中测试您的解决方案,但如果您根据您的建议做出回答,我会支持它,因为它很可能会帮助其他人。跨度>

标签: c# wpf wpfdatagrid wpftoolkit


【解决方案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 这适用于在页面创建后无需加载数据的任何人。如果我可以更改我的应用程序的工作流程,这也将是已接受的答案。
【解决方案2】:

尝试将代码放入 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);

【讨论】:

  • 没有帮助,现在表格部分显示为空并且已调整大小。
【解决方案3】:

我的解决方案是创建一个继承 Toolkit DataGrid 的新 DataGrid,并覆盖 MeasureOverride 方法并手动设置宽度。这样在第一次渲染时就可以正确计算宽度。

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/Workaround,因为它对我可以使用的列宽类型以及我可以对它们执行的操作(例如绑定宽度)施加了一些限制这个解决方案是不可能的)。

注意:对于可以在页面创建之前加载数据的任何人,Rohit Vats 的答案很可能会起作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-22
    • 2021-04-21
    • 1970-01-01
    • 2015-03-20
    • 1970-01-01
    • 2022-10-25
    • 2013-05-12
    • 2010-09-29
    相关资源
    最近更新 更多