WPF 4 DataGrid:将行号放入 RowHeader [英] WPF 4 DataGrid: Getting the Row Number into the RowHeader

查看:14
本文介绍了WPF 4 DataGrid:将行号放入 RowHeader的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望将行号放入 WPF 4 DataGrid 的 RowHeader 中,以便它有一个类似于 Excel 的列用于 DataGrid 的行号.

I am looking to get the row number into the RowHeader of the WPF 4 DataGrid so it has an Excel-like column for the row numbers of the DataGrid.

我在网上看到的解决方案建议向业务对象添加索引字段.这不是一个真正的选择,因为 DataGrid 将被大量使用,我们不希望必须不断跟踪更改这些索引字段.

The solution I've seen out there on the web suggests adding an index field to the business objects. This isn't really an option because the DataGrid will be getting resorted a lot and we don't want to have to keep track of changing these index fields constantly.

非常感谢

推荐答案

一种方法是将它们添加到 DataGrid 的 LoadingRow 事件中.

One way is to add them in the LoadingRow event for the DataGrid.

<DataGrid Name="DataGrid" LoadingRow="DataGrid_LoadingRow" ... />

void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
    // Adding 1 to make the row count start at 1 instead of 0
    // as pointed out by daub815
    e.Row.Header = (e.Row.GetIndex() + 1).ToString(); 
}

更新
要使其与 WPF Toolkit 中的 .NET 3.5 DataGrid 一起使用,需要进行一些修改.索引仍能正确生成,但在使用虚拟化时输出失败.对 RowHeaderTemplate 的以下修改修复了这个问题

Update
To get this to work with the .NET 3.5 DataGrid in WPF Toolkit a little modification is needed. The index is still generated correctly but the output fails when using virtualization. The following modification to the RowHeaderTemplate fixes this

<toolkit:DataGrid LoadingRow="DataGrid_LoadingRow">
    <toolkit:DataGrid.RowHeaderTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type toolkit:DataGridRow}},
                                      Path=Header}"/>
        </DataTemplate>
    </toolkit:DataGrid.RowHeaderTemplate>
</toolkit:DataGrid>

编辑 2012-07-05
如果从源列表中添加或删除项目,则数字将不同步,直到列表滚动,以便再次调用 LoadingRow.解决这个问题有点复杂,我现在能想到的最佳解决方案是保留上面的 LoadingRow 解决方案,并且

Edit 2012-07-05
If items are added or removed from the source list then the numbers get out of sync until the list is scrolled so LoadingRow is called again. Working around this issue is a little more complex and the best solution I can think of right now is to keep the LoadingRow solution above and also

  • 订阅dataGrid.ItemContainerGenerator.ItemsChanged
  • 在事件处理程序中,找到可视化树中的所有子DataGridRows
  • 将Header设置为每个DataGridRow的索引

这是执行此操作的附加行为.像这样使用

Here is an attached behavior which does this. Use it like this

<DataGrid ItemsSource="{Binding ...}"
          behaviors:DataGridBehavior.DisplayRowNumber="True">

DisplayRowNumber

public class DataGridBehavior
{
    #region DisplayRowNumber

    public static DependencyProperty DisplayRowNumberProperty =
        DependencyProperty.RegisterAttached("DisplayRowNumber",
                                            typeof(bool),
                                            typeof(DataGridBehavior),
                                            new FrameworkPropertyMetadata(false, OnDisplayRowNumberChanged));
    public static bool GetDisplayRowNumber(DependencyObject target)
    {
        return (bool)target.GetValue(DisplayRowNumberProperty);
    }
    public static void SetDisplayRowNumber(DependencyObject target, bool value)
    {
        target.SetValue(DisplayRowNumberProperty, value);
    }

    private static void OnDisplayRowNumberChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        DataGrid dataGrid = target as DataGrid;
        if ((bool)e.NewValue == true)
        {
            EventHandler<DataGridRowEventArgs> loadedRowHandler = null;
            loadedRowHandler = (object sender, DataGridRowEventArgs ea) =>
            {
                if (GetDisplayRowNumber(dataGrid) == false)
                {
                    dataGrid.LoadingRow -= loadedRowHandler;
                    return;
                }
                ea.Row.Header = ea.Row.GetIndex();
            };
            dataGrid.LoadingRow += loadedRowHandler;

            ItemsChangedEventHandler itemsChangedHandler = null;
            itemsChangedHandler = (object sender, ItemsChangedEventArgs ea) =>
            {
                if (GetDisplayRowNumber(dataGrid) == false)
                {
                    dataGrid.ItemContainerGenerator.ItemsChanged -= itemsChangedHandler;
                    return;
                }
                GetVisualChildCollection<DataGridRow>(dataGrid).
                    ForEach(d => d.Header = d.GetIndex());
            };
            dataGrid.ItemContainerGenerator.ItemsChanged += itemsChangedHandler;
        }
    }

    #endregion // DisplayRowNumber

    #region Get Visuals

    private static List<T> GetVisualChildCollection<T>(object parent) where T : Visual
    {
        List<T> visualCollection = new List<T>();
        GetVisualChildCollection(parent as DependencyObject, visualCollection);
        return visualCollection;
    }

    private static void GetVisualChildCollection<T>(DependencyObject parent, List<T> visualCollection) where T : Visual
    {
        int count = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < count; i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(parent, i);
            if (child is T)
            {
                visualCollection.Add(child as T);
            }
            if (child != null)
            {
                GetVisualChildCollection(child, visualCollection);
            }
        }
    }

    #endregion // Get Visuals
}

这篇关于WPF 4 DataGrid:将行号放入 RowHeader的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