在两个列表中的对象不会在一个列表中找到

本文关键字:列表 一个 对象 两个 | 更新日期: 2023-09-27 18:12:12

我有一些奇怪的行为,我不能解释:我在WPF-Canvas中有一个省略号列表,我想让它闪烁。出于性能目的,我将新创建的星星添加到Canvas(其中包含更多对象)和一个本地列表中。这意味着我可以只使用本地列表,而不必每次都重新检查Children-Collection。我的代码是这样的:

    private const Int32 STAR_COUNT = 500;
    private readonly double STAR_MOVE_RATE = GameObject.OBJECTS_MOVE_RATE/2;
    private readonly Timer _blinkingTimer = new Timer();
    private readonly Canvas _gameField;
    private readonly List<Ellipse> _stars = new List<Ellipse>();
    public StarHandler(Canvas gameField)
    {
        _gameField = gameField;
        _blinkingTimer.Interval = 70;
        _blinkingTimer.Elapsed += _blinkingTimer_Elapsed;
        for (int i = 0; i < STAR_COUNT; i++)
            AddSetStar(StarFactory.CreateStar());
        _blinkingTimer.Start();
    }
    private void AddSetStar(Ellipse star)
    {
        Canvas.SetTop(star, GameObject.Random.Next(GameObject.LEVEL_HEIGHT));
        Canvas.SetLeft(star, GameObject.Random.Next(GameObject.LEVEL_WIDTH));
        Panel.SetZIndex(star, 0);
        _gameField.Children.Add(star);
        _stars.Add(star);
    }
    private void _blinkingTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        ThreadingHelper.ThreadingAction(() =>
        {
            Ellipse star = _stars.ElementAt(GameObject.Random.Next(STAR_COUNT));
            _gameField.Children.Remove(star);
            _stars.Remove(star);
            var newStar = StarFactory.CreateStar();
            AddSetStar(newStar);
        });
    }

StarFactory只是创建这样一个椭圆并返回它。我不明白的是:

_gameField.Children.Remove(star);

只适用于我在构造函数中添加的星星。我在计时器上添加的星星在儿童列表上找不到。

我真的不知道,为什么这个元素找不到,因为我每次都在两个列表中添加新创建的星星。

注:: ThreadingAction只是一个帮助工作的ui线程:

    internal static void ThreadingAction(Action action)
    {
        if (Thread.CurrentThread == Application.Current.Dispatcher.Thread)
            action();
        else 
            Application.Current.Dispatcher.Invoke(action);
    }
编辑:我持有两个列表的原因是:如果我想处理List,我使用:
_stars.ForEach(f =>

如果没有这个,我将不得不

        _gameField.Children.OfType<Ellipse>().ToList().ForEach(f => )

这是2个枚举,一个用于OfType,一个用于tollist。如果我加上其他不是星星的椭圆呢?

关于星星的构造:我只在两个位置这样做:在Timer-Elapsed Event和构造函数中。那么Children-List不指向对象吗?所以星星是相同的引用,因为我每次在两个列表中添加相同的引用。

在两个列表中的对象不会在一个列表中找到

您的代码有许多问题。我将依次尝试解决每一个问题。首先,你说你

将新创建的星星添加到Canvas(它可以容纳更多的对象)和一个本地列表中。这意味着我可以只使用本地列表,而不必每次

都重新检查Children-Collection。

然而,这样做没有任何好处。Children收集点指向内存中的某个位置,而您的收集点指向另一个位置……几乎没有差别。

我没有得到的:Children.Remove(star)只适用于我在构造函数

中添加的星星

这是因为您只能从集合中删除该项,如果该项恰好在集合中。因此,您不能生成具有某些属性值的新对象,并期望它与具有相同属性值的另一个对象相等…它们在内存中是不同的对象。所以,为了解决这个问题,你可以使用LinQ做这样的事情:

_gameField.Children.Remove(_gameField.Children[0]);

然而,我认为您的最后一个错误是您不应该像您那样将这些对象删除并重新添加到Children集合中。相反,将对象留在Children集合中并且仅仅将它们的Visiblity值从Visible更改为Hidden并反复返回更有意义。也许像这样:

foreach (UIElement element in Canvas.Children)
{
    element.Visibility = element.Visibility == Visibility.Hidden ? 
        Visibility.Visible : Visibility.Hidden;
}