WPF4DataGrid:将行号放入行标头

WPF4DataGrid:将行号放入行标头,wpf,wpfdatagrid,Wpf,Wpfdatagrid,我希望将行号放入WPF4DataGrid的RowHeader中,这样它就有了一个类似Excel的列来表示DataGrid的行号 我在网上看到的解决方案建议在业务对象中添加一个索引字段。这并不是一个真正的选项,因为DataGrid将被大量使用,我们不想一直跟踪这些索引字段的变化 非常感谢一种方法是将它们添加到数据网格的LoadingRow事件中 void DataGrid\u LoadingRow(对象发送方,DataGridRowEventArgs e) { //添加1以使行计数从1开始,而

我希望将行号放入WPF4DataGrid的RowHeader中,这样它就有了一个类似Excel的列来表示DataGrid的行号

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


非常感谢

一种方法是将它们添加到
数据网格的LoadingRow事件中


void DataGrid\u LoadingRow(对象发送方,DataGridRowEventArgs e)
{
//添加1以使行计数从1开始,而不是从0开始
//正如daub815所指出的
e、 Row.Header=(e.Row.GetIndex()+1.ToString();
}
更新
为了在WPF工具包中使用.NET3.5DataGrid,需要进行一些修改。索引仍然正确生成,但使用虚拟化时输出失败。以下对
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>
显示行数

公共类DataGridBehavior
{
#区域显示行数
公共静态从属属性DisplayRowNumberProperty=
DependencyProperty.RegisterAttached(“DisplayRowNumber”,
类型(bool),
类型(DataGridBehavior),
新的FrameworkPropertyMetadata(false,OnDisplayRowNumberChanged));
公共静态bool GetDisplayRowNumber(DependencyObject目标)
{
返回(bool)target.GetValue(DisplayRowNumberProperty);
}
公共静态void SetDisplayRowNumber(DependencyObject目标,布尔值)
{
target.SetValue(DisplayRowNumberProperty,value);
}
私有静态无效OnDisplayRowNumberChanged(DependencyObject目标,DependencyPropertyChangedEventArgs e)
{
DataGrid DataGrid=目标为DataGrid;
if((bool)e.NewValue==true)
{
EventHandler loadedRowHandler=null;
loadedRowHandler=(对象发送方,DataGridRowEventArgs ea)=>
{
if(GetDisplayRowNumber(dataGrid)==false)
{
dataGrid.LoadingRow-=loadedRowHandler;
返回;
}
ea.Row.Header=ea.Row.GetIndex();
};
dataGrid.LoadingRow+=loadedRowHandler;
ItemsChangedEventHandler itemsChangedHandler=null;
itemsChangedHandler=(对象发送者,ItemsChangedEventArgs ea)=>
{
if(GetDisplayRowNumber(dataGrid)==false)
{
dataGrid.ItemContainerGenerator.ItemsChanged-=itemsChangedHandler;
返回;
}
GetVisualChildCollection(数据网格)。
ForEach(d=>d.Header=d.GetIndex());
};
dataGrid.ItemContainerGenerator.ItemsChanged+=itemsChangedHandler;
}
}
#endregion//DisplayRowNumber
#区域获得视觉效果
私有静态列表GetVisualChildCollection(对象父对象),其中T:Visual
{
List visualCollection=新列表();
GetVisualChildCollection(父对象作为DependencyObject,visualCollection);
返回视觉采集;
}
私有静态void GetVisualChildCollection(DependencyObject父对象,列出visualCollection),其中T:Visual
{
int count=VisualTreeHelper.GetChildrenCount(父级);
for(int i=0;i
编辑:显然,滚动会更改索引,因此绑定不会像那样工作…

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


如果添加或删除行,所有这些方法都将不起作用。在这种情况下,应该刷新行索引。看看这种行为:

public static class DataGridBehavior
{
    #region RowNumbers property

    public static readonly DependencyProperty RowNumbersProperty =
        DependencyProperty.RegisterAttached("RowNumbers", typeof (bool), typeof (DataGridBehavior), 
        new FrameworkPropertyMetadata(false, OnRowNumbersChanged));

    private static void OnRowNumbersChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
    {
        DataGrid grid = source as DataGrid;
        if (grid == null)
            return;
        if ((bool)args.NewValue)
        {
            grid.LoadingRow += onGridLoadingRow;
            grid.UnloadingRow += onGridUnloadingRow;
        }
        else
        {
            grid.LoadingRow -= onGridLoadingRow;
            grid.UnloadingRow -= onGridUnloadingRow;
        }
    }

    private static void refreshDataGridRowNumbers(object sender)
    {
        DataGrid grid = sender as DataGrid;
        if (grid == null)
            return;

        foreach (var item in grid.Items)
        {
            var row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(item);
            if (row != null)
                row.Header = row.GetIndex() + 1;
        }
    }

    private static void onGridUnloadingRow(object sender, DataGridRowEventArgs e)
    {
        refreshDataGridRowNumbers(sender);
    }

    private static void onGridLoadingRow(object sender, DataGridRowEventArgs e)
    {
        refreshDataGridRowNumbers(sender);
    }

    [AttachedPropertyBrowsableForType(typeof(DataGrid))]
    public static void SetRowNumbers(DependencyObject element, bool value)
    {
        element.SetValue(RowNumbersProperty, value);
    }

    public static bool GetRowNumbers(DependencyObject element)
    {
        return (bool) element.GetValue(RowNumbersProperty);
    }

    #endregion
}

@弗雷德里克·海德布拉德的回答对我很有用。谢谢

我添加了另一个属性来获取“offset”值,这样DataGrid可以从0或1(或任何设置)开始

要使用该行为,(注意“b”是名称空间)


修改后的类:

/// <summary>
/// Collection of DataGrid behavior
/// </summary>
public static class DataGridBehavior
{
    #region DisplayRowNumberOffset

    /// <summary>
    /// Sets the starting value of the row header if enabled
    /// </summary>
    public static DependencyProperty DisplayRowNumberOffsetProperty =
        DependencyProperty.RegisterAttached("DisplayRowNumberOffset",
                                            typeof(int),
                                            typeof(DataGridBehavior),
                                            new FrameworkPropertyMetadata(0, OnDisplayRowNumberOffsetChanged));

    public static int GetDisplayRowNumberOffset(DependencyObject target)
    {
        return (int)target.GetValue(DisplayRowNumberOffsetProperty);
    }

    public static void SetDisplayRowNumberOffset(DependencyObject target, int value)
    {
        target.SetValue(DisplayRowNumberOffsetProperty, value);
    }

    private static void OnDisplayRowNumberOffsetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        DataGrid dataGrid = target as DataGrid;
        int offset = (int)e.NewValue;

        if (GetDisplayRowNumber(target))
        {
            WPFUtil.GetVisualChildCollection<DataGridRow>(dataGrid).
                    ForEach(d => d.Header = d.GetIndex() + offset);
        }
    }

    #endregion

    #region DisplayRowNumber

    /// <summary>
    /// Enable display of row header automatically
    /// </summary>
    /// <remarks>
    /// Source: 
    /// </remarks>
    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)
        {
            int offset = GetDisplayRowNumberOffset(target);

            EventHandler<DataGridRowEventArgs> loadedRowHandler = null;
            loadedRowHandler = (object sender, DataGridRowEventArgs ea) =>
            {
                if (GetDisplayRowNumber(dataGrid) == false)
                {
                    dataGrid.LoadingRow -= loadedRowHandler;
                    return;
                }
                ea.Row.Header = ea.Row.GetIndex() + offset;
            };
            dataGrid.LoadingRow += loadedRowHandler;

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

    #endregion // DisplayRowNumber
}
//
///数据网格行为的集合
/// 
公共静态类DataGridBehavior
{
#区域显示RowNumberOffset
/// 
///设置行标题的起始值(如果启用)
/// 
公共静态从属属性DisplayRowNumberOfSetProperty=
DependencyProperty.RegisterAttached(“DisplayRowNumberOfSet”,
类型(int),
类型(DataGridBehavior),
新的框架属性元数据(0,OnDisplayRowNumberOfSetChanged));
公共静态int GetDisplayRowNumberOffset(DependencyObject目标)
{
返回(int)target.GetValue(DisplayRowNumberOffsetProperty);
}
公共静态void SetDisplayRowNumberOffset(DependencyObject目标,int值)
{
target.SetValue(DisplayRowNumberOffsetProperty,value);
}
私有静态无效OnDisplayRowNumberOfSetChanged(DependencyObject目标,DependencyPropertyChangedEventArgs e)
{
DataGrid DataGrid=目标为DataGrid;
int offset=(int)e.NewValue;
如果(GetDisplayRowNumber(目标))
{
GetVisualChildCollection(dataGrid)。
ForEach(d=>d.Header=d.GetIndex()+偏移量);
}
}
#端区
#区域显示行数
/// 
///启用r的显示
<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>
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
}
public static class DataGridBehavior
{
    #region RowNumbers property

    public static readonly DependencyProperty RowNumbersProperty =
        DependencyProperty.RegisterAttached("RowNumbers", typeof (bool), typeof (DataGridBehavior), 
        new FrameworkPropertyMetadata(false, OnRowNumbersChanged));

    private static void OnRowNumbersChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
    {
        DataGrid grid = source as DataGrid;
        if (grid == null)
            return;
        if ((bool)args.NewValue)
        {
            grid.LoadingRow += onGridLoadingRow;
            grid.UnloadingRow += onGridUnloadingRow;
        }
        else
        {
            grid.LoadingRow -= onGridLoadingRow;
            grid.UnloadingRow -= onGridUnloadingRow;
        }
    }

    private static void refreshDataGridRowNumbers(object sender)
    {
        DataGrid grid = sender as DataGrid;
        if (grid == null)
            return;

        foreach (var item in grid.Items)
        {
            var row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(item);
            if (row != null)
                row.Header = row.GetIndex() + 1;
        }
    }

    private static void onGridUnloadingRow(object sender, DataGridRowEventArgs e)
    {
        refreshDataGridRowNumbers(sender);
    }

    private static void onGridLoadingRow(object sender, DataGridRowEventArgs e)
    {
        refreshDataGridRowNumbers(sender);
    }

    [AttachedPropertyBrowsableForType(typeof(DataGrid))]
    public static void SetRowNumbers(DependencyObject element, bool value)
    {
        element.SetValue(RowNumbersProperty, value);
    }

    public static bool GetRowNumbers(DependencyObject element)
    {
        return (bool) element.GetValue(RowNumbersProperty);
    }

    #endregion
}
<DataGrid ItemsSource="{Binding ...}"
      b:DataGridBehavior.DisplayRowNumberOffset="1"
      b:DataGridBehavior.DisplayRowNumber="True">
/// <summary>
/// Collection of DataGrid behavior
/// </summary>
public static class DataGridBehavior
{
    #region DisplayRowNumberOffset

    /// <summary>
    /// Sets the starting value of the row header if enabled
    /// </summary>
    public static DependencyProperty DisplayRowNumberOffsetProperty =
        DependencyProperty.RegisterAttached("DisplayRowNumberOffset",
                                            typeof(int),
                                            typeof(DataGridBehavior),
                                            new FrameworkPropertyMetadata(0, OnDisplayRowNumberOffsetChanged));

    public static int GetDisplayRowNumberOffset(DependencyObject target)
    {
        return (int)target.GetValue(DisplayRowNumberOffsetProperty);
    }

    public static void SetDisplayRowNumberOffset(DependencyObject target, int value)
    {
        target.SetValue(DisplayRowNumberOffsetProperty, value);
    }

    private static void OnDisplayRowNumberOffsetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        DataGrid dataGrid = target as DataGrid;
        int offset = (int)e.NewValue;

        if (GetDisplayRowNumber(target))
        {
            WPFUtil.GetVisualChildCollection<DataGridRow>(dataGrid).
                    ForEach(d => d.Header = d.GetIndex() + offset);
        }
    }

    #endregion

    #region DisplayRowNumber

    /// <summary>
    /// Enable display of row header automatically
    /// </summary>
    /// <remarks>
    /// Source: 
    /// </remarks>
    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)
        {
            int offset = GetDisplayRowNumberOffset(target);

            EventHandler<DataGridRowEventArgs> loadedRowHandler = null;
            loadedRowHandler = (object sender, DataGridRowEventArgs ea) =>
            {
                if (GetDisplayRowNumber(dataGrid) == false)
                {
                    dataGrid.LoadingRow -= loadedRowHandler;
                    return;
                }
                ea.Row.Header = ea.Row.GetIndex() + offset;
            };
            dataGrid.LoadingRow += loadedRowHandler;

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

    #endregion // DisplayRowNumber
}
ICollectionView view = CollectionViewSource.GetDefaultView(_dataGrid.ItemsSource);
view.Refresh();