首页 > 解决方案 > 将大小更改传递给子控件的问题

问题描述

我正在开发一个具有如下分层界面的 WinForms 应用程序:

我的用户界面布局

忽略面板 A。旁边我有一个带有 2 个选项卡的 TabControl。在第二个选项卡的 TabPage 上,我在顶部有一些用于过滤数据的控件,在其下方有面板 B,它是一个 FlowLayoutPanel,它显示来自数据库的记录列表。每条记录都显示在面板 C 中,面板 C 包含各种文本字段,具体取决于记录的内容。

加载时 UI 看起来相当不错(但请参阅下面的问题 #2)。我正在努力解决的第一个问题是正确处理主窗口的调整大小事件。当用户拖动主窗口的一侧使其变宽时,主窗体会调整 TabPage 和 Panel B 的大小,然后调用 Panel B 上的方法来调整其内容的大小。TabPage 顶部的控件根据其设置自动均匀地分布在顶部。到目前为止,一切都很好。

面板 B 遍历其 C 面板列表,调整每个面板的宽度。(稍后我将为 C Panel 添加代码以相应地调整每个文本字段的宽度。)

但目前,我遇到了两个可能相关的问题:

  1. 我似乎无法让 C 面板改变它们的宽度。我最初希望通过正确的 AutoSize、AutoScroll 等设置,我可以得到我想要的,但是当这不起作用时,我决定添加一个 resize 事件处理程序来获得更多控制权。这目前无法正常工作。

  2. 甚至在调整大小之前,我将面板 B 的宽度设置为适合 TabPage,并将面板 B 的 FlowDirection 设置为 FlowDirection.TopDown,但是一旦有足够的 C 面板超过面板 B 的高度,面板 B 变为双倍宽度,其中有第二列 C 面板。我真正想要的是添加一个垂直滚动条来滚动“TopDown”列表。

当我将面板 B 的 AutoScroll 设置为 true 时,我没有得到垂直滚动条(这是我期望的 TopDown 面板);相反,我得到了一个水平滚动条,面板向右增长!所以我关闭了自动滚动。

这是一些相关的代码:

    class MainForm : Form
{
    private int priorHeight;
    private int priorWidth;
    private System.Windows.Forms.TabPage MyTabPage;
    private SelectableListPanel PanelB = null;

    ...

    private void OnResize(object sender, EventArgs e)
    {
        this.SuspendLayout();

        int vDiff = this.Height - priorHeight;
        int hDiff = this.Width - priorWidth;

        MyTabPage.Height += vDiff;
        MyTabPage.Width += hDiff;

        PanelB.Height += vDiff;
        PanelB.Width += hDiff;

        // tell PanelB to resize its record panels
        PanelB.PropagateResize(hDiff);

        ResumeLayout(false);
        PerformLayout();

        priorHeight = this.Height;
        priorWidth = this.Width;
    }
}

class SelectableListPanel : FlowLayoutPanel
{
    protected List<Panel> panels = new List<Panel>();

    public SelectableListPanel(List<Panel> Panels) : base()
    {
        FlowDirection = FlowDirection.TopDown;
        AutoScroll = false;
        AutoSize = false;
        panels = Panels;
    }

    ...

    public void PropagateResize(int hDiff)
    {
        foreach (Panel genPanel in panels)
        {
            genPanel.Width += hDiff;
            // TODO:  genPanel.PropagateResize(hDiff)
        }
    }
}

有什么想法/建议吗?

标签: c#.netwinformsresizechildcontrol

解决方案


想发布一些代码,让我可以测试我在评论中收到的建议。我的演示程序是这样做的:

在此处输入图像描述

这是它的代码:

    public Form1()
{
    Panel BluePanel;
    Panel OrangePanel;
    Panel GreenPanel;
    List<Panel> PurplePanels;

    InitializeComponent();
    SuspendLayout();

    // Field 1
    TextBox f1 = new TextBox();
    f1.Text = "Main Form";
    f1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
    f1.Font = new Font("Microsoft Sans Serif", 14F, FontStyle.Regular,
       GraphicsUnit.Point, (byte) 0);
    f1.Location = new Point(12, 12);
    f1.Multiline = true;
    f1.Name = "Field1";
    f1.Size = new Size(460, 32);
    f1.TabIndex = 0;

    // BluePanel
    BluePanel = new Panel();
    BluePanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
    BluePanel.BackColor = Color.Blue;
    BluePanel.Location = new Point(12, 50);
    BluePanel.Name = "BluePanel";
    BluePanel.Size = new Size(460, 402);
    BluePanel.TabIndex = 1;

    // Field 2
    TextBox f2 = new TextBox();
    f2.Text = "Blue Panel";
    f2.Anchor = f1.Anchor;
    f2.Font = f1.Font;
    f2.Location = f1.Location;
    f2.Name = "Field2";
    f2.Size = new Size(BluePanel.Width - 24, f1.Height);
    f2.TabIndex = 0;
    BluePanel.Controls.Add(f2);

    // OrangePanel
    OrangePanel = new Panel();
    OrangePanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
    OrangePanel.BackColor = Color.Orange;
    OrangePanel.Location = new Point(f2.Left, f2.Bottom + 6);
    OrangePanel.Name = "OrangePanel";
    OrangePanel.Size = new Size(BluePanel.Width - 24, BluePanel.Height - (f2.Bottom + 6 + 12));
    OrangePanel.TabIndex = 1;
    BluePanel.Controls.Add(OrangePanel);

    // Field 3
    TextBox f3 = new TextBox();
    f3.Text = "Orange Panel";
    f3.Anchor = f1.Anchor;
    f3.Font = f1.Font;
    f3.Location = f1.Location;
    f3.Name = "Field3";
    f3.Size = new Size(OrangePanel.Width - 24, f1.Height);
    f3.TabIndex = 0;
    OrangePanel.Controls.Add(f3);

    // GreenPanel
//    GreenPanel = new FlowLayoutPanel();
//    GreenPanel.FlowDirection = FlowDirection.LeftToRight;
    GreenPanel = new Panel();
    GreenPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
    GreenPanel.AutoScroll = true;
    GreenPanel.AutoSize = false;
    GreenPanel.BackColor = Color.Green;
    GreenPanel.Location = new Point(f3.Left, f3.Bottom + 6);
    GreenPanel.Name = "GreenPanel";
    GreenPanel.Size = new Size(OrangePanel.Width - 24, OrangePanel.Height - (f3.Bottom + 6 + 12));
    GreenPanel.TabIndex = 1;
    OrangePanel.Controls.Add(GreenPanel);

    // PurplePanels
    PurplePanels = new List<Panel>();
    for (int i = 0; i < 10; i++)
    {
        Panel PurplePanel = new Panel();
        PurplePanel.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;

        PurplePanel.BackColor = Color.Purple;
        PurplePanel.Size = new Size(GreenPanel.Width - 24, 32 + 24);
        PurplePanel.Location = new Point(12, 6 + (i * (32 + 24 + 6)));
        PurplePanel.Name = "PurplePanel" + i.ToString();
        PurplePanel.TabIndex = i;

        // Fields
        TextBox fi = new TextBox();
        fi.Text = "Purple Panel " + i.ToString();
        fi.Anchor = f1.Anchor;
        fi.Font = f1.Font;
        fi.Location = f1.Location;
        fi.Name = "Fieldi" + i.ToString();
        fi.Size = new Size(PurplePanel.Width - 24, f1.Height);
        fi.TabIndex = 0;
        PurplePanel.Controls.Add(fi);

        GreenPanel.Controls.Add(PurplePanel);
        PurplePanels.Add(PurplePanel);
    }

    ResumeLayout(false);
    PerformLayout();
}

要查看 FlowLayoutPanel 有什么不同,只需取消注释 Green Panel 部分中的相关行,并注释掉“GreenPanel = new Panel();” 线。在那里您会看到 FlowDirection.LeftToRight 不会产生所需的结果。

我还想向@Jimi 和@LarsTech 大声疾呼,因为他们为我指明了正确的方向。


推荐阅读