随机DependencyProperty.多重绑定时的UnsetValue



我遇到了一个奇怪的问题。

我在一次可观测的收集中得到了一组太空物体(行星(。这些对象在屏幕上移动,因此它们的X轴和Y轴一直在变化。这是它的xaml代码:

<DataTemplate DataType="{x:Type spaceObjects:SpaceObject}">
                    <Path Fill="{Binding Color, Converter={StaticResource ColorConverter}}"
                          Stroke="{Binding Border, Converter={StaticResource ColorConverter}}"
                          StrokeThickness="{Binding BorderThickness}" Tag="{Binding Name}">
                        <Path.Data>
                            <EllipseGeometry RadiusY="{Binding Radius}" RadiusX="{Binding Radius}">
                                <EllipseGeometry.Center>
                                    <MultiBinding Converter="{StaticResource XYPositionConverter}">
                                        <Binding Path="X"></Binding>
                                        <Binding Path="Y"></Binding>
                                    </MultiBinding>
                                </EllipseGeometry.Center>
                            </EllipseGeometry>
                        </Path.Data>
                    </Path>
                </DataTemplate>

我将xaml代码缩短了很多,因为有很多冗余信息。只要知道它是一个具有多种对象的可观察集合(这就是我使用数据模板的原因(,并且该数据模板所在的itemscontrol也绑定到另一个集合。不过,我认为这与这个问题无关。

所以,在我们讨论错误代码之前,我将向您展示一些不会引发错误的代码。此方法移动spaceObjects并执行一些与UI无关的其他操作。没有问题。

private void MoveAndCheckLegacy(Object source, ElapsedEventArgs e)
        {
            Parallel.For(0, _spaceObjects.Count, i =>
            {
                var isSpaceObject = _spaceObjects[i] is SpaceObject;
                if (isSpaceObject)
                {
                    var spaceObject = (SpaceObject) _spaceObjects[i];
                    spaceObject.Move();
                    CheckForCollisionLegacy(spaceObject);
                }
                else
                {
                    var lineObject = (LineSpaceObject) _spaceObjects[i];
                    lineObject.UpdatePosition();
                }
            });
        }

它只是在observablecollection中的spaceObject中循环,更改它们的X和Y。多绑定会注意到这一点并相应地采取行动。

现在我写了一个更大的方法,它也将元素插入到QuadTree中,但移动部分和以前一样只是for循环的一部分(以前也是parralel,但我在调试这个问题时更改了它(。

var qtree = new QuadTree(new Rectangle(0, 0, 800, 600), "base");
            for (int i = 0; i < _spaceObjects.Count - 1; i++)
            {
                var isSpaceObject = _spaceObjects[i] is SpaceObject;
                if (isSpaceObject)
                {
                    var spaceObject = (SpaceObject)_spaceObjects[i];
                    spaceObject.Move();
                    // Printing X and Y and Name for debugging purposes
                    Trace.WriteLine($"{spaceObject.Name}: ({spaceObject.X}, {spaceObject.Y})");
                }
                else       // Some stuff to do with other objects. 
                {
                    var lineObject = (LineSpaceObject)_spaceObjects[i];
                    lineObject.UpdatePosition();
                }
            }
             // Insert spaceObjects into QuadTree
            for (int i = 0; i < _spaceObjects.Count - 1; i++)
            {
                var so = _spaceObjects[i] is SpaceObject;
                if (so) qtree.Insert((SpaceObject)_spaceObjects[i]);
            }
            
            // Show Quadtree on UI
            ShowQtree(qtree);

这在一段时间内运行良好,但随后我的转换器抛出DependencyProperty.UnsetValue错误。所以我开始打印我的转换器在进行任何转换之前收到的值:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            Trace.WriteLine($"({values[0]}. {values[1]})");
            var i = (decimal) values[0];
            var y = (decimal) values[1];
            var a = (int) i;
            var b = (int) y;
            return new Point(a, b);
        }

现在是奇怪的部分。我还打印行星的x,y值(用于调试目的(。如果可观察集合中只存在一个spaceObject,则输出如下。

Kobol: (127,5, 12,0)
(127,5. 18,0)
Kobol: (127,8, 11,4)
(127,5. 11,4)                 <<<<< right here
({DependencyProperty.UnsetValue}. 11,4)

似乎就在它尝试转换任何东西之前,转换器有正确的值!我把"就在这里"放在你可以看到转换器内部值的地方。下一刻,它似乎又进入了转换器,现在它没有值了。我敢打赌,实际的行星确实有一个X和Y值(但不能检查这个,因为应用程序在调试时会冻结:((。这种移动算法没有改变,在这种方法之外,没有任何问题(仍然没有任何问题(。

有人有什么想法或建议吗?

如果不清楚,请告诉我。我将删除并在需要的地方添加详细信息。

编辑**

在评论了大多数涉及移动和四叉树的方法之后,我让它像最复杂的移动方法一样工作。可能是我的方法太大了吗?我忘了提到它在Timer线程内部运行。。。。也许它太慢会导致问题?

您的XYPositionConverter必须处理此特殊值。WPF在探测转换器时将使用DependencyProperty.UnsetValue。这通常发生在创建DataTemplate时,可能在视图之外。

所以,只要确保在你的转换器中处理这个:

public class XYPositionConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null ||
            values.Any(x => x == null || x == DependencyProperty.UnsetValue))
        {
            return DependencyProperty.UnsetValue;
        }
        // ...
        return result;
    }
    // ...
}

相关内容

  • 没有找到相关文章

最新更新