引言

创设响应式WinForm应用程序并不那么粗略。
响应式布局,在此作者指的是应用程序在不一致显示器分辨率下的可用性。
对于WinForm应用程序,大家须要通晓地依据分辨率来调动控件的轻重缓急和重复定位。
纵然在接纳WPF时有相关的实施应用,通过使用控件的docking和anchoring,或行使panels等格局,但本文提供了一种将响应式应用于WinForm应用程序的差异方法。

背景

作者在三个和睦规划的总结游戏中遇见了难点:作者布署了一台分辨率为壹玖壹柒x1080的机械,
可是当自身妄图在台式机计算机上播放时,开采应用程序边界跑到显示器之外。由此很有不可缺少让程序来适应差别分辨率的配备,而不是让用户来适应程序。
因而,作者对代码举行了查对。

技术

骨子里没什么才干可言,只是用了三个小手艺。大家用五个常量来保存设计时的荧屏分辨率,大家誉为设计时分辨率。那样,无论曾几何时运营应用程序,它都会得到一个乘法因子,那实际是一个比例因子,通过将眼下分辨率除以设计时分辨率来获取该因子。
窗体的有着控件都被传送给那么些类对象实行缩放和调动大小。

代码

The Responsive Class – Responsive.cs

创办三个类Responsive.cs,加多5个变量。

float WIDTH_AT_DESIGN_TIME = (float)Convert.ToDouble
                             (ConfigurationManager.AppSettings["DESIGN_TIME_SCREEN_WIDTH"]);
float HEIGHT_AT_DESIGN_TIME = (float)Convert.ToDouble
                              (ConfigurationManager.AppSettings["DESIGN_TIME_SCREEN_HEIGHT"]);
Rectangle Resolution;
float WidthMultiplicationFactor;
float HeightMultiplicationFactor;

布置时荧屏分辨率保存在App.config文件中。

<add key ="DESIGN_TIME_SCREEN_WIDTH" value="1920"/>
<add key ="DESIGN_TIME_SCREEN_HEIGHT" value="1080"/>

当类的叁个实例被创建时,当前的辨析被提要求构造函数。
之后调用该类的SetMultiplicationFactor()方法。
这种方法通过将眼下分辨率除以设计时间分辨率来博取缩放因子。

public Responsive(Rectangle ResolutionParam)
{
    Resolution = ResolutionParam;
}

public void SetMultiplicationFactor()
{
    WidthMultiplicationFactor = Resolution.Width / WIDTH_AT_DESIGN_TIME;
    HeightMultiplicationFactor = Resolution.Height / HEIGHT_AT_DESIGN_TIME;
}

诸如,该应用程序设计在一九二〇x1080分辨率。
固然此应用程序在分辨率为1024×768的计算机上运营,则WidthMultiplicationFactor和HeightMultiplicationFactor退换如下:

WidthMultiplicationFactor = 1024/1920 = 0.533
HeightMultiplicationFactor = 768/1080 = 0.711

末尾有二种重载方法,它们为应用程序控件提供响应式消除方案(最棒大小,地点和字体大小)的终极方法。

public int GetMetrics(int ComponentValue)
{
    return (int)(Math.Floor(ComponentValue * WidthMultiplicationFactor));
}

public int GetMetrics(int ComponentValue, string Direction)
{
    if (Direction.Equals("Width") || Direction.Equals("Left"))
        return (int)(Math.Floor(ComponentValue * WidthMultiplicationFactor));
    else if (Direction.Equals("Height") || Direction.Equals("Top"))
        return (int)(Math.Floor(ComponentValue * HeightMultiplicationFactor));
    return 1;
}

举例,要是存在宽度=465,中度=72,左=366,最上部=41和字体大小=40的控件,则该方法重回提出的大小,地点和字体大小为:

Width = 465 * 0.533 = 248
Height = 72 * 0.711= 51
Left = 366 * 0.533= 195
Top = 41 * 0.711= 29
Font-size = 40 * 0.533 = 21

其实,那些方式再次来到缩放的控件与大小、地点和字体大小,而那一个值是显得的最棒值。

使用 Responsive Class

小编们要求的是以别的索要响应的款型轻易地创设这些类的靶子。
当前的分辨率是在构造函数中提供的, 之后的做事正是创立所需的乘法因子。

Responsive ResponsiveObj;
ResponsiveObj = new Responsive(Screen.PrimaryScreen.Bounds);
ResponsiveObj.SetMultiplicationFactor();

在这件事后,表单的全部控件都将每种传递,以在表单的加载事件中调治大小和再一次定位。
那个调用在底下的代码中做到。 它所做的是首先将窗体定位到显示屏的大旨。
我在这里设置了叁个校准常数(30),为最好的垂直地方增多控件,那可能因开垦人员而异。
之后,表单的每三个控件都会再也定位,调治大小,同仁一视新校准字体大小。

