程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WindowsMobile/Win Form-界面自適應

WindowsMobile/Win Form-界面自適應

編輯:關於.NET

起因

使用SmartPhone上的WinForm做了一個WM的小程序,結果放到手機上實際一運行。發現動態生成的控件在裡面顯示得都非常小,難以看清。

原因

我的問題是需要在InitializeComponent方法結束後,動態生成一些控件,如下:

/// <summary>
/// 這個方法會根據傳入的實體模型,生成一些選擇框,設置它們的大小、位置;並會改變其它控件的大小、位置。
/// </summary>
/// <param name="categories"></param>
private void GenerateCheckBoxes(IList<Category> categories)
{

   ……
}

原因就是因為手機分辨率較大,而這些動態生成的控件並沒有進行隨著分辨率不同而進行自動縮放。而由界面設計器設計出來的控件,都能很好的顯示。

求索

由於界面生成的控件能夠很好的自適應分辨率的不同,所以先看一下Designer生成的代碼:

private void InitializeComponent()
{
   this.BAdd = new System.Windows.Forms.Button();
   this.PCategories = new System.Windows.Forms.Panel();
   this.SuspendLayout();

   // BAdd 
   this.BAdd.Location = new System.Drawing.Point(165, 164);
   this.BAdd.Name = "BAdd";
   this.BAdd.Size = new System.Drawing.Size(72, 20);
   this.BAdd.TabIndex = 11;
   this.BAdd.Text = "Add";
   this.BAdd.Click += new System.EventHandler(this.BAdd_Click);
   // PCategories 
   this.PCategories.Location = new System.Drawing.Point(73, 83);
   this.PCategories.Name = "PCategories";
   this.PCategories.Size = new System.Drawing.Size(164, 75);
   // MainForm 
   this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
   this.AutoScroll = true;
   this.ClientSize = new System.Drawing.Size(243, 258);
   this.Controls.Add(this.PCategories);
   this.Controls.Add(this.BAdd);
   this.Name = "MainForm";
   this.Text = "MoneyManagerForm";
   this.ResumeLayout(false);
}

這裡的重點是使用了AutoScaleDimensions和AutoScaleMode屬性來設置界面為自動縮放。(Dpi表示Dot per inch,WPF就是直接使用這種方式來控制界面的。)然後最後一步調用ResumeLayout方法,這個方法中,會調用到 ContainerControl.PerformAutoScale方法進行自動縮放。

最可惡的一點:從控件的構造,到界面的自動縮放,全部在一個方法中實現!而且這個方法中,沒有什麼好的辦法來調用我生成控件的方法……

解決過程

在Form中,重寫ScaleControl方法如下:

protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
{
   var categories = Config.Instance.Categories;
   this.GenerateCheckBoxes(categories);

   base.ScaleControl(factor, specified);
}

因為調用過程是這樣的:

Control.LayoutResume() –> ContainerControl.PerformAutoScale() –> Control.Scale() –> Control.ScaleControl() & Control.ScaleChildControls()。

所以,只需要重寫這個方法,就可以在真正執行自動縮放所有控件前,先把動態控件生成。

不過,這樣做同樣有局限性:因為這裡是在InitializeComponent方法中進行 PerformAutoScale,所以這裡的這些動態生成的控件,其實是在應用程序的開始階段就已經被明確了。相反,如果在運行一段時間後,需要想再動態生成其它控件,就不能使用這個方法了。那時,就需要直接調用剛生成的需要縮放的控件的Scale方法。而且不能直接使用PerformAutoScale方法了,因為要保證一個控件只被調用Scale方法一次! 在這裡,只需要這樣簡單實現就行了。

另外,一開始以為PerformAutoScale並不會把縮放過的控件,再縮放一次,結果就寫成了這樣的錯誤方案:

public MainForm()
{
   InitializeComponent();

   //暫停布局

   this.SuspendLayout();

   //在InitComponents調用的PerformAutoScale方法裡面,最後會把這個數給置為運行時的數據。所以這裡需要重新設置。
   this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
   //生成控件 
   this.GenerateCategories();
   //自動縮放 
   this.PerformAutoScale();//其實這裡會把InitializeComponent中縮放的控件都再縮放一遍。
   //繼續布局 
   this.ResumeLayout(false);
}

結束語

其實,這裡的自動縮放過程,在WinForm開發中,也是一樣的。

而且這次實踐中,我還發現:我在Win7的系統上隨手點了一下這個程序,居然所有功能都能夠正常的運行……汗,當時做的時候,可是專門為WindowsMobile開發的窗體啊。這個“跨平台”功能,確實很強大,著實讓我吃驚不小。

另外,由於VS2008自帶的模擬器的屏幕分辨率和設計時的分辨率是一樣大的,而我手機的分辨率比這個要大得多。所以每次調試這個縮放過程時,都要生成好了,然後拷貝到手機上看效果,真是吐血……

引用

Windows 窗體中的自動縮放自動縮放的執行過程

Windows 窗體現在使用下面的邏輯自動對窗體及其內容進行縮放:

設計時,每一個 ContainerControl 分別在 AutoScaleMode 和 AutoScaleDimensions 中記錄縮放模式和它的當前分辨率。

運行時,實際分辨率存儲在 CurrentAutoScaleDimensions 屬性中。AutoScaleFactor 屬性會動態計算運行時分辨率與設計時分辨率的比值。

當加載窗體時,如果 CurrentAutoScaleDimensions 和 AutoScaleDimensions 的值不同,則會調用 PerformAutoScale 方法對該控件及其子控件進行縮放。此方法會掛起布局並調用 Scale 方法執行實際縮放。然後,會更新 AutoScaleDimensions 值以避免累進縮放。

在下面的情況下還會自動調用 PerformAutoScale:

在縮放模式為 Font 時響應 OnFontChanged 事件。

當繼續執行容器控件的布局時檢測到 AutoScaleDimensions 或 AutoScaleMode 屬性發生更改。

與上面的情況類似,檢測到父 ContainerControl 正在被縮放。每個容器控件只負責使用自己的比例因子縮放自己的子控件,並不負責縮放其父容器中的控件。

子控件可以通過下面的若干方式修改其縮放行為:

可以重寫 ScaleChildren 屬性以確定是否應縮放其子控件。

可以重寫 GetScaledBounds 方法以調整要將控件縮放至的邊界,但不調整縮放邏輯。

可以重寫 ScaleControl 方法以更改當前控件的縮放邏輯。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved