WPF 4 DataGrid:将行号放入RowHeader

Gre*_*ora 20 wpf wpfdatagrid

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

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

非常感谢

Fre*_*lad 39

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

<DataGrid Name="DataGrid" LoadingRow="DataGrid_LoadingRow" ... />
Run Code Online (Sandbox Code Playgroud)
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(); 
}
Run Code Online (Sandbox Code Playgroud)

更新
要在WPF Toolkit中使用.NET 3.5 DataGrid,需要进行一些修改.索引仍然正确生成,但使用虚拟化时输出失败.以下修改RowHeaderTemplate修复此问题

<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>
Run Code Online (Sandbox Code Playgroud)

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

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

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

<DataGrid ItemsSource="{Binding ...}"
          behaviors:DataGridBehavior.DisplayRowNumber="True">
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

  • 索引从0开始,所以你应该加1. (2认同)
  • 非常感谢,你刚刚救了我一堆工作.通过行为的解决方案是完美的:) (2认同)

H.B*_*.B. 7

编辑:显然滚动会更改索引,因此绑定将不会像那样工作...

一个(看似)干净的模板解决方案:
Xaml:

<Window
    ...
    xmlns:local="clr-namespace:Test"
    DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
    <Window.Resources>
        <local:RowToIndexConv x:Key="RowToIndexConv"/>
    </Window.Resources>
        <DataGrid ItemsSource="{Binding GridData}">
            <DataGrid.RowHeaderTemplate>
                <DataTemplate>
                    <TextBlock Margin="2" Text="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={StaticResource RowToIndexConv}}"/>
                </DataTemplate>
            </DataGrid.RowHeaderTemplate>
        </DataGrid>
</Window>
Run Code Online (Sandbox Code Playgroud)

转换器:

public class RowToIndexConv : IValueConverter
{

    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        DataGridRow row = value as DataGridRow;
        return row.GetIndex() + 1;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)