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

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

问题描述

我希望将行号放入WPF 4 DataGrid的RowHeader中,以便为DataGrid的行号提供类似于Excel的列。

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

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

  • Subscribe to dataGrid.ItemContainerGenerator.ItemsChanged
  • In the event handler, find all the child DataGridRows in the visual tree
  • Set the Header to the index for each 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天全站免登陆