我正在寻找将行号放入WPF 4 DataGrid的RowHeader,因此它具有类似Excel的DataGrid行号。WPF 4 DataGrid:获取RowHeader的行号
我在网上看到的解决方案建议在业务对象中添加一个索引字段。这不是一个真正的选择,因为DataGrid将会得到很大的提升,我们不希望不断跟踪改变这些索引字段。
非常感谢
我正在寻找将行号放入WPF 4 DataGrid的RowHeader,因此它具有类似Excel的DataGrid行号。WPF 4 DataGrid:获取RowHeader的行号
我在网上看到的解决方案建议在业务对象中添加一个索引字段。这不是一个真正的选择,因为DataGrid将会得到很大的提升,我们不希望不断跟踪改变这些索引字段。
非常感谢
一种方法是将它们添加在LoadingRow事件为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();
}
更新
为了得到这个在.NET 3.5中的DataGrid WPF工具包需要稍加修改工作。索引仍然正确生成,但使用虚拟化时输出失败。以下修改的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>
编辑2012-07-05
如果项目被添加或删除源列表,然后将号码不同步,直到列表滚动所以LoadingRow
是再次呼叫。解决此问题的工作是有点复杂,我现在能想到的最好的办法就是保持LoadingRow
解决方案上面,也
dataGrid.ItemContainerGenerator.ItemsChanged
DataGridRows
在视觉树DataGridRow
下面是一个附加的行为,其执行此操作。使用这样的
<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
}
编辑:显然滚动变化的指标,因此结合不喜欢你的工作...
A(貌似)清洁模板解决方案:
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>
转换器:
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
}
@Fredrik Hedblad的答案适合我。谢谢!
我添加了另一个属性来获得“偏移”值,因此DataGrid可以从0或1(或任何设置)开始。
要使用的行为,(注 'B' 是命名空间)
<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
}
LoadingRowEvent由该触发:
ICollectionView view = CollectionViewSource.GetDefaultView(_dataGrid.ItemsSource);
view.Refresh();
指数从0开始,所以你应该添加1. – kevindaub 2011-01-11 23:29:52
@ daub815:好点 – 2011-01-11 23:31:33
谷歌搜索,你会发现这个答案也在其他论坛中提供,这是完全错误的。它可能工作的条件非常严格,以至于使这个“解决方案”成为一个笑话。就像,如果你添加5个项目到你的列表中,然后永远不要调整它,不要调整它,不要添加或删除项目,不要做任何会影响重新显示这些项目的东西,那么你很好。事实是,行索引是行数据(项目)的内部容器集合中的索引。这与其集合中的项目(数据)本身的索引无关。 – Tony 2012-05-26 13:16:29