Перемещение Picturebox внутри TableLayoutPanel из одной ячейки в другую с задержкой

У меня есть TableLayoutPanel внутри формы, и этот TableLayoutPanel имеет пять элементов управления Picturebox внутри некоторых ячеек. Что я хотел бы сделать, так это переместить эти поля изображений в разные ячейки на основе списка координат, переданного в качестве аргумента. С точки зрения пользователя, эти графические блоки исчезнут из одной ячейки и снова появятся в другой (точно так же, как главный персонаж в основной игре с плиткой, где персонаж исчезает в одной ячейке и снова появляется в соседней ячейке). Метод обновления находится внутри класса Form и вызывается методом из другого класса. Проблема в том, что он не отображает каждое движение. Он просто показывает начальные позиции всех Picturebox'ов с последующим обновлением, а затем конечное положение. Он должен отображать PictureBoxes в каждой координате, прежде чем он перейдет к окончательной координате. Я пробовал Thread.Sleep (), но он не работает. Как мне решить эту проблему?

public partial class CheckerBoard : Form
{
   ....
   ....
   public void update(Position k, List<Position> p)                
   { 

        p1_picturebox.Visible = false;
        p2_picturebox.Visible = false;
        p3_picturebox.Visible = false;
        p4_picturebox.Visible = false;
        p5_picturebox.Visible = false;

        // Load images in new positions            

        this.board.Controls.Add(k_picturebox, k.col, knight.row);
        this.board.Controls.Add(p1_picturebox, p[0].col, p[0].row);
        this.board.Controls.Add(p2_picturebox, p[1].col, p[1].row);
        this.board.Controls.Add(p3_picturebox, p[2].col, p[2].row);
        this.board.Controls.Add(p4_picturebox, p[3].col, p[3].row);
        this.board.Controls.Add(p5_picturebox, p[4].col, p[4].row);  

        ------UPDATED---------
        this.Invalidate();
        Thread.Sleep(3000);

   }
}  

ОБНОВЛЕНИЕ Я исправил свой код в соответствии с предложениями. Однако проблема все еще сохраняется. Кажется, что он перерисовывает всю tablelayoutpanel вместо того, чтобы перемещать блок изображения из одной ячейки в другую. Я вижу обновление tablelayoutpanel.

    private void replay(State currentState)
    {            
        DispatcherTimer timer = new DispatcherTimer
        {
            Interval = TimeSpan.FromSeconds(0.5)
        };
        timer.Tick += (o, e) =>
        {
            List<Position> pos = new List<Position>();

            foreach(Position p in currentState.pawns)
            {
                pos.Add(p);
            }

            this.update(currentState.knight, pos);
            currentState = currentState.next;
            if (currentState == null)
            {
                timer.IsEnabled = false;
                //this.prepareDisplay();
            }
        };
        timer.IsEnabled = true;


    }


    public void update(Position knight, List<Position> pawns)                
    { 
        // Load images in new positions            
        this.board.Controls.Remove(knight_picturebox);
        this.board.Controls.Add(knight_picturebox, knight.col, knight.row);

        for(int i=0; i < pawns.Count; i++)
        { 
            //this.board.Controls.Add(this.picBoxList[i], pawns[i].col, pawns[i].row);
            this.picBoxList[i].WaitOnLoad = true;
            this.board.Controls.Remove(this.picBoxList[i]);
            this.board.Controls.Add(this.picBoxList[i], pawns[i].col, pawns[i].row);
        }

    }

ОБНОВЛЕНИЕ с помощью suspendLayout иhanceLayout улучшается перерисовка. Но мне интересно, можно ли не перерисовывать макет таблицы, а только графические блоки, чтобы казалось, что движутся только графические блоки.


person Andrew    schedule 16.02.2016    source источник
comment
На что вы нацеливаетесь: Winforms? WPF? ASP? ... ?? Всегда помечайте свой вопрос соответствующим образом! - Вместо Thread.Sleep вы должны использовать таймер для анимации в winforms.   -  person TaW    schedule 16.02.2016
comment
Вызов Sleep () в программе с графическим интерфейсом - очень плохая идея, вы никогда не захотите, чтобы поток реагировал на ввод пользователя и обновлял окно, чтобы оно стало кататоническим. Вы продвинетесь вперед, позвонив this.Update(); перед сном. Но дальше нужно научиться пользоваться таймером. Затем мы узнаем, как выглядит игровой цикл.   -  person Hans Passant    schedule 16.02.2016
comment
@TaW Это Winform. Обновил тег.   -  person Andrew    schedule 16.02.2016
comment
@Hans Passant: Я попробовал заснуть после вызова обновления, но результат точно такой же. Я посмотрю на таймер.   -  person Andrew    schedule 16.02.2016
comment
К сожалению, время не работает. Я не уверен, где я делаю не так   -  person Andrew    schedule 24.02.2016


Ответы (1)


Надеюсь, это сработает. Предполагая, что вы сделали временный список имен графических блоков в List, откуда вы можете извлечь имена и найти их, чтобы переместиться в другую позицию. Итак, в основном в моем методе вы просто перемещаете их позиции в другие ячейки в своей панели tablelayout. Вы можете оптимизировать его, используя цикл «foreach» для извлечения блоков изображений вместо повторения одной и той же функции Controls.Find () для каждого элемента control.name блока изображений.

public void update(Position k, List<Position> p)
    {
        PictureBox p1 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        PictureBox p2 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        PictureBox p3 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        PictureBox p4 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        PictureBox p5 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
        this.board.Controls.Remove(p1);
        this.board.Controls.Remove(p2);
        this.board.Controls.Remove(p3);
        this.board.Controls.Remove(p4);
        this.board.Controls.Remove(p5);

        //p1_picturebox.Visible = false;
        //p2_picturebox.Visible = false;
        //p3_picturebox.Visible = false;
        //p4_picturebox.Visible = false;
        //p5_picturebox.Visible = false;

        // Load images in new positions            

        //this.board.Controls.Add(k_picturebox, k.col, knight.row);
        this.board.Controls.Add(p1, p[0].col, p[0].row);
        this.board.Controls.Add(p2, p[1].col, p[1].row);
        this.board.Controls.Add(p3, p[2].col, p[2].row);
        this.board.Controls.Add(p4, p[3].col, p[3].row);
        this.board.Controls.Add(p5, p[4].col, p[4].row);

        //alternatively for the whole above code you may optimize like below.
        int i = 0;
        foreach(Control c in PictureBoxList)    //PictureBoxList is retrieved as List<Control>
        {
            PictureBox p1 = this.Controls.Find(c.Name, true).FirstOrDefault() as PictureBox;
            p1.Name = c.Name;   //assign new name from the same list which contains pictureboxes and can get name by using c.Name
            this.board.Controls.Remove(p1);
            this.board.Controls.Add(p1, p[i].col, p[i].row);
            i++;
        }


        ------UPDATED-------- -
        this.Invalidate();
        Thread.Sleep(3000);

    }

Обновление:

Вы пытались установить для свойства WaitOnLoad Picturebox значение true?

Обновление2:

Попробуйте сделать недействительными доску, а затем, в частности, новые поля для изображений.

person Sagar Maru    schedule 19.02.2016
comment
Я сделал, но не решил проблему. Вы можете увидеть это в моем обновленном коде. - person Andrew; 24.02.2016
comment
Вы хотите обновить всю таблицу в форме ?? Я имею в виду, есть ли какие-либо другие элементы управления, размещенные в tablelayout, кроме тех, которые вам нужно переместить? - person Sagar Maru; 25.02.2016