C # Winforms Размер вкладки и ClientSize неправильно - PullRequest
0 голосов
/ 21 мая 2019

Я создал пользовательский элемент управления, который содержит TabControl с 2 TabPages.Положение дочерних элементов управления на обеих вкладках TabPage адаптируется программно в событии Layout пользовательского элемента управления.
Проблема заключается в том, что 2-я TabPage еще не была нарисована при вызове события, и поэтому эта TabPage имеетнеправильный размер и размер клиента.

Как я могу обойти это?
Я пробовал цикл с var oHandle = tabpage.Handle и tabctrl.SelectedTab = each tabpage уже для принудительного создания TabPages, но это не помогло.

РЕДАКТИРОВАТЬ # 1
Я обнаружил первую «ошибку», которая наблюдается в конструкторе VS:
Когда вы перетаскиваете TabControl на форму и затем изменяете размерэто в Designer, размер видимого в данный момент TabPage обновляется.Но размеры всех других вкладок не являются;они остаются неизменными до тех пор, пока не будут внесены какие-либо дополнительные изменения в какой-либо элемент управления (проверено!).
Я допускаю, что эта ситуация довольно необычна, поэтому размеры обычно обновляются, но, тем не менее, на мой взгляд, это ошибка дизайна в TabControl.

Этот недостаток дизайна становится очень актуальным, когда во время выполнения изменяется размер TabControl!Вот минимальный пример для воспроизведения (без UC, просто TabControl в форме):

Form1.cs:

public Form1 ()
{
  InitializeComponent ();

  Debug.Print ("ctor before resize");
  Debug.Print ("TC: " + tabControl1.Size);
  Debug.Print ("T1: " + tabPage1.Size);
  Debug.Print ("T2: " + tabPage2.Size);

  tabControl1.Size = tabControl1.Size + new Size (10, 10);
  Debug.Print ("ctor after resize");
  Debug.Print ("TC: " + tabControl1.Size);
  Debug.Print ("T1: " + tabPage1.Size);
  Debug.Print ("T2: " + tabPage2.Size);
}