private void ResponsiveForm_Load(object sender, EventArgs e)
{
    Width = ResponsiveObj.GetMetrics(Width, "Width");           // Form width and height set up.
    Height = ResponsiveObj.GetMetrics(Height, "Height");
    Left = Screen.GetBounds(this).Width / 2 - Width / 2;        // Form centering.
    Top = Screen.GetBounds(this).Height / 2 - Height / 2 - 30;  // 30 is a calibration factor.

    foreach (Control Ctl in this.Controls)
    {
        Ctl.Font = new Font(FontFamily.GenericSansSerif, 
                   ResponsiveObj.GetMetrics((int)Ctl.Font.Size), FontStyle.Regular);
        Ctl.Width = ResponsiveObj.GetMetrics(Ctl.Width, "Width");
        Ctl.Height = ResponsiveObj.GetMetrics(Ctl.Height, "Height");
        Ctl.Top = ResponsiveObj.GetMetrics(Ctl.Top, "Top");
        Ctl.Left = ResponsiveObj.GetMetrics(Ctl.Left, "Left");
    }
}

示例

以下是二个特别轻易的表单,当中储存贰个data
gird,贰个label,一个textbox和八个button。
上面包车型地铁图片以两种不相同的分辨率截取。
上面包车型地铁截图是在1917×1080分辨率下截取的:
图片 1

上边包车型地铁截图是在1360×768分辨率下截取的:
图片 2

上面包车型地铁截图是在1024×768分辨率下截取的:
图片 3

实际上,通过缩短/增加和重新定位调控到最好水平,Form在差别的分辨率下看起来是平等的。

代码调治

就如大家对垂直大旨定位所做的那样,大家可能供给设置有个别参数来调节总体布局。

除此以外,提议开拓者尝试以不一致的分辨率查看表单的外观,以确认全部的控件都是可知的,并服从预期在显示器上正确定位。

除去,对于贰个简练的表单,那是三个通用的点子,它一旦表单的享有控件都有所这几个属性—宽度,中度,右边,顶上部分和字体大小。可是,真实情状并不是那样。有一部分表单控件不具备全数这个属性。比方,图片框没有font-size属性。由此,若是这么的图景下并未有显明管理,运营代码将会导致运维时十分。本文目的在于介绍这种方法,开荒人员需求依赖真实情况开始展览校准。建议的情势如下:

private void ResponsiveForm_Load(object sender, EventArgs e)
{
    Width = ResponsiveObj.GetMetrics(Width, "Width");           // Form width and height set up.
    Height = ResponsiveObj.GetMetrics(Height, "Height");
    Left = Screen.GetBounds(this).Width / 2 - Width / 2;        // Form centering.
    Top = Screen.GetBounds(this).Height / 2 - Height / 2 - 30;  // 30 is a calibration factor.

    foreach (Control Ctl in this.Controls)
    {
        if (Ctl is PictureBox)
        {
            Ctl.Width = ResponsiveObj.GetMetrics(Ctl.Width, "Width");
            Ctl.Height = ResponsiveObj.GetMetrics(Ctl.Height, "Height");
            Ctl.Top = ResponsiveObj.GetMetrics(Ctl.Top, "Top");
            Ctl.Left = ResponsiveObj.GetMetrics(Ctl.Left, "Left");
        }
        else
        {
            Ctl.Font = new Font(FontFamily.GenericSansSerif, 
                                ResponsiveObj.GetMetrics((int)Ctl.Font.Size), FontStyle.Regular);
            Ctl.Width = ResponsiveObj.GetMetrics(Ctl.Width, "Width");
            Ctl.Height = ResponsiveObj.GetMetrics(Ctl.Height, "Height");
            Ctl.Top = ResponsiveObj.GetMetrics(Ctl.Top, "Top");
            Ctl.Left = ResponsiveObj.GetMetrics(Ctl.Left, "Left");
        }
    }
}

恐怕会依据业务员要求和控件的性格来调解代码。
其余,恐怕须要为不一致的控件类型引进越多的重载方法。

其他

如前所述,还也许有别的部分方法,举个例子利用WPF,使用anchoring/docking等,那是三个更精通的取舍。
假使表单上有数千个控件,则或者会遇上加载延迟。
可是,那一点延迟对现行运营高效的管理器来讲小意思。
这种格局只是在表单的加载时才推行一遍调用操作,因而不会推动致命的习性裁减的标题。

结尾

制造响应式WinForm应用程序,依照机器的运转时刻分辨率自动调度大小,重新定位字体大小相提并论新校准字体大小,那是一种面向开荒职员的章程。
只需将该类加多到品种中,在App.config文件中设置规划时分辨率,然后在窗体的加载事件中加上响应代码。
So easy!