Author SHA1 Message Date
redlineoandClaude Sonnet 5 f1c67669fd Fix template list becoming unclickable with many entries via Dock layout
lstTemplates was a direct child of tabTemplates with an explicit pixel
Size, computed once against this dev machine's tab-strip height under
its own DPI/font scale. On the operator's real machine, adding enough
templates pushed rows past the control's actual bottom edge -
maximizing the window didn't help, confirming it wasn't a screen-space
problem but a stale size assumption baked into the designer file (the
same root cause as the earlier add/remove-button visibility bug).

Moved the button strip + list into their own panel (pnlTemplateList),
with the buttons Dock=Top and lstTemplates Dock=Fill - the list's
bounds are now computed by the layout engine against the real
container at runtime, with no absolute size to be wrong about,
regardless of DPI/font scale/window size.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 12:39:49 +03:00
@@ -35,6 +35,8 @@ namespace BulkArchiveMailer.AddIn.UI
private System.Windows.Forms.Label lblFromAccount; private System.Windows.Forms.Label lblFromAccount;
private System.Windows.Forms.ComboBox cboFromAccount; private System.Windows.Forms.ComboBox cboFromAccount;
private System.Windows.Forms.Panel pnlTemplateList;
private System.Windows.Forms.Panel pnlTemplateButtons;
private System.Windows.Forms.ListBox lstTemplates; private System.Windows.Forms.ListBox lstTemplates;
private System.Windows.Forms.Button btnAddTemplate; private System.Windows.Forms.Button btnAddTemplate;
private System.Windows.Forms.Button btnRemoveTemplate; private System.Windows.Forms.Button btnRemoveTemplate;
@@ -80,6 +82,8 @@ namespace BulkArchiveMailer.AddIn.UI
this.lblFromAccount = new System.Windows.Forms.Label(); this.lblFromAccount = new System.Windows.Forms.Label();
this.cboFromAccount = new System.Windows.Forms.ComboBox(); this.cboFromAccount = new System.Windows.Forms.ComboBox();
this.pnlTemplateList = new System.Windows.Forms.Panel();
this.pnlTemplateButtons = new System.Windows.Forms.Panel();
this.lstTemplates = new System.Windows.Forms.ListBox(); this.lstTemplates = new System.Windows.Forms.ListBox();
this.btnAddTemplate = new System.Windows.Forms.Button(); this.btnAddTemplate = new System.Windows.Forms.Button();
this.btnRemoveTemplate = new System.Windows.Forms.Button(); this.btnRemoveTemplate = new System.Windows.Forms.Button();
@@ -105,6 +109,8 @@ namespace BulkArchiveMailer.AddIn.UI
this.tabControl.SuspendLayout(); this.tabControl.SuspendLayout();
this.tabGeneral.SuspendLayout(); this.tabGeneral.SuspendLayout();
this.tabTemplates.SuspendLayout(); this.tabTemplates.SuspendLayout();
this.pnlTemplateList.SuspendLayout();
this.pnlTemplateButtons.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
@@ -213,9 +219,7 @@ namespace BulkArchiveMailer.AddIn.UI
this.tabTemplates.Text = "Шаблоны"; this.tabTemplates.Text = "Шаблоны";
this.tabTemplates.Padding = new System.Windows.Forms.Padding(12); this.tabTemplates.Padding = new System.Windows.Forms.Padding(12);
this.tabTemplates.UseVisualStyleBackColor = true; this.tabTemplates.UseVisualStyleBackColor = true;
this.tabTemplates.Controls.Add(this.btnAddTemplate); this.tabTemplates.Controls.Add(this.pnlTemplateList);
this.tabTemplates.Controls.Add(this.btnRemoveTemplate);
this.tabTemplates.Controls.Add(this.lstTemplates);
this.tabTemplates.Controls.Add(this.lblTplDisplayName); this.tabTemplates.Controls.Add(this.lblTplDisplayName);
this.tabTemplates.Controls.Add(this.txtTplDisplayName); this.tabTemplates.Controls.Add(this.txtTplDisplayName);
this.tabTemplates.Controls.Add(this.lblTplFileSuffix); this.tabTemplates.Controls.Add(this.lblTplFileSuffix);
@@ -230,50 +234,74 @@ namespace BulkArchiveMailer.AddIn.UI
this.tabTemplates.Controls.Add(this.txtTplBody); this.tabTemplates.Controls.Add(this.txtTplBody);
this.tabTemplates.Controls.Add(this.lblTplHint); this.tabTemplates.Controls.Add(this.lblTplHint);
// btnAddTemplate / btnRemoveTemplate // pnlTemplateList
// //
// Deliberately placed ABOVE lstTemplates (not below it) so // Left-column container for the template picker (buttons +
// their visibility never depends on how much vertical room is // list). Its own outer Location/Size/Anchor still use fixed
// left over at the bottom of the tab page after the list - // pixel coordinates relative to the tab page, exactly like
// that computation (tab-strip height under the operator's // before - that outer placement was never the problem. What
// actual DPI/font scale, which this code cannot know at design // is Dock-based from here down is everything INSIDE this
// time) is exactly what went wrong before: lstTemplates ran all // panel, which is the part that actually broke on a real
// the way to the tab page's real bottom edge with only ~6px to // machine: lstTemplates used to be a direct child of
// spare for the buttons beneath it, which was enough on some // tabTemplates with an explicit Size, so its bottom edge (and
// machines and not on others. Anchored Top|Left (fixed // therefore its scrollability/clickability once many
// distance from the tab page's top-left corner) rather than // templates were added) depended on a hand-computed pixel
// Bottom, they are visible as long as the tab page itself is // height that was only ever verified on the dev machine's own
// visible at all - not merely as long as it is "tall enough". // DPI/font scale. Docking removes that computation entirely -
this.btnAddTemplate.Location = new System.Drawing.Point(15, 20); // see pnlTemplateButtons/lstTemplates below.
this.pnlTemplateList.Location = new System.Drawing.Point(15, 20);
this.pnlTemplateList.Size = new System.Drawing.Size(190, 467);
this.pnlTemplateList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
// Dock order matters here: pnlTemplateButtons (Dock=Top) is
// added FIRST, lstTemplates (Dock=Fill) SECOND, so the Fill
// control's layout is computed against whatever client area
// remains under the already-docked top strip.
this.pnlTemplateList.Controls.Add(this.pnlTemplateButtons);
this.pnlTemplateList.Controls.Add(this.lstTemplates);
// pnlTemplateButtons
//
// Fixed-height strip pinned to the top of pnlTemplateList.
// btnAddTemplate/btnRemoveTemplate live inside it at a fixed
// offset from ITS top-left corner (0,0)/(95,0) - a small,
// never-resized container, so plain Location placement here
// carries none of the earlier risk (that risk only existed
// when the same fixed coordinates were relative to the whole,
// variable-height tab page).
this.pnlTemplateButtons.Dock = System.Windows.Forms.DockStyle.Top;
this.pnlTemplateButtons.Size = new System.Drawing.Size(190, 35);
this.pnlTemplateButtons.Controls.Add(this.btnAddTemplate);
this.pnlTemplateButtons.Controls.Add(this.btnRemoveTemplate);
// btnAddTemplate
this.btnAddTemplate.Location = new System.Drawing.Point(0, 0);
this.btnAddTemplate.Size = new System.Drawing.Size(90, 27); this.btnAddTemplate.Size = new System.Drawing.Size(90, 27);
this.btnAddTemplate.Text = "+ Добавить"; this.btnAddTemplate.Text = "+ Добавить";
this.btnAddTemplate.UseVisualStyleBackColor = true; this.btnAddTemplate.UseVisualStyleBackColor = true;
this.btnAddTemplate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)));
this.btnAddTemplate.Click += new System.EventHandler(this.btnAddTemplate_Click); this.btnAddTemplate.Click += new System.EventHandler(this.btnAddTemplate_Click);
// btnRemoveTemplate // btnRemoveTemplate
this.btnRemoveTemplate.Location = new System.Drawing.Point(115, 20); this.btnRemoveTemplate.Location = new System.Drawing.Point(95, 0);
this.btnRemoveTemplate.Size = new System.Drawing.Size(90, 27); this.btnRemoveTemplate.Size = new System.Drawing.Size(90, 27);
this.btnRemoveTemplate.Text = "Удалить"; this.btnRemoveTemplate.Text = "Удалить";
this.btnRemoveTemplate.UseVisualStyleBackColor = true; this.btnRemoveTemplate.UseVisualStyleBackColor = true;
this.btnRemoveTemplate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)));
this.btnRemoveTemplate.Click += new System.EventHandler(this.btnRemoveTemplate_Click); this.btnRemoveTemplate.Click += new System.EventHandler(this.btnRemoveTemplate_Click);
// lstTemplates // lstTemplates
// //
// Starts below the two buttons now (y=55, was y=20) and still // Dock=Fill: always occupies exactly whatever area of
// stretches down to the bottom of the tab page (Anchor // pnlTemplateList is left below pnlTemplateButtons, computed
// Top|Bottom|Left) - only its OWN bottom edge is at risk of // by the layout engine at every resize/DPI - not a hand-picked
// being visually tight against the tab page's real bottom // pixel height that can end up too short (and therefore
// edge if the assumed content height is off, which just means // effectively unscrollable/unclickable for items past the cut
// slightly less of the list is visible at once (it already has // -off) on a machine with different DPI/font scaling than the
// a scrollbar - IntegralHeight = false - so this degrades // one this was last tested on. IntegralHeight = false just
// gracefully) rather than an entire control disappearing. // means the list doesn't force its height to a whole multiple
this.lstTemplates.Location = new System.Drawing.Point(15, 55); // of the item height - irrelevant to whether Fill can "escape"
this.lstTemplates.Size = new System.Drawing.Size(190, 432); // the panel, which it structurally cannot.
this.lstTemplates.Dock = System.Windows.Forms.DockStyle.Fill;
this.lstTemplates.IntegralHeight = false; this.lstTemplates.IntegralHeight = false;
this.lstTemplates.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.lstTemplates.SelectedIndexChanged += new System.EventHandler(this.lstTemplates_SelectedIndexChanged); this.lstTemplates.SelectedIndexChanged += new System.EventHandler(this.lstTemplates_SelectedIndexChanged);
// lblTplDisplayName // lblTplDisplayName
@@ -399,6 +427,8 @@ namespace BulkArchiveMailer.AddIn.UI
this.tabControl.ResumeLayout(false); this.tabControl.ResumeLayout(false);
this.tabGeneral.ResumeLayout(false); this.tabGeneral.ResumeLayout(false);
this.tabGeneral.PerformLayout(); this.tabGeneral.PerformLayout();
this.pnlTemplateButtons.ResumeLayout(false);
this.pnlTemplateList.ResumeLayout(false);
this.tabTemplates.ResumeLayout(false); this.tabTemplates.ResumeLayout(false);
this.tabTemplates.PerformLayout(); this.tabTemplates.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);