星期四, 7月 13, 2017

[RV] ReportViewer 和 DPI 感知

在 Winform 上利用 ReportViewer 製作報表釋出後,HR 就急急忙忙跑來說報表異常,Orz

正常報表,是設定在 A4 紙張上,理論上內容是接近滿版

[RV] ReportViewer 和 DPI 感知-1

異常報表,內容被縮小了

[RV] ReportViewer 和 DPI 感知-2

在開發 PC 或其他 PC 上進行列印都正常,就只有 HR 那台 PC 上會發生該現象,有嘗試重新安裝 Printer Driver,連 Printer 韌體都更新到最新版本,也還是異常,Orz

直覺是 HR PC Windows 10 設定哪裡出錯,才意識到該 PC DPI 設定不是標準的 100%,這台是 125%,嘗試調回 100% 後,報表就正常啦

尋找 ReportViewer 和 DPI 相關資料,發現要讓報表依設計呈現,必須利用應用程式資訊清單(Application Manifest File)告知 Windows,程式是 DPI 感知,不需要去變化它

在 Project 內新增 Mainfest 檔案

[RV] ReportViewer 和 DPI 感知-3

Manifest 檔案名稱的建議命名方式,擷取 MSDN 內容
File Name Syntax
The name of an application manifest file is the name of the application's executable followed by .manifest.
For example, an application manifest that refers to Example.exe or Example.dll would use the following file name syntax. You can omit the <resource ID> field if resource ID is 1.
  • example.exe.<resource ID>.manifest
  • example.dll.<resource ID>.manifest
Manifest 檔案內的預設檔案內容
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <!-- UAC 資訊清單選項
             如果要變更 Windows 使用者帳戶控制層級,請將 
             requestedExecutionLevel 節點以下列其中之一取代。

        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />

            指定 requestedExecutionLevel 項目會停用檔案及登錄虛擬化。
            如果您的應用程式需要針對回溯相容性進行這項虛擬化,請移除這個
            項目。
        -->
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>

  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- 這個應用程式測試所在及可配合使用的
           Windows 版本清單。請取消註解適當的項目,Windows 將會
           自動選取最相容的環境。-->

      <!-- Windows Vista -->
      <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->

      <!-- Windows 7 -->
      <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->

      <!-- Windows 8 -->
      <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->

      <!-- Windows 8.1 -->
      <!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->

      <!-- Windows 10 -->
      <!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->

    </application>
  </compatibility>

  <!-- 表示應用程式為 DPI 感知,Windows 不會在 DPI 變高時自動
       調整。Windows Presentation Foundation (WPF) 應用程式會自動感知 DPI,因此不需要
       選擇加入。選擇加入這項設定之以 .NET Framework 4.6 為目標的 Windows Form 應用程式也
       應該在其 app.config 中將 'EnableWindowsFormsHighDpiAutoResizing' 設定為 'true'。-->
  <!--
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>
  -->

  <!-- 啟用 Windows 通用控制項和對話方塊的佈景主題 (Windows XP 以後版本) -->
  <!--
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
          type="win32"
          name="Microsoft.Windows.Common-Controls"
          version="6.0.0.0"
          processorArchitecture="*"
          publicKeyToken="6595b64144ccf1df"
          language="*"
        />
    </dependentAssembly>
  </dependency>
  -->

</assembly>
新增 Manifest 後,在 Project 屬性內,預設會自動選取該 Manifest 檔案

[RV] ReportViewer 和 DPI 感知-4

把 dpiAware uncomment 並把參數設為 true/pm (預設為 true),參數說明請參考 Application Manifests
<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
         true/pm
      </dpiAware>
    </windowsSettings>
  </application>
另外 Manifest 檔案內還有提到 dotNet 4.6 以上,也要把 EnableWindowsFormsHighDpiAutoResizing 參數,加入 App.Config 檔案內
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="EnableWindowsFormsHighDpiAutoResizing" value="true" />
  </appSettings>
</configuration>
設定之後在 Windows 10 上,DPI 非 100% PC 上就可以輸出預期的報表,不過要特別注意,畢竟該設定會影響整個程式,要看看 WinForm Layout 會不會跑掉喔

人生第一張 ReportViewer 報表就踩到這個存在已久的雷,>.<
  • 20170727 補充
Windows 10 1703 有個新功能 - 覆蓋高 DPI 縮放行為,可以直接對 EXE 檔案設定該選項,也可以避免該問題
[RV] ReportViewer 和 DPI 感知-5

沒有留言:

張貼留言