Tripper Tripper - 16 days ago 6
C# Question

C# Delete UIElement whenever another UIElement passes him

I have made a Canvas (playArea) on which I added 1 Bee (by using

playArea.children.Add(bee)
). And I also add new
box
every X seconds at random points on the
playArea
. I'm able to move my
bee
from the current point to the point I click using
Storyboard
and
DoubleAnimation
.

What I want to do is I want to delete the
box
which
bee
is passing through (like it should just do
playAre.Children.Remove(box)
. I just can't figure it out how to check it.

example

Here's an example. If I would click on A, my
bee
would go to that point and remove the 3 boxes on it's way. I was thinking I should probably use my own
EventHandler
(I'm not sure how to make my own yet, but that's another problem). So any ides what should I do, or what condition I should make?

EDIT:
Here's how my methods I use looks like. What I do at the beggining, I just draw a bee and add it to my canvas, and every X seconds I just add a new box at random location

//moving the bee to the position which I got from Point p = Mouse.GetPosition(playArea);
public static void MoveBee(UIElement element, double toX, double toY)
{
double fromX = Canvas.GetLeft(element);
double fromY = Canvas.GetTop(element);

Storyboard storyboard = new Storyboard();
DoubleAnimation animationX = CreateDoubleAnimation(element,
fromX, toX, new PropertyPath(Canvas.LeftProperty));
DoubleAnimation animationY = CreateDoubleAnimation(element,
fromY, toY, new PropertyPath(Canvas.TopProperty));
storyboard.Children.Add(animationX);
storyboard.Children.Add(animationY);
storyboard.Begin();
}

public static DoubleAnimation CreateDoubleAnimation(UIElement element,
double from, double to, PropertyPath propertyToAnimate)
{
DoubleAnimation animation = new DoubleAnimation();
Storyboard.SetTarget(animation, element);
Storyboard.SetTargetProperty(animation, propertyToAnimate);
animation.From = from;
animation.To = to;
animation.Duration = TimeSpan.FromSeconds(3);
return animation;
}

public void DrawBox()
{
BoxControl newBox = new BoxControl();
playArea.Children.Add(newBox);
Canvas.SetTop(newBox, random.Next(0, 419));
Canvas.SetLeft(newBox, random.Next(0, 792));
}

Answer

You could use the CurrentTimeInvalidated event handler on your animations. See code below for details.

Valid XHTML


public partial class MainWindow : Window
{
    public Random Rng { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        Rng = new Random(0);

        do
        {
            AddBoxToRandomPointInPlayArea();
        } while (PlayArea.Children.Count < 10);

    }

    private void AddBoxToRandomPointInPlayArea()
    {
        var x = Rng.Next(0, Convert.ToInt32(PlayArea.Width));
        var y = Rng.Next(0, Convert.ToInt32(PlayArea.Height));

        var box = new Rectangle
        {
            Height = 10,
            Width = 30,
            Fill = Brushes.Brown
        };

        PlayArea.Children.Add(box);

        Canvas.SetLeft(box, x);
        Canvas.SetTop(box, y);
    }

    private void PlayArea_MouseDown(object sender, MouseButtonEventArgs e)
    {
        var x = Canvas.GetLeft(Bee);
        var y = Canvas.GetTop(Bee);

        var storyboard = new Storyboard();

        var xTranslation = new DoubleAnimation(x, e.GetPosition(PlayArea).X, new Duration(new TimeSpan(0, 0, 5)));
        Storyboard.SetTargetProperty(xTranslation, new PropertyPath(Canvas.LeftProperty));
        xTranslation.CurrentTimeInvalidated += CheckForCollidingBoxesAndRemoveIfNeeded;

        storyboard.Children.Add(xTranslation);

        var yTranslation = new DoubleAnimation(y, e.GetPosition(PlayArea).Y, new Duration(new TimeSpan(0, 0, 5)));
        Storyboard.SetTargetProperty(yTranslation, new PropertyPath(Canvas.TopProperty));
        yTranslation.CurrentTimeInvalidated += CheckForCollidingBoxesAndRemoveIfNeeded; 

        storyboard.Children.Add(yTranslation);

        Bee.BeginStoryboard(storyboard);
    }


    private void CheckForCollidingBoxesAndRemoveIfNeeded(object sender, EventArgs eventArgs)
    {
        var idxToRemoveAt = GetIndexOfBoxCollidingWithBee;
        if ( idxToRemoveAt != -1 )
        {
            PlayArea.Children.RemoveAt(idxToRemoveAt);
        }
    }

    /// <summary>
    /// returns 0 if no boxes collide, otherwise the number is the index of the box in the 
    /// </summary>
    public int GetIndexOfBoxCollidingWithBee
    {
        get
        {
            var beeTopLeft = PointToScreen(new Point(Canvas.GetLeft(Bee), Canvas.GetTop(Bee))); // local to world coordinates
            var beeCentroid = new Point((beeTopLeft.X + Bee.ActualWidth) * 0.5, (beeTopLeft.Y + Bee.ActualHeight) * 0.5); // center point of bee

            for (var idx = 0; idx < PlayArea.Children.Count; idx++)
            {
                var child = PlayArea.Children[idx];
                var currentBoxInSearch = child as Rectangle;
                if (currentBoxInSearch != null)
                {
                    var boxTopLeft = PointToScreen(new Point(Canvas.GetLeft(currentBoxInSearch), Canvas.GetTop(currentBoxInSearch))); // local to world coordinates
                    var boxCentroid = new Point((boxTopLeft.X + currentBoxInSearch.ActualWidth) * 0.5, (boxTopLeft.Y + currentBoxInSearch.ActualHeight) * 0.5); // center point of bee

                    var xCollided = false;
                    var yCollided = false;

                    if (Math.Abs(beeCentroid.X - boxCentroid.X) < Bee.ActualWidth*0.5)
                        xCollided = true;

                    if (Math.Abs(beeCentroid.Y - boxCentroid.Y) < Bee.ActualHeight*0.5)
                        yCollided = true;

                    if (xCollided && yCollided)
                        return idx;
                }
            }

            return -1;
        }
    }
}