private void Form1_Load (object sender, EventArgs e)
{
  ... same as ctor, prints adapted ("load before/after resize)
}

private void Form1_Layout (object sender, LayoutEventArgs e)
{
  Debug.Print ("Layout");
}

private void button1_Click (object sender, EventArgs e)
{
  ... same as ctor, prints adapted ("button before/after resize)
}

Form1.Designer.cs: (удалены несущественные части)

private void InitializeComponent ()
{
  this.tabControl1 = new System.Windows.Forms.TabControl ();
  this.tabPage1 = new System.Windows.Forms.TabPage ();
  this.tabPage2 = new System.Windows.Forms.TabPage ();
  this.button1 = new System.Windows.Forms.Button ();
  this.tabControl1.SuspendLayout ();
  this.SuspendLayout ();
  //
  this.tabControl1.Controls.Add (this.tabPage1);
  this.tabControl1.Controls.Add (this.tabPage2);
  this.tabControl1.Size = new System.Drawing.Size (300, 120);
  //
  this.tabPage1.Size = new System.Drawing.Size (292, 91);
  //
  this.tabPage2.Size = new System.Drawing.Size (292, 91);
  //
  this.button1.Click += new System.EventHandler (this.button1_Click);
  //
  this.AutoScaleDimensions = new System.Drawing.SizeF (96F, 96F);
  this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
  this.ClientSize = new System.Drawing.Size (384, 262);
  this.Controls.Add (this.tabControl1);
  this.Controls.Add (this.button1);
  this.Load += new System.EventHandler (this.Form1_Load);
  this.tabControl1.ResumeLayout (false);
  this.ResumeLayout (false);
}
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.Button button1;

Отладочные отпечатки:

ctor before resize
TC: {Width=300, Height=120}
T1: {Width=292, Height=91}
T2: {Width=292, Height=91}
Layout
Layout
ctor after resize
TC: {Width=310, Height=130}
T1: {Width=292, Height=91}    (wrong)
T2: {Width=292, Height=91}    (wrong)

Load before resize
TC: {Width=310, Height=130}
T1: {Width=302, Height=101}    (now correct because updated after ctor)
T2: {Width=302, Height=101}    (now correct because updated after ctor)
Layout
Layout
Load after resize
TC: {Width=320, Height=140}
T1: {Width=312, Height=111}    (correct because visible)
T2: {Width=302, Height=101}    (wrong again)
Layout

(TabPage1 selected, TabPage2 is not updated)
button before resize
TC: {Width=320, Height=140}
T1: {Width=312, Height=111}
T2: {Width=302, Height=101}    (still wrong: TabPage2 HAS NOT BEEN UPDATED WHILE THE UI-THREAD WAS IDLE)
Layout
Layout
button after resize
TC: {Width=330, Height=150}
T1: {Width=322, Height=121}
T2: {Width=302, Height=101}    (even more wrong)

(TabPage1 selected, TabPage2 is not updated)
button before resize
TC: {Width=330, Height=150}
T1: {Width=322, Height=121}
T2: {Width=302, Height=101}    (still wrong)
Layout
Layout
button after resize
TC: {Width=340, Height=160}
T1: {Width=332, Height=131}
T2: {Width=302, Height=101}    (again more wrong)

(TabPage2 selected, now TabPage1 is not updated)
button before resize
TC: {Width=340, Height=160}
T1: {Width=332, Height=131}
T2: {Width=332, Height=131}    (now correct because visible)
Layout
Layout
button after resize
TC: {Width=350, Height=170}
T1: {Width=332, Height=131}    (now wrong)
T2: {Width=342, Height=141}    (still correct because visible)

Исходя из этого поведения, единственное решение, которое у меня сейчас есть, - это вызов функции UpdateLayout() моего UC при каждом вызове tabControl1_SelectedIndexChanged (..).

РЕДАКТИРОВАНИЕ # 2
«Решение» Редактирования # 1 не работает, потому что:
Если TabPages имеют небольшую ширину, элементы управления на страницах расположены вертикально, что приводит кбольшая высота соответствующей вкладки.Общая высота UC зависит от высоты TabControl, высота которого зависит от всех TabPages, поэтому UpdateLayout() должен иметь правильные размеры всех TabPages, иначе высота UC изменится позже, когда будет выбрана другая вкладка, ноэто должно быть правильно уже во время разработки.

1 Ответ

0 голосов
/ 22 мая 2019

Я нашел довольно простое решение, чтобы получить правильный размер TabPages:

Все TabPages принадлежат одному и тому же TabControl, поэтому все TabPages имеют одинаковый размер, независимо от того, что говорит свойство Size соответствующей TabPage.
Кроме того, всегда есть одна вкладка, которая сообщает правильный размер, который является выбранной в данный момент вкладкой.
Поэтому размер каждой вкладки составляет TabControl.SelectedTab.Size.

EDIT:
К сожалению, это НЕ работает, если весь TabControl не виден, возможно, потому что он помещен на TabPage другого TabControl, который в данный момент не выбран.
Тем не менее, я нашел другое решение, которое я написал как ответ на этот вопрос Могу ли я заставить TabControl изменять размер *, прежде чем они будут выбраны? 1019 *, что на самом деле больше или меньше моего вопроса.
Соответствующая часть этого ответа:

[...]
Вы должны добавить только 1 строку к вашему коду:

var oSize = i_oTabControl.DisplayRectangle.Size;

и избегайте того, чтобы он, вероятно, был оптимизирован компилятором:

[MethodImpl (MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
public static void TabControlForceUpdateOfTabpageSize (this TabControl i_oTabControl)
{
  if (i_oTabControl == null)
    return;
  var oSize = i_oTabControl.DisplayRectangle.Size;
}

[...]

...