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

Я делаю небольшую игру Reversi/Othello, и внутри моего метода рисования доски у меня есть вложенный цикл for для отображения сетки PictureBox, в каждом из которых есть изображение.

При первом вызове метода все PictureBox создаются правильно, а изображения помещаются внутрь. Однако, если я затем снова вызову метод, я не смогу перезаписать изображения, которые уже есть.

Я некоторое время занимался исследованиями, и, насколько я понимаю, это может быть связано с блокировкой 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 это двумерный массив, который содержит информацию о каждой фигуре на доске, например ее значение.   -  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
Кажется, что вы полностью воссоздаете все заново каждый раз, когда вызывается этот метод, что кажется неправильным. Вы должны создать свои PictureBox только один раз и добавить их в коллекцию Controls только один раз. Затем вам нужно будет только изменить свойства элементов управления, таких как Image. Если вы запускаете игру заново и вызываете этот метод, убедитесь, что коллекция 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 - Color).

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», это говорит, что имя не существует в текущем контексте. спасибо за всю вашу помощь кстати! - person MBrazier4; 11.04.2016
comment
@MBrazier4 Я обновил ответ. Я считаю решение с сеткой картинок наиболее рациональным. - person Valentin; 11.04.2016
comment
@Валентин Спасибо большое! Я думаю, вы правы в том, что один раз создали сетку картинок, а затем ссылаетесь на них оттуда. Сейчас попробую реализовать. Спасибо, что нашли время! - person MBrazier4; 11.04.2016
comment
@MBrazier4 Я также добавил одну подсказку со словарем, проверьте это :) - person Valentin; 11.04.2016
comment
@Valentin Пока все работает отлично! Подсказка словаря, которую вы дали, действительно элегантна, очищает код! Еще раз спасибо дружище - person MBrazier4; 11.04.2016