Проблема с производительностью при добавлении элементов управления на панель в C#
Я создаю панель, а затем добавляю к ней несколько ярлыков / кнопок для формирования сетки. Проблема в том, что если я добавлю более 25х25 элементов на панель, произойдет ужасное снижение производительности. Я могу изменить размер формы в порядке, но когда я прокручиваю панель, чтобы увидеть все метки, которые запаздывает программа, метки / кнопки рвутся или мерцают, а иногда это может привести к тому, что программа перестает отвечать на запросы. Я попытался добавить элементы управления в "DoubleBufferedPanel", который я создал. Это, кажется, не имеет никакого эффекта. Что еще я мог сделать? Извините за такой большой листинг кода. Я не хотел терять чье-то время.
namespace GridTest
{
public partial class Form1 : Form
{
private const int COUNT = 50;
private const int SIZE = 50;
private Button[,] buttons = new Button[COUNT, COUNT];
private GridPanel pnlGrid;
public Form1()
{
InitializeComponent();
pnlGrid = new GridPanel();
pnlGrid.AutoScroll = true;
pnlGrid.Dock = DockStyle.Fill;
pnlGrid.BackColor = Color.Black;
this.Controls.Add(pnlGrid);
}
private void Form1_Load(object sender, EventArgs e)
{
int x = 0;
int y = 0;
int offset = 1;
for (int i = 0; i < COUNT; i++)
{
for (int j = 0; j < COUNT; j++)
{
buttons[i, j] = new Button();
buttons[i, j].Size = new Size(SIZE, SIZE);
buttons[i, j].Location = new Point(x, y);
buttons[i, j].BackColor = Color.White;
pnlGrid.Controls.Add(buttons[i, j]);
x = x + SIZE + offset;
}
x = 0;
y = y + SIZE + offset;
}
}
}
}
Также класс GridPanel:
namespace GridTest
{
public class GridPanel : Panel
{
public GridPanel()
: base()
{
this.DoubleBuffered = true;
this.ResizeRedraw = false;
}
}
}
2 ответа
Если вам необходимо добавить элементы управления во время выполнения, основываясь на некотором динамическом или изменяющемся значении, вы можете рассмотреть возможность создания изображения на лету и захвата событий щелчка мыши на его окне рисунка. Это будет намного быстрее и будет иметь только один элемент управления, а не сотни. Вы потеряете некоторые функции кнопок, такие как анимация щелчка и другие автоматические свойства и события; но вы можете воссоздать большинство тех, кто генерирует образ.
Это метод, который я использую, чтобы предложить пользователям возможность включать и выключать отдельные устройства из пула тысяч, когда значение в двухмерном пространстве имеет значение. Если расположение кнопок неважно, вам лучше предложить список элементов в виде списка или в комбинированном списке, или, как предлагают другие ответы, в виде таблицы данных со столбцами кнопок.
РЕДАКТИРОВАТЬ:
Пример, показывающий, как добавить рисунок с виртуальными кнопками. Очень простая реализация, но, надеюсь, вы получите идею:
Сначала несколько начальных переменных в качестве предпочтений:
int GraphicWidth = 300;
int GraphicHeight = 100;
int ButtonWidth = 60;
int ButtonHeight = 20;
Font ButtonFont = new Font("Arial", 10F);
Pen ButtonBorderColor = new Pen(Color.Black);
Brush ButtonTextColor = new SolidBrush(Color.Black);
Генерация изображения:
Bitmap ControlImage = new Bitmap(GraphicWidth, GraphicHeight);
using (Graphics g = Graphics.FromImage(ControlImage))
{
g.Clear(Color.White);
for (int x = 0; x < GraphicWidth; x += ButtonWidth)
for (int y = 0; y < GraphicHeight; y += ButtonHeight)
{
g.DrawRectangle(ButtonBorderColor, x, y, ButtonWidth, ButtonHeight);
string ButtonLabel = ((GraphicWidth / ButtonWidth) * (y / ButtonHeight) + x / ButtonWidth).ToString();
SizeF ButtonLabelSize = g.MeasureString(ButtonLabel, ButtonFont);
g.DrawString(ButtonLabel, ButtonFont, ButtonTextColor, x + (ButtonWidth/2) - (ButtonLabelSize.Width / 2), y + (ButtonHeight/2)-(ButtonLabelSize.Height / 2));
}
}
pictureBox1.Image = ControlImage;
И отвечая на Click
Событие pictureBox:
// Determine which "button" was clicked
MouseEventArgs em = (MouseEventArgs)e;
Point ClickLocation = new Point(em.X, em.Y);
int ButtonNumber = (GraphicWidth / ButtonWidth) * (ClickLocation.Y / ButtonHeight) + (ClickLocation.X / ButtonWidth);
MessageBox.Show(ButtonNumber.ToString());
Я думаю, что вы не сможете предотвратить мерцание, имея 625 кнопок (кстати, окна) на панели. Если такой макет является для вас обязательным, попробуйте использовать DataGridView, привязать его к поддельному источнику данных, содержащему необходимое количество столбцов и строк, и создать в нем DataGridViewButtonColumns. Это должно работать намного лучше, чем ваш текущий результат...