DataGrid中的依赖属性交叉污染

时间:2016-05-04 19:42:23

标签: c# wpf dependency-properties

我有一个绑定到集合的WPF DataGrid。 DataGrid的一个列是包含我的自定义控件的DataGridTemplateColumn:

<DataGridTemplateColumn Header="$ Diff" Width="60*">
  <DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
      <ui:BoardValueDifference Board1="{Binding Board1}" Board2="{Binding Board2}"/>
    </DataTemplate>
  </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

我的自定义控件有两个依赖属性,Board1和Board2,非常标准的东西。

public BoardValueDifference()
{
    InitializeComponent();
}

public static readonly DependencyProperty Board1Property = DependencyProperty.Register("Board1", typeof(PackageBoard),
        typeof(BoardValueDifference), new FrameworkPropertyMetadata(OnDataChanged));

public PackageBoard Board1
{
    get { return (PackageBoard)GetValue(Board1Property); }
    set { SetValue(Board1Property, value); }
}

protected static void OnDataChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
    BoardValueDifference bvd = d as BoardValueDifference;

    if ( bvd != null )
        bvd.CalculateDifference();
}

protected void CalculateDifference()
{
    if ( Board1 != null && Board2 != null) {
        // Calculate value difference between boards
    }
}

我的问题是Board1和Board2似乎是不确定的,我从其他行获取值。如果我在OnDataChanged()中放置一个断点,我会看到它被Board1的数据绑定所击中,然后是Board2的数据绑定,但是Board2之间会有来自其他行的值,它就是&#39 ;如果我向上和向下滚动DataGrid,那就特别糟糕。

在另一个问题中,我发现了这个链接,Collection-Type Dependency Properties,这与我的案例并不相似,但似乎相似。他们在构造函数中建议SetValue(),并将属性的默认值设置为新实例。我尝试将其设置为null但它似乎完全禁用了我的数据绑定。

SetValue(Board1Property, null);

我的猜测是因为DependencyProperties是静态的,并且因为我的DependencyProperty是一个类,所以在我的BoardValueDifference用户控件的实例之间进行某种共享。我该如何解决?我认为它可能与this question类似,但我不能很好地理解答案,以便解决我的问题。

更新

在我的UserControl中添加一些日志记录后,我想我知道发生了什么:

  1. 我假设DataGrid的每一行都会获得UserControl的新实例,而Board1和Board2将从null开始。根据我的日志,BoardValueDifference正在重新使用,而只是更改了DependencyProperties。
  2. 在我的代码中,一旦Board1和Board2都不再为空,我就在计算板之间的差异。我意识到我现在无法做到这一点,但是在我的UserControl中留下剩余的数据感觉非常草率。我想你必须把它想象成一个静态类?
  3. 总而言之,我可以解决这个问题,但如果有人有更好的解决方法或者确切知道DataGrid中UserControl的生命周期应该如何工作,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

由于行虚拟化,您的UserControl会被回收。如果DataGrid中没有太多行,则可以通过将EnableRowVirtualization属性设置为false来禁用此行为。

DataGrid.EnableRowVirtualization页面的备注部分:

  

要提高性能,请将EnableRowVirtualization属性设置为   默认为true。当EnableRowVirtualization属性设置为   true,DataGrid不为每个实例化DataGridRow对象   绑定数据源中的数据项。而是,DataGrid创建   DataGridRow仅在需要时才对象,并重用它们   尽可能。例如,DataGrid为其创建DataGridRow对象   当前处于视图中的每个数据项,并在其中回收该行   滚动出视图。