C# 如何获得控件';从原始设计器设置中选择的位置和大小?

C# 如何获得控件';从原始设计器设置中选择的位置和大小?,c#,winforms,C#,Winforms,Windows(取决于字体/缩放/缩放)正在调整我的表单大小。我希望通过编程找到表单和控件(在设计器中设置)的原始位置和大小。在运行时,这些大小和位置会随着表单的创建而更改 Windows(取决于字体/缩放/缩放)正在调整我的表单大小 Windows没有调整窗体的大小。窗体已配置为自动缩放。这由控制。设计器的默认值为(真正的默认值为继承)。可以在文档中找到WinForm自动缩放的高级概述。常用的替代值是System.Windows.Forms.AutoScaleMode.DPI。启用自动缩放时,

Windows(取决于字体/缩放/缩放)正在调整我的表单大小。我希望通过编程找到表单和控件(在设计器中设置)的原始位置和大小。在运行时,这些大小和位置会随着表单的创建而更改

Windows(取决于字体/缩放/缩放)正在调整我的表单大小

Windows没有调整窗体的大小。窗体已配置为自动缩放。这由控制。设计器的默认值为(真正的默认值为
继承
)。可以在文档中找到WinForm自动缩放的高级概述。常用的替代值是
System.Windows.Forms.AutoScaleMode.DPI
。启用自动缩放时,将使用的值计算缩放因子,并在运行时使用DPI计算值报告给应用程序。
自动缩放尺寸
在设计器通用代码中设置

如果应用程序声明为可识别DPI,则使用真实的DPI值。如果不可识别DPI,Windows会告诉该应用程序它正在以96 DPI的速度运行。报告的DPI值还影响基于字体的缩放中使用的度量

我希望通过编程找到表单和控件(在设计器中设置)的原始位置和大小。在运行时,这些大小和位置会随着表单的创建而更改

这可以通过在应用自动缩放之前截取点来实现。在处理自动生成的代码(Form.designer.cs文件的InitializeComponent方法)时,没有直接的方法来实现。正是在这种方法中设置了
AutoScaleDimensions
AutoScaleMode

创建新表单时,此方法如下所示

private void InitializeComponent()
{
    this.components = new System.ComponentModel.Container();
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(800, 450);
    this.Text = "Form1";
}
请注意,
AutoScaleDimensions
属性尚未在方法中声明;一旦对表单进行了一些更改(更改属性或添加控件),就会添加该属性并将新信息写入文件。
AutoScaleDimensions
属性仅在
AutoScaleMode
设置为DPI或Font时才会写入

以下是更改表单的
大小
的结果

private void InitializeComponent()
{
    this.SuspendLayout();
    // 
    // Form1
    // 
    this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(782, 453);
    this.Name = "Form1";
    this.Text = "Form1";
    this.ResumeLayout(false);
}
显示上述内容的目的是向您展示如何在以下建议的解决方案中获取设置
AutoScaleDimensions
属性的值

建议的解决方案

在设计器中,将窗体的AutoScaleMode属性设置为
Inherit
None
。然后修改窗体的构造函数代码以反映以下内容:

SizeF scalingFactor;
public Form1()
{
    InitializeComponent();

    SuspendLayout();
    AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    AutoScaleDimensions = new System.Drawing.SizeF(8.0F, 16.0F);

    // at this point you can obtain the scaling factor that will
    // be applied on ResumeLayout
    scalingFactor = AutoScaleFactor;

    // store the design-time bounds in the control's Tag property
    RecursivelyRecordBounds(this);
    ResumeLayout(true);
}
还要将此方法添加到表单的代码中

private static void RecursivelyRecordBounds(Control c)
{
    c.Tag = c.Bounds;
    foreach (Control cc in c.Controls)
    {
        cc.Tag = cc.Bounds;
        if (cc.Controls.Count > 0)
        {
            RecursivelyRecordBounds(cc);
        }
    }
}
在本例中,每个控件的设计时
边界
存储在其
标记
属性中。请注意,设置两个自动缩放属性必须包装在SupendLayout/ResumeLayout区域中。另外,在设置
AutoScaleDimens之前,首先设置
AutoScaleMode
属性也很重要离子
属性

另一种解决方案(hack)将
AutoScaleMode
属性设置为Font或DPI,并依赖于
Initialize
方法的观察模式。在该方法中,表单的
Text
属性始终设置在两个缩放属性之后。这允许使用TextChanged事件来指示正确的检索时间设计时间界限

public Form1()
{
    EventHandler eh = (s,e) => RecursivelyRecordBounds(this);;
    TextChanged += eh;
    InitializeComponent();
    TextChanged -= eh;
}

可以肯定的是,唯一的方法是将窗体和控件的x/y位置复制到一个变量中。您为什么想要这些值?它们有什么可能的用途?这是一个锚定/停靠问题,还是计算机的显示设置问题?但如果您正确地锚定或停靠控件,这不应该是一个问题。请在控件前面使用@符号用户名,通知他们您正在回复评论。我们不知道您的表单有多复杂,但TableLayoutPanel可以基于百分比进行布局。感谢@TnTinMn的非常透彻的回复和解释。这对理解潜在的挑战非常有帮助。我偶然发现了一个解决方法……我有一个包含我试图管理/缩放的随机放置控件的面板。如果我处理“ParentChanged”事件,我可以枚举面板的所有控件(并获取它们的位置)。有了这些信息,我现在可以在面板调整大小时以编程方式放置它们。