Я создаю проект WinForm, который отображает сообщения от сервера и клиента.Сообщения клиента добавляются с помощью стандартных событий пользовательского интерфейса, таких как Click и KeyPress.Сообщения сервера добавляются через фоновый поток, который прослушивает сообщения и «предупреждает» пользовательский интерфейс, когда они поступают.«Предупреждение» происходит через EventHandler, который затем использует метод Invoke, поскольку мы запрашиваем изменение пользовательского интерфейса из потока, который его не создавал.
Когда сообщения добавляются от клиента, они отображаются по желанию(т. е. правильно подобранного размера, обтекание и изменение размера выполняется правильно).Когда сообщения добавляются из фоновой цепочки через Invoke, только первое сообщение отображается правильно, и даже тогда только изначально.После изменения размера формы обертка перестает работать, и первое сообщение обрезается в зависимости от того, сколько места доступно.Сообщения после первого имеют совершенно неправильный размер, так как кажется, что их высота установлена в 1 пиксель или что-то очень маленькое, так что видны только вершины символов из первой строки.Поскольку я новичок в WinForms, я подозреваю, что я делаю что-то не так, как правильный способ программного добавления элементов управления в пользовательский интерфейс.
И клиент, и фоновый поток вызывают один и тот же метод для добавления элементов управленияк форме;только фон вызывает это через Invoke.Я в недоумении, почему добавленные элементы управления ведут себя по-разному в зависимости от события, из которого они возникли, потому что в любом случае они добавляются точно так же.Моя единственная мысль - я упускаю что-то очевидное, потому что я новичок в WinForms.
В любом случае, достаточно объяснения, вот соответствующий код:
private void AddMessage(string message)
{
tableLayoutPanel1.SuspendLayout();
RichTextBox rtb = new RichTextBox();
rtb.AppendText(message);
rtb.Multiline = true;
rtb.WordWrap = true;
rtb.Dock = DockStyle.Top;
rtb.ReadOnly = true;
rtb.BorderStyle = BorderStyle.None;
rtb.ScrollBars = RichTextBoxScrollBars.None;
rtb.BackColor = Color.LightBlue;
rtb.Font = new Font("Tahoma", 8, FontStyle.Italic);
rtb.Resize += rtb_Resize;
rtb.MinimumSize = new Size(150, 15);
rtb.Margin = new Padding(1, 0, 0, 5);
rtb.Padding = new Padding(3, 3, 3, 3);
rtb.Height = rtb.GetPositionFromCharIndex(rtb.Text.Length).Y;
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tableLayoutPanel1.RowCount = tableLayoutPanel1.RowStyles.Count;
tableLayoutPanel1.Controls.Add(rtb);
tableLayoutPanel1.SetColumnSpan(rtb, 2);
tableLayoutPanel1.ResumeLayout(true);
tableLayoutPanel1.AutoScrollPosition = new Point(0, tableLayoutPanel1.VerticalScroll.Maximum);
}
private void richTextBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13 && !String.IsNullOrEmpty(richTextBox1.Text))
{
AddMessage(richTextBox1.Text);
richTextBox1.Clear();
}
}
public void PostMessage(object sender, MessageEventArgs e)
{
BeginInvoke(new AddMsg(AddMessage), new object[] { e.Message });
}
public delegate void AddMsg(string m);
private void rtb_Resize(object sender, EventArgs e)
{
var rtb = (RichTextBox) sender;
rtb.Height = rtb.GetPositionFromCharIndex(rtb.Text.Length).Y;
}
Хорошо, теперь еще немногообъяснение.Сообщения клиента исходят из richTextBox1_KeyPress, а сообщения сервера - из PostMessage (PostMessage назначается EventHandler для фонового потока, когда он получает сообщение).Как вы можете видеть вызов AddMessage, который добавляет RichTextBox с сообщением в TableLayoutPanel.Метод rtb_Resize содержит логику для способа, который я нашел в Интернете, чтобы получить RickTextBox для автоматического размера, так как, очевидно, он не поддерживает это;возможно, это возможный источник моей проблемы.
Я также предоставлю код конструктора ниже для TableLayoutPanel, так как это, кажется, полезно и актуально из других постов, которые я видел здесь.
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.AutoScroll = true;
this.tableLayoutPanel1.AutoSize = true;
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.BackColor = System.Drawing.Color.White;
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 50F));
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(1, 10);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(5, 5, 12, 5);
this.tableLayoutPanel1.RowCount = 1;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(272, 276);
this.tableLayoutPanel1.TabIndex = 0;
TableLayoutPanel содержит начальную строку, так как конструктор не позволяет иметь ее без строк, но я очищаю все строки в конструкторе формы после стандартного вызова InitializeComponent.
НадеюсьЯ предоставил здесь достаточно информации, чтобы дать людям необходимую информацию, но, пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы или вам нужно просмотреть другие части кода, и я предоставлю их как можно быстрее.Также, если это имеет значение, я использую Visual Studio 2008 и .NET 3.5.
Спасибо.