C# 如何使用WPF绑定触发DataGrid中特定单元格的更新

C# 如何使用WPF绑定触发DataGrid中特定单元格的更新,c#,wpf,binding,C#,Wpf,Binding,我有一个自定义类,提供具有只读属性的三维点信息: public class Point3d { private readonly double x; public double X { get { return x; } } private readonly double y; public double Y { get { return y; } } private readonly double z; public double Z { g

我有一个自定义类,提供具有
只读属性的三维点信息:

public class Point3d
{
    private readonly double x;
    public double X { get { return x; } }

    private readonly double y;
    public double Y { get { return y; } }

    private readonly double z;
    public double Z { get { return z; } }

    public PoseCartesian(double x, double y, double z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}
要显示多个3d点,我使用WPF中有四列的
DataGrid
。第一列应该显示条目的行号

<DataGrid Name="dgrPoints" AutoGenerateColumns="False" 
    ItemsSource="{Binding UpdateSourceTrigger=Default, Mode=OneWay}"
    SelectionChanged="dgr_Poses_SelectionChanged" CanUserSortColumns="False"
    IsReadOnly="True">
    <DataGrid.Columns>
          <DataGridTextColumn x:Name="colI" Binding="{Binding Mode=OneWay,
               RelativeSource={RelativeSource AncestorType=DataGridRow},
               Converter={local:RowToIndexConverter}}"/>
          <DataGridTextColumn x:Name="colX" Binding="{Binding X}" Header="X"/>
          <DataGridTextColumn x:Name="colY" Binding="{Binding Y}" Header="Y"/>
          <DataGridTextColumn x:Name="colZ" Binding="{Binding Z}" Header="Z"/>
     </DataGrid.Columns>
</DataGrid>
通过设置
DataContext
结束绑定:

this.pointList = new ObservableCollection<Point3d>();
dgrPoints.ItemsSource= this.poseList;
无论何时添加新行(
Point3d
),这一切都可以正常工作,并在
DataGrid
的第一列中设置相应的行号。但每当删除一行时,行号都不会更新,因为转换器是通过添加新的
DataGridRow
触发的。现在,我通过将
DataGrid.DataContext
设置为
null
并再次添加来强制取消更新:

this.pointList.RemoveAt(0);
dgrPoints.ItemsSource = null;
dgrPoints.ItemsSource = this.pointList;
这不是实现行号不更新的正确解决方案。每当
点列表更改时,触发每行转换器的最佳方法是什么


我不想使用
DataGridRow.Header
属性,因为这会替换我的列。如果我错了,请纠正我。除此之外,每个考虑不同方法的建议都是受欢迎的。

您可以处理
加载行
ItemContainerGenerator.ItemsChanged
事件,并将
DataGridRow
容器的
标记
属性设置为相应的行号:

public Window1()
{
    InitializeComponent();
    dgrPoints.ItemContainerGenerator.ItemsChanged += ItemContainerGenerator_ItemsChanged;
    dgrPoints.LoadingRow += DgrPoints_LoadingRow;
    dgrPoints.ItemsSource = ...;
}

private void DgrPoints_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Tag = (e.Row.GetIndex() + 1).ToString();
}

private void ItemContainerGenerator_ItemsChanged(object sender, ItemsChangedEventArgs e)
{
    IEnumerable<DataGridRow> rows = FindVisualChildren<DataGridRow>(dgrPoints);
    foreach (DataGridRow row in rows)
        row.Tag = (row.GetIndex() + 1).ToString();
}

private static IEnumerable<T> FindVisualChildren<T>(DependencyObject dependencyObject) where T : DependencyObject
{
    if (dependencyObject != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, i);
            if (child != null && child is T)
            {
                yield return (T)child;
            }

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}
公共窗口1()
{
初始化组件();
dgrPoints.ItemContainerGenerator.ItemsChanged+=ItemContainerGenerator\u ItemsChanged;
dgrPoints.LoadingRow+=dgrPoints_LoadingRow;
dgrPoints.ItemsSource=。。。;
}
私有void DgrPoints_LoadingRow(对象发送方,DataGridRowEventArgs e)
{
e、 Row.Tag=(e.Row.GetIndex()+1.ToString();
}
私有void ItemContainerGenerator_ItemsChanged(对象发送方,ItemsChangedEventArgs e)
{
IEnumerable rows=FindVisualChildren(dgrPoints);
foreach(DataGridRow行中的行)
row.Tag=(row.GetIndex()+1.ToString();
}
私有静态IEnumerable FindVisualChildren(DependencyObject DependencyObject),其中T:DependencyObject
{
if(dependencyObject!=null)
{
for(int i=0;i


this.pointList.RemoveAt(0);
dgrPoints.ItemsSource = null;
dgrPoints.ItemsSource = this.pointList;
public Window1()
{
    InitializeComponent();
    dgrPoints.ItemContainerGenerator.ItemsChanged += ItemContainerGenerator_ItemsChanged;
    dgrPoints.LoadingRow += DgrPoints_LoadingRow;
    dgrPoints.ItemsSource = ...;
}

private void DgrPoints_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Tag = (e.Row.GetIndex() + 1).ToString();
}

private void ItemContainerGenerator_ItemsChanged(object sender, ItemsChangedEventArgs e)
{
    IEnumerable<DataGridRow> rows = FindVisualChildren<DataGridRow>(dgrPoints);
    foreach (DataGridRow row in rows)
        row.Tag = (row.GetIndex() + 1).ToString();
}

private static IEnumerable<T> FindVisualChildren<T>(DependencyObject dependencyObject) where T : DependencyObject
{
    if (dependencyObject != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, i);
            if (child != null && child is T)
            {
                yield return (T)child;
            }

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}
<DataGrid Name="dgrPoints" AutoGenerateColumns="False" 
          ItemsSource="{Binding UpdateSourceTrigger=Default, Mode=OneWay}"
          CanUserSortColumns="False"
          IsReadOnly="True">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="colI" Binding="{Binding Path=Tag, Mode=OneWay, 
            RelativeSource={RelativeSource AncestorType=DataGridRow}}"/>
        <DataGridTextColumn x:Name="colX" Binding="{Binding X}" Header="X"/>
        <DataGridTextColumn x:Name="colY" Binding="{Binding Y}" Header="Y"/>
        <DataGridTextColumn x:Name="colZ" Binding="{Binding Z}" Header="Z"/>
    </DataGrid.Columns>
</DataGrid>