Не може да се актуализира изображението в картинната кутия

Създавам малка игра Reversi/Othello и в моя метод за рисуване на дъската имам вложен for цикъл за показване на решетка от PictureBoxes, всяка с изображение.

При първото извикване на метода всички PictureBoxes се създават правилно и изображенията се поставят вътре. Но ако след това извикам метода отново, не мога да презапиша изображенията, които вече са там.

Проучвах известно време и доколкото разбирам, може да има нещо общо със заключването на PictureBox или необходимостта от правилно Dispose() на PictureBox, преди да напише друго изображение в него. Въпреки това не можах да накарам нито едно от тези решения да работи, така че всяка конкретна помощ ще бъде много оценена!

private void Draw()
{
    Bitmap White = Properties.Resources.white;
    Bitmap Black = Properties.Resources.black;
    Bitmap None = Properties.Resources.none;

    for (int r = 0; r <= grid.GetUpperBound(0); r++)
    {
        for (int c = 0; c <= grid.GetUpperBound(0); c++)
        {
            if (grid[r, c].value == 1)
            {
                var picbox = new PictureBox()                // initialise picturebox for displaying images
                {
                    Name = grid[r, c].name,
                    Size = new Size(64, 64),
                    Location = new Point(r * 65 + 15, c * 65 + 60),
                    Text = grid[r, c].name,
                    Image = White
                };

                Controls.Add(picbox);                // add picturebox to form 
                picbox.Click += ClickBox;
                MessageBox.Show("white draw" + grid[r, c].name);
            }

            if (grid[r, c].value == -1)
            {
                var picbox = new PictureBox()
                {
                    Name = grid[r, c].name,
                    Size = new Size(64, 64),
                    Location = new Point(r * 65 + 15, c * 65 + 60),
                    Text = grid[r, c].name,
                    Image = Black
                 };

                Controls.Add(picbox);
                picbox.Click += ClickBox;
                MessageBox.Show("black draw" + grid[r, c].name);
            }

            if (grid[r, c].value == 0)
            {
                var picbox = new PictureBox()
                {
                    Name = grid[r, c].name,
                    Size = new Size(64, 64),
                    Location = new Point(r * 65 + 15, c * 65 + 60),
                    Text = grid[r, c].name,
                    Image = None
                };

                Controls.Add(picbox);
                picbox.Click += ClickBox;
            }
        }
    }
}

person MBrazier4    schedule 11.04.2016    source източник
comment
Можете ли да покажете как работи целият метод?   -  person Valentin    schedule 11.04.2016
comment
Сигурен! Редактирано за добавяне на целия метод.   -  person MBrazier4    schedule 11.04.2016
comment
И какво е grid?   -  person Valentin    schedule 11.04.2016
comment
@Valentin това е 2d масив, който съдържа информация за всяка фигура на дъската, като нейната стойност.   -  person MBrazier4    schedule 11.04.2016
comment
Имате ли само една кутия за снимки? С местоположение равно на Location = new Point(r * 65 + 15, c * 65 + 60)   -  person Valentin    schedule 11.04.2016
comment
@Valentin това е решетка 8x8 от кутии за картини, създадена по метода по-горе. Ако има по-добър начин да го направя, който ще реши проблема ми, тогава ще се радвам да го променя!   -  person MBrazier4    schedule 11.04.2016
comment
Къде актуализирате? Виждам само, че добавяте нови контроли на PictureBox.   -  person LarsTech    schedule 11.04.2016
comment
Изглежда, че напълно пресъздавате всичко при всяко извикване на този метод, което изглежда неправилно. Трябва да създадете вашите PictureBoxes само веднъж и да ги добавите към колекцията Controls също само веднъж. След това трябва само да промените свойствата на контролите, като например Изображение. Ако стартирате играта наново и извиквате този метод, тогава се уверете, че колекцията Controls е изчистена и попълнена правилно. Може обаче да не се налага да правите това в зависимост от вашия дизайн. Може просто да успеете да изчистите съществуващите свойства на контролите, готови за ново начало.   -  person ManoDestra    schedule 11.04.2016
comment
@ManoDestra Благодаря за приноса. Чувствах се малко странно, създавайки отново кутиите за снимки всеки път. Новият ми въпрос би бил, че след като веднъж създам картинните кутии, как да ги препратя по-късно, за да променя свойствата? ако опитам да направя picbox.Image, той казва, че името не съществува в текущия контекст   -  person MBrazier4    schedule 11.04.2016
comment
Трябва да съхранявате препратки на ниво частен клас към масива от картинни кутии. Те трябва да са достъпни за целия клас.   -  person ManoDestra    schedule 11.04.2016
comment
Ако вашите PictureBox имат уникални имена, тогава можете да ги препратите с това име: PictureBox pb = Controls["cellname"] as PictureBox;   -  person LarsTech    schedule 11.04.2016
comment
@ManoDestra Точно! Как да запазя референции за картинните кутии? Дадох им имена, но това не изглежда да е същото като препратка.   -  person MBrazier4    schedule 11.04.2016
comment
Поставете ги в горната част на вашата дефиниция на клас, напр. Private PictureBox[,] picBoxArray; След това изградете този масив само веднъж. След това се обърнете към него по-късно чрез picBoxArray[3, 4].Image = <code here for new image object>; Нещо подобно.   -  person ManoDestra    schedule 11.04.2016


Отговори (1)


Проблемът е, че създавате нова картинна кутия, но не премахвате/актуализирате съществуващата картинна кутия от Controls. Първо трябва да намерите кутия с картинка, която искате да актуализирате или премахнете от Controls.

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

private var pictureGrid = new PictureBox[8, 8];

И тогава

if (grid[r, c].value == 1)
{
    if (pictureGrid[r,c] != null) 
    {
        pictureGrid[r,c].Image = White;
    } 
    else 
    {
        var picbox = new PictureBox()                
        {
            Name = grid[r, c].name,
            Size = new Size(64, 64),
            Location = new Point(r * 65 + 15, c * 65 + 60),
            Text = grid[r, c].name,
            Image = White
        };

        pictureGrid[r,c] = picbox; 
        Controls.Add(picbox);                
        picbox.Click += ClickBox;
        MessageBox.Show("white draw" + grid[r, c].name);
    }
}

Можете също да използвате Речник, който съдържа двойки (grid.Value - Цвят).

private Dictionary<int, Bitmap> colors = new  Dictionary<int, Bitmap>();

private void Load() 
{
    Bitmap White = Properties.Resources.white;
    Bitmap Black = Properties.Resources.black;
    Bitmap None = Properties.Resources.none;

    colors.Add(1, White);
    colors.Add(-1, Black);
    colors.Add(0, None);
}

Така че вашият метод ще изглежда така

private var pictureGrid = new PictureBox[8, 8];    
private Dictionary<int, Bitmap> colors = new  Dictionary<int, Bitmap>();

private void Load() 
{
    Bitmap White = Properties.Resources.white;
    Bitmap Black = Properties.Resources.black;
    Bitmap None = Properties.Resources.none;

    colors.Add(1, White);
    colors.Add(-1, Black);
    colors.Add(0, None);
}

private void Draw()
{
    for (int r = 0; r <= grid.GetUpperBound(0); r++)
    {
        for (int c = 0; c <= grid.GetUpperBound(0); c++)
        {
            if (pictureGrid[r, c] != null) 
            {
                pictureGrid[r,c].Image = colors[grid[r,c]];
            }

            else 
            {
                var picbox = new PictureBox()
                {
                    Name = grid[r, c].name,
                    Size = new Size(64, 64),
                    Location = new Point(r * 65 + 15, c * 65 + 60),
                    Text = grid[r, c].name,
                    Image = colors[grid[r,c]]
                 };

                pictureGrid[r,c] = picbox;
                Controls.Add(picbox);
                picbox.Click += ClickBox;
                MessageBox.Show("black draw" + grid[r, c].name);

            }

        }
    }
}

Също така можете да намерите полето с картинка за актуализиране с помощта на linq

var pictureToRemove = this.Controls.OfType<PictureBox>().Where(x => x.Location.X == r * 65 + 15 && x.Location.Y == c * 65 + 60).First();
person Valentin    schedule 11.04.2016
comment
Изхвърляйте, а не премахвайте, освен ако не искате да го използвате отново в бъдеще. - person LarsTech; 11.04.2016
comment
Ах, разбирам какво имаш предвид! Това може да е нубски въпрос, но как да направя препратка към картинните кутии, които създадох? ако просто използвам „picbox“, това казва, че името не съществува в текущия контекст. благодаря за цялата ви помощ btw! - person MBrazier4; 11.04.2016
comment
@MBrazier4 Актуализирах отговора. Мисля, че решението с решетка от кутии за картини е най-рационално. - person Valentin; 11.04.2016
comment
@Valentin Благодаря много! Мисля, че си прав да направиш мрежа от картинни кутии веднъж и след това да ги препратиш оттам. Ще се опитаме да приложим това сега. Наздраве за отделеното време! - person MBrazier4; 11.04.2016
comment
@MBrazier4 Добавих и един съвет с речника, вижте това :) - person Valentin; 11.04.2016
comment
@Valentin Всичко работи перфектно досега! Подсказката за речника, която дадохте, е наистина елегантна, изчиства много кода! Благодаря отново приятел - person MBrazier4; 11.04.2016