دعم الدقّة العالية (High DPI) في WinForms ── أسباب النِّيَة والانكسار على شاشات 4K ومعالجتها الواقعيّة
· آخر تحديث: · غو كومورا · WinForms, الدقّة العالية (High DPI), Windows, .NET, C#, .NET Framework, صيانة الأنظمة القديمة, UI, الاستشارات التقنية
«بعد استبدال الحاسوب المحمول الجديد، صار نصّ التطبيق التجاريّ نيّئاً وصعب القراءة»، «بعد التوصيل بشاشة 4K، تداخلت الأزرار والتسميات»، «تنكسر معاينة التقرير فقط في بيئة العميل بدقّة 125%». في السنوات الأخيرة، تزايدت هذه الاستشارات بشدّة مع فترات استبدال الحواسيب. أصبحت الشاشات ذات الدقّة العالية التي تتجاوز Full HD والتحجيم بين 125% و200% معياريّة حتّى في حواسيب العمل، فلم تعد تطبيقات WinForms التي صُمِّمت في عصر 96 DPI / تحجيم 100% تُعرَض بشكل مريح كما هي. أصبح هذا الموضوع، من واقع استشارات صيانة تطبيقات WinForms القديمة، أعلى المواضيع تردّداً حاليّاً.
المُزعِج أنّ الأعراض تبدو متفرّقة: «نيّئ»، «منكسر»، «جزء صغير فقط». في الواقع يمكن ترتيب الأسباب في عدد قليل من الفئات، وحين تعرف أيّ عرَض يقابل أيّ سبب، يمكنك تحديد طريقة الإصلاح ومدى العمق المطلوب في المعالجة. في هذا المقال، وانطلاقاً من آليّة تحجيم DPI في Windows وأوضاع إدراك DPI، نرتّب دعم الدقّة العالية في تطبيقات WinForms (.NET و.NET Framework كليهما) ── طريقة الإعداد، والفخاخ النمطيّة، واستراتيجيّة المعالجة المرحليّة ── من منظور عمليّ.
1. الخلاصة أوّلاً
- «النِّيَة» في بيئة الدقّة العالية للتطبيقات القديمة ليست خللاً، بل إجراء إنقاذ من نظام التشغيل (الافتراض الوهميّ لـ DPI). بالنسبة للتطبيقات غير الداعمة لـ DPI، يجعل Windows التطبيق يرسم بدقّة 96 DPI ثمّ يكبّر النتيجة كصورة نقطيّة، فيبقى التخطيط سليماً في مقابل ظهور النِّيَة.1
- وفي المقابل، «واضح لكن منكسر» تعني أنّ دعم DPI أُعلن لكن التخطيط عجز عن مجاراته. أسباب النِّيَة والانكسار معاكسة تماماً، لذا ميّز أيّهما قبل المعالجة.
- الخطوة الأولى في المعالجة هي معرفة أيّ وضع إدراك DPI (Unaware / System Aware / Per-Monitor V2) يعمل به تطبيقك حاليّاً. تحقّق مما إذا كنتَ تُعلِنه عبر المانيفست أو app.config أو استدعاء API (أو لا شيء منها).2
- تختلف طريقة الإعداد باختلاف الجيل. .NET (Core 3.1 حتّى .NET 8) عبر ملفّ المشروع أو
Application.SetHighDpiMode، و.NET Framework 4.7 فما بعده عبر app.config، و4.6 فما دون يقف الخطّ الواقعيّ عند System Aware عبر المانيفست.34 - يجب فتح المصمِّم دائماً على شاشة 100% (96 DPI). فتح نموذج على بيئة 150% وحفظه يُعيد كتابة
AutoScaleDimensions، ما يسبِّب حادثاً كلاسيكيّاً بانكسار تخطيط الفريق بأكمله.5 - الدعم الكامل (Per-Monitor V2) يتطلّب حجم عمل كبير. الأنسب هو اتّباع مرحلتين: «واضح على الشاشة الرئيسيّة فقط عبر System Aware» كمرحلة أولى، ودعم PMv2 كامل كمرحلة ثانية، بحيث يتناسب حجم الاستثمار مع عمر التطبيق وبيئة الاستخدام.
- كإجراء مؤقّت في حال تعذّر التعديل الذاتيّ أو ضيق الوقت، من المفيد أيضاً معرفة «إعداد الدقّة العالية» الذي يمكن للمستخدم نفسه تجاوزه من خصائص الملفّ التنفيذيّ ← علامة تبويب التوافقيّة، فهو يسهِّل التعامل مع الاستفسارات.6
2. لماذا يظهر نيّئاً ── آليّة الافتراض الوهميّ لـ DPI
يُعبَّر عن تحجيم العرض في Windows بمعامل يجعل 96 DPI يساوي 100%. أي 125% = 120 DPI، و150% = 144 DPI، و200% = 192 DPI. عند استخدام شاشة 4K (3840×2160) بحجم 27 بوصة بتحجيم 100%، يصبح النصّ صغيراً جدّاً، لذا يوصي Windows افتراضيّاً بنحو 150%. هذا يعني أنّ انتشار الشاشات عالية الدقّة يعني مباشرةً «انتشار بيئات تعمل بدقّة غير 96 DPI».
المشكلة أنّ معظم تطبيقات سطح المكتب القديمة كُتبت على افتراض «الشاشة دائماً 96 DPI». الإحداثيّات والخطوط والأيقونات جميعها مكتوبة بالبكسل مباشرةً، فإذا رُسمت كما هي في بيئة 150%، ستظهر كلّ العناصر فعليّاً بحجم يعادل ثلثي الحجم. لذلك، يوهم Windows التطبيقات التي لم تُعلن دعم DPI بأنّ «الشاشة 96 DPI»، ثمّ يعرض ما رسمه التطبيق ظانّاً أنّه بدقّة 96 DPI كصورة نقطيّة مكبَّرة. هذا هو الافتراض الوهميّ لـ DPI (تمديد الصورة النقطيّة).1
مع أخذ هذه الآليّة بالحسبان، يتطابق العرَض والسبب بشكل مرتَّب. استخدم هذا الجدول في التشخيص الأوّل.
| العرَض | السبب | الحالة |
|---|---|---|
| نيّئ ومشوَّش بشكل موحَّد على كامل الشاشة. لا ينكسر التخطيط | الافتراض الوهميّ لـ DPI (نظام التشغيل يكبِّر الصورة النقطيّة) | غير داعم لـ DPI (Unaware). آمن لكن قبيح |
| النصّ واضح، لكن عناصر التحكّم تتداخل أو تُقصّ | أُعلن دعم DPI لكن التخطيط عجز عن مجاراته | دعم DPI ناقص. من هنا يبدأ التعديل |
| واضح على الشاشة الرئيسيّة، نيّئ عند الانتقال إلى شاشة فرعيّة | System Aware (دقّة الشاشة الرئيسيّة عند بدء التشغيل ثابتة) | كما هو المتوقَّع. موضوع قرار حول التحوّل إلى PMv2 |
| حجم النصّ جيّد، لكن الأيقونات والصور فقط صغيرة أو خشنة | أصول الصور النقطيّة لا تزال لـ 96 DPI | عدم دعم أصول الصور (الفصل 6) |
| شاشة أو عنصر تحكّم معيّن فقط ينكسر | تخطيط بإحداثيّات ثابتة، رسم ذاتيّ، عنصر تحكّم من طرف ثالث | موضوع تعديل فرديّ (الفصل 6) |
المهمّ هو أنّ التطبيق «النيّئ» ليس منكسراً في الحقيقة. إجراء إنقاذ نظام التشغيل يعمل بشكل صحيح. التعديل يعني قطع إجراء الإنقاذ هذا وإعلان «سأُحجِّم بنفسي» (أي رفع وضع إدراك DPI)، وبمجرّد الإعلان تصبح مشكلة التخطيط كلّها مسؤوليّتك. الاستشارات من نوع «حاولتُ التحوّل إلى PMv2 فازداد الأمر سوءاً» تحدث في هذا الإطار بالضبط.
3. تنظيم أوضاع إدراك DPI
تُعلِن التطبيقات وحدةً بوحدة (وبدقّة، النافذة العلويّة (top-level window) منذ Windows 10 فما بعده) إلى أيّ حدّ تستطيع التعامل مع DPI. الأوضاع أربعة فعليّاً.16
| الوضع | نظام التشغيل الذي أُدخِل فيه | DPI الذي يراه التطبيق | عند الانتقال بين الشاشات / تغيّر DPI | الموقع الواقعيّ في WinForms |
|---|---|---|---|---|
| Unaware | ── | دائماً 96 | نظام التشغيل يكبِّر الصورة النقطيّة (نِيَة) | الافتراضيّ إذا لم يُعلَن شيء. نيّئ لكن لا ينكسر |
| System Aware | Vista | دقّة الشاشة الرئيسيّة عند تسجيل الدخول ثابتة | خارج الشاشة الرئيسيّة أو بعد التغيير، يكبِّر نظام التشغيل (نِيَة) | يعمل في جميع الأجيال. المرشَّح الأوّل للتسوية |
| Per-Monitor (V1) | 8.1 | دقّة الشاشة التي تحوي النافذة | إشعار فقط للنافذة العلويّة. التحجيم كلّه يدويّ | لا دعم من الإطار، جدوى عمليّة ضئيلة. لا يُختار |
| Per-Monitor V2 | 10 (1703) | دقّة الشاشة التي تحوي النافذة | إشعار حتّى النوافذ الفرعيّة. المنطقة غير العميليّة (non-client) يتابعها نظام التشغيل | المرشَّح الأوّل للدعم الكامل. متاح في .NET Framework 4.7+ و.NET |
الفرق بين Per-Monitor V1 وV2 حاسم في العمل الفعليّ. V1 آليّة موجَّهة لـ Win32 الخام حيث «يصلك الإشعار لكن الباقي كلّه بنفسك»، ولا يوجد سبب لاستخدامها من WinForms. أمّا V2 فيحجِّم نظام التشغيل تلقائيّاً شريط العنوان وشريط التمرير والقوائم وغيرها من المناطق غير العميليّة، ودعم إطار WinForms نفسه (لاحقاً) مبنيّ على افتراض V2. إن اخترتَ Per-Monitor، فـ V2 هو الاختيار الوحيد.6
هناك أيضاً وضع آخر يُدعى تحجيم GDI (DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED، من Windows 10 1809 فما بعده). يبقى التطبيق كما هو Unaware، لكنّ النصّ والأشكال المرسومة عبر GDI فقط يكبِّرها نظام التشغيل على مستوى المتّجهات (vector)، وهي نسخة مُحسَّنة من تمديد الصورة النقطيّة.6 بما أنّها قد تخفِّف نِيَة النصّ دون تغيير أيّ شيفرة على الإطلاق، فمن المفيد تذكّرها كإجراء مؤقّت للتطبيقات التي يتعذّر تعديلها (الفقرة 4.3).
كذلك، منذ Windows 10 1607 فما بعده يوجد أيضاً وضع مختلط (Mixed-Mode) يسمح بمزج أوضاع مختلفة وحدةً بوحدة على مستوى النافذة العلويّة، بحيث يُدعَم انتقال مرحليّ من نوع «الشاشة الرئيسيّة PMv2 فقط، والحوارات التي يتعذّر إصلاحها تبقى Unaware ليكبِّرها نظام التشغيل» على مستوى Win32.7 ليس أمراً يُستخدَم بسهولة من WinForms، لكن فكرة تصميم «لا حاجة لإصلاح كامل الشاشة دفعة واحدة» تتّصل باستراتيجيّة المراحل في الفصل 7.
4. طريقة الإعداد ── الإجابة الصحيحة حسب الجيل
تختلف طريقة إعلان وضع إدراك DPI حسب جيل تطبيقك. الخطأ هنا يُضيِّع الوقت في حالة «ضبطتُه لكنّه لا يعمل»، لذا نكتبه مفصَّلاً حسب كلّ جيل.
4.1 WinForms في .NET (Core 3.1 حتّى .NET 8)
في .NET يتوفّر Application.SetHighDpiMode، ويستدعيه ApplicationConfiguration.Initialize() (المُولَّد بواسطة القالب، من .NET 6 فما بعده). الافتراضيّ هو SystemAware.3 يُنصَح بكتابة الإعداد في ملفّ المشروع، وهو ما يستخدمه أيضاً مصمِّم Visual Studio.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<!-- SystemAware (الافتراضيّ) / PerMonitorV2 / DpiUnaware / DpiUnawareGdiScaled -->
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
</PropertyGroup>
</Project>
نقطة يجب الانتباه إليها هي أنّ ApplicationHighDpiMode في ملفّ المشروع وApplicationConfiguration.Initialize() هما آليّة أُدخِلت في .NET 6.3 في مشاريع .NET Core 3.1 / .NET 5، كتابة هذه الخاصّية لا تعمل، لذا استدعِ Application.SetHighDpiMode مباشرةً من الشيفرة كما يلي (وينطبق الأمر نفسه على النمط القديم لـMain الذي لا يستخدم ApplicationConfiguration.Initialize()). في كلتا الحالتين، يجب استدعاؤه قبل إنشاء نافذة واحدة.
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
تحسَّن في .NET 6 فما بعده تحجيم عناصر تحكّم الحاويّة (container controls) ونوافذ MDI الفرعيّة عند استخدام PMv2، وحُلّت إلى حدّ كبير مشاكل مثل «انزياح عناصر التحكّم عند الانتقال من شاشة 200% إلى شاشة 100%» التي كانت موجودة حتّى .NET 5.3 عند خوض دعم PMv2 بجدّيّة، فإنّ الانطباع الفعليّ هو أنّ .NET الأحدث أسهل في التعامل معه بوضوح مقارنة بـ.NET Framework. عوامل النظر في الانتقال من .NET Framework مجموعة في «قائمة فحص ما قبل الترحيل من .NET Framework إلى .NET».
4.2 .NET Framework 4.7 فما بعده
تعزَّز دعم الدقّة العالية بقوّة في .NET Framework 4.7. أُدخِل تحسين تحجيم عناصر التحكّم، وأحداث تغيّر DPI (سلسلة DpiChanged)، وخاصّية DeviceDpi. لكنّه اختياريّ التفعيل (opt-in)، ولا يُفعَّل إلّا بضبط النقطتين التاليتين معاً.4
أوّلاً، أعلِن توافق Windows 10 عبر المانيفست (بدونه لا تُفعَّل ميزة الدقّة العالية في 4.7 من الأساس).
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- إعلان التوافق مع Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
ثانياً، أعلِن وضع إدراك DPI عبر System.Windows.Forms.ApplicationConfigurationSection في app.config.
<configuration>
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="PerMonitorV2" />
<!-- إذا كانت هناك شاشات مُحجَّمة يدويّاً بالفعل، يمكن إيقاف ميزات فرديّة -->
<!-- <add key="EnableWindowsFormsHighDpiAutoResizing" value="false" /> -->
</System.Windows.Forms.ApplicationConfigurationSection>
</configuration>
تأكّد أيضاً من استدعاء Application.EnableVisualStyles() في بداية Main. هنا نقطة تنبيه واحدة: الطريقة القديمة المتمثِّلة في وصف <dpiAware> / <dpiAwareness> في المانيفست تُبطِل إعداد app.config، فالموصى به رسميّاً في WinForms 4.7 عدم استخدامهما معاً.4 عند ترقية تطبيق كتب سابقاً <dpiAware>true</dpiAware> في المانيفست للتحوّل إلى System Aware إلى 4.7+PMv2، ابدأ بتنظيف الإعلان في جانب المانيفست. سبب حالة «ضبطتُه في app.config لكنّه لا يعمل» غالباً ما يكون هذا بالضبط.
4.3 .NET Framework 4.6 فما دون · خليط VB6/MFC
في WinForms لجيل 4.6 فما دون لا توجد شيفرة إطار داعمة لـ PMv2، وحتّى لو أُعلِن قسراً، ستُضطرّ إلى معالجة كامل انكسار التخطيط بنفسك. الحلّ الواقعيّ لهذا الجيل هو الوقوف عند إعلان System Aware عبر المانيفست. الوسيلة الموصى بها للإعلان على مستوى نظام التشغيل هي المانيفست، وكتابة <dpiAware> (من Vista) و<dpiAwareness> (من Windows 10 1607) معاً تجعل التفسير صحيحاً في الأنظمة القديمة والحديثة كليهما.2
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">system</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
عند التحوّل إلى System Aware، يعمل التحجيم التلقائيّ لـ WinForms (الفصل 5) مرّة واحدة عند بدء التشغيل وفق دقّة الشاشة الرئيسيّة، فيظهر واضحاً على الشاشة الرئيسيّة. النموذج الذي ضُبط فيه AutoScaleMode.Font بشكل صحيح غالباً ما يصل إلى حالة مقبولة إلى حدّ كبير بهذا الإعلان وحده. توجد أيضاً طريقة للإعلان وقت التشغيل عبر API مثل SetProcessDpiAwareness، لكن لا يمكن تغييره بعد إنشاء النافذة، والإعلان عبر المانيفست هو الموصى به رسميّاً.8 فكرة التعامل واحدة أيضاً لتطبيقات تختلط فيها شيفرات VB6 أو MFC، إذ يُحدَّد الوضع على مستوى العمليّة بأكملها عبر مانيفست الملفّ التنفيذيّ (لا يملك MFC نفسه دعماً للتحجيم التلقائيّ، لذا يبقى فحص الشاشات بعد إعلان System Aware ضروريّاً. راجع أيضاً «ما هو MFC في Windows» بخصوص التعامل مع أصول هذا الجيل).
نذكر أيضاً الحلّ المؤقّت من جهة المستخدم في حال تعذّر التعديل نفسه. يمكن للمستخدم بنقر يمينيّ على الملفّ التنفيذيّ ← خصائص ← علامة تبويب التوافقيّة ← «تغيير إعداد الدقّة العالية» تجاوز تحجيم DPI لذلك التطبيق. تعيين «تجاوز سلوك تحجيم الدقّة العالية» إلى «النظام» يفرض الافتراض الوهميّ لـ DPI (لا ينكسر لكن يظهر نيّئاً)، وتعيينه إلى «النظام (محسَّن)» يطبِّق تحجيم GDI المذكور في الفصل 3، فيصبح النصّ المرسوم عبر GDI فقط واضحاً.6 ليس حلّاً شاملاً، لكنّه يستحقّ إدراجه في دليل الدعم كوسيلة يمكن إرشادها عبر الهاتف عند الحاجة إلى حلّ فوريّ لدى العميل.
5. AutoScaleMode وفخّ المصمِّم (Designer)
يملك WinForms آليّة تحجيم تلقائيّ خاصّة بالنموذج نفسه، منفصلة عن وضع إدراك DPI. من دون فهم هذه الآليّة، لن يُحجَّم بشكل صحيح حتّى بعد التحوّل إلى System Aware.
الآليّة كالتالي: عند التصميم، يسجِّل كلّ نموذج (ContainerControl) مرجع التحجيم في AutoScaleMode، والقيمة المرجعيّة في بيئة التصميم في AutoScaleDimensions. عند التشغيل، تُقارَن قيمة البيئة الحاليّة (CurrentAutoScaleDimensions) بها، وإن وُجد فرق، تُكبَّر أو تُصغَّر عناصر التحكّم الفرعيّة معاً.9 بعبارة أخرى، هذه آليّة تمتصّ «الفرق بين بيئة التصميم وبيئة التشغيل»، وتُحفَظ القيمة المرجعيّة داخل الشيفرة (Designer.cs).
خيارات AutoScaleMode اثنان فعليّاً.
| AutoScaleMode | المرجع | الخصائص |
|---|---|---|
| Font (موصى به · الافتراضيّ) | أبعاد خطّ النموذج | يتغيّر الحجم الفعليّ لخطّ النظام مع ارتفاع DPI، فيتابع DPI أيضاً. يتابع أيضاً تغيير إعداد خطّ المستخدم |
| Dpi | دقّة الشاشة | يتناسب مع DPI فقط. مناسب للشاشات القائمة على الرسوميّات |
| None | ── | التحجيم التلقائيّ معطَّل. غالباً ما تكون هذه حالة التطبيقات المكتوبة بالبكسل مباشرةً لـ 96 DPI |
إن ترددتَ، اختر Font. نقطة تنبيه: مزج أوضاع مختلفة بين النموذج الأساسيّ والنماذج المشتقّة يؤدّي إلى نتيجة غير متوقَّعة، وهذا موثَّق رسميّاً أيضاً.9 في التطبيقات التي تستخدم وراثة النماذج، يجب أوّلاً جرد وتوحيد وضع جميع النماذج.
والآن الفخّ الرئيسيّ: بما أنّ AutoScaleDimensions آليّة تسجِّل «قيمة بيئة التصميم»، فإنّ فتح مصمِّم Visual Studio على شاشة 150% وحفظ النموذج يُعيد كتابة AutoScaleDimensions في Designer.cs بقيمة 150% (في وضع Font تصبح 6F, 12F مثلاً 9F, 18F). وتُحفَظ الإحداثيّات والأحجام أيضاً بقيمة مضروبة في 1.5. عندما يبني عضو من الفريق يعمل ببيئة 100% هذا النموذج ويشغِّله، يظهر كلّ شيء منكمشاً، وتظهر في مراجعة الفروق (diff) فروقات ضخمة تشمل إحداثيّات جميع عناصر التحكّم. هذا حادث كلاسيكيّ في استشارات الدقّة العالية: «عضو جديد بحاسوب محمول عالي الدقّة لمس نموذجاً واحداً فانكسر تخطيط المستودع».
الحلّ الأساسيّ واحد فقط: يجب فتح المصمِّم بدقّة 100% (96 DPI). Visual Studio نفسه تطبيق داعم لـ DPI، لكنّ مصمِّم WinForms (لتطبيقات .NET Framework) غير داعم لـ DPI، لذا عند فتحه على شاشة عالية الدقّة، يظهر شريط معلوماتيّ أصفر يطلب «إعادة تشغيل Visual Studio بتحجيم 100%».5 اتّبع هذا الشريط، أعد التشغيل بوضع عدم دعم DPI، عدِّل النموذج، ثمّ عد إلى الوضع العاديّ بعد الانتهاء ─ اجعل هذا قاعدة معتمَدة في الفريق. يمكن أيضاً التشغيل عبر سطر الأوامر بـdevenv /noScale. في مشاريع .NET 6 فما بعده، يتيح ضبط <ForceDesignerDPIUnaware>true</ForceDesignerDPIUnaware> في ملفّ المشروع (من Visual Studio 2022 17.8 فما بعده) تشغيل تبويب المصمِّم فقط بوضع عدم دعم DPI دون إعادة تشغيل Visual Studio كاملاً (لا يُستخدَم في مشاريع .NET Framework).5
بالنسبة لآليّة الفحص التلقائيّ، فإنّ «رصد أيّ فرق في AutoScaleDimensions في Designer.cs عن القيمة المحدَّدة عبر CI أو pre-commit» طريقة سهلة وفعّالة. من الأرخص إيقاف الحادث عند مدخل الالتزام (commit) بدل إصلاحه بعد وقوعه.
6. الأنماط النمطيّة للانكسار وطريقة إصلاحها
عند رفع وضع إدراك DPI (أو محاولة رفعه)، تقع المواضع المنكسرة غالباً ضمن الأنماط التالية.
| ما ينكسر | السبب | طريقة الإصلاح |
|---|---|---|
| تداخل عناصر التحكّم / قصّها | تخطيط بإحداثيّات وأحجام ثابتة | الاستبدال بـAnchor/Dock، وTableLayoutPanel / FlowLayoutPanel. الاستفادة من AutoSize |
| الأيقونات والصور صغيرة/خشنة | إلصاق صورة نقطيّة مباشرة لـ 96 DPI | تجهيز صور بدقّات متعدّدة والتبديل حسب DPI. تصغير من صورة كبيرة واحدة إن أمكن |
| الرسم الذاتيّ (الرسوم البيانيّة، الرسومات، معاينة التقارير) | كتابة مباشرة بالبكسل إلى Graphics | تحجيم الإحداثيّات وعرض الخطّ والخطّ استناداً إلى DeviceDpi |
| ضيق صفوف DataGridView | تحديد بكسليّ لـRowHeight وما شابه | استخدام AutoSizeRowsMode، أو ضبط قيمة مُحجَّمة وفق DPI |
| أيقونات ToolStrip صغيرة كحبّة الأرزّ | ثابتة 16×16 | ضبط ImageScalingSize وفق DPI |
| عنصر تحكّم معيّن من طرف ثالث أو ActiveX فقط ينكسر | العنصر نفسه غير داعم لـ DPI | التحديث إلى نسخة داعمة من المورِّد. إن لم تتوفّر، فهذا هو سقف مستوى الدعم |
استبدال التخطيط هو محور حجم العمل. بعبارة أخرى، الشاشة المبنيّة أصلاً بـTableLayoutPanel وDock لا تحتاج جهداً يُذكَر حتّى بعد رفع وضع إدراك DPI. مجرّد اعتماد قاعدة «تُبنى الشاشات الجديدة من الآن فصاعداً بلوحات تخطيط من البداية» يقلِّل من الدين المستقبليّ.
تحجيم الرسم الذاتيّ أساسه تحويل القيمة المحسوبة على أساس 96 DPI استناداً إلى Control.DeviceDpi (.NET Framework 4.7+ / .NET).
public partial class ChartPanel : Panel
{
// تحويل القيمة المصمَّمة على أساس 96 DPI إلى الدقّة الحاليّة
private int Scale(int value96) => value96 * DeviceDpi / 96;
protected override void OnPaint(PaintEventArgs e)
{
using var pen = new Pen(Color.Navy, Scale(2));
e.Graphics.DrawRectangle(pen,
Scale(16), Scale(16), Scale(320), Scale(120));
}
// في PMv2 تتغيّر DPI عند الانتقال بين الشاشات، لذا نحفِّز إعادة الرسم
protected override void OnDpiChangedAfterParent(EventArgs e)
{
base.OnDpiChangedAfterParent(e);
Invalidate();
}
}
حتّى System Aware، تبقى دقّة DPI ثابتة عند بدء التشغيل، لذا يكفي إدخال Scale فقط، لكن في PMv2 يتغيّر DeviceDpi مع كلّ انتقال بين الشاشات، لذا يلزم تصميم يُعيد بناء الخطوط والصور وقيم التخطيط المخزَّنة مؤقّتاً عبر أحداث سلسلة DpiChanged.4 «كم عدد شاشات الرسم الذاتيّ» يؤثِّر مباشرةً على تقدير حجم العمل لدعم PMv2.
عناصر التحكّم من طرف ثالث وActiveX/OCX هي العامل الذي يحدِّد سقف هذا التعديل. إن كان العنصر نفسه غير داعم لـDPI، فمهما بذلت من جهد على جانب المضيف، لن تكتمل تلك الشاشة كاملة. تحقّق من حالة دعم المورِّد، وبالنسبة لـActiveX التي لا يُرجى تحديثها، حدِّد كيفيّة التعامل معها من جدول القرار في «هل تُبقي على ActiveX/OCX أم تُغلِّفه أم تستبدله» قبل ضبط هدف دعم الدقّة العالية.
7. استراتيجيّة المعالجة المرحليّة ── جدول القرار حول مدى العمق المطلوب
استناداً إلى ما سبق، يمكن ترتيب مستوى المعالجة في 3 مراحل. المثاليّ التقنيّ هو جعل كلّ التطبيقات PMv2، لكن مع أخذ ميزانيّة التعديل وعمر التطبيق بالحسبان، غالباً ما يكون التسوية هي الإجابة الصحيحة.
| (1) لا شيء (Unaware) | (2) التحوّل إلى System Aware | (3) دعم PMv2 كامل | |
|---|---|---|---|
| المظهر | نيّئ في جميع البيئات (لا ينكسر) | واضح على الشاشة الرئيسيّة. نيّئ عند الشاشة الفرعيّة أو تغيير DPI | واضح في جميع الشاشات |
| العمل الرئيسيّ | لا شيء | إعلان المانيفست/الإعدادات + فحص AutoScaleMode + التحقّق من عرض جميع الشاشات | (2) + فحص شامل للتخطيط + دعم DPI للرسم الذاتيّ وأصول الصور + دعم DpiChanged |
| حجم العمل | صفر | صغير إلى متوسّط (التحقّق يتناسب مع عدد الشاشات) | كبير (محوره إصلاح الانكسار. عناصر التحكّم من طرف ثالث تحدّد السقف) |
| الحالة المناسبة | مُقرَّر إلغاؤه خلال سنوات قليلة. يقبله المستخدمون | تطبيقات العمل الداخليّة المتمحورة حول سطح مكتب ثابت / شاشة واحدة. كمرحلة أولى | استخدام مختلط للحاسوب المحمول + شاشة خارجيّة. تطبيق رئيسيّ طويل العمر. منتج يُوزَّع على العملاء |
محاور القرار ثلاثة: عمر التطبيق (كم سنة سيُستخدَم بعد)، بيئة الاستخدام (إن كان الجميع على نفس سطح المكتب الثابت، فإنّ System Aware يكتمل عمليّاً؛ أمّا إذا كثر استخدام الحاسوب المحمول مع شاشة خارجيّة، فسيبقى استياء من System Aware الذي يظهر نيّئاً عند كلّ انتقال بين الشاشات)، وميزانيّة التعديل. الخطوة الموصى بها هي تنفيذ (2) أوّلاً كمعيار لجميع التطبيقات، ثمّ الاستناد إلى حجم الانكسار الذي وُجد خلال هذه العمليّة وقيود عناصر التحكّم من طرف ثالث لتقرير الانتقال إلى (3) أم لا، وأيّ الشاشات فقط. (2) محوره «الإعلان + الفحص»، ومخاطر الفشل فيه صغيرة، ومع ذلك يتحسَّن إحساس المستخدم كثيراً.
نتطرّق أيضاً للاختبار. غالباً لا تظهر مشاكل الدقّة العالية على جهاز التطوير، لذا يجب تعمُّد إنشاء البيئات التالية للتحقّق.1
- توصيل شاشتين بتحجيم مختلف (مثال: 150% للشاشة المدمجة في الحاسوب المحمول + 100% للشاشة الخارجيّة)، والانتقال بالنافذة بينهما
- تبديل الشاشة الرئيسيّة ثمّ التشغيل بعد إعادة تسجيل الدخول (تُحدَّد دقّة DPI للنظام عند تسجيل الدخول، فلن تتغيّر دون إعادة تسجيل الدخول)
- تغيير إعداد التحجيم أثناء تشغيل التطبيق
- الاتّصال عبر سطح المكتب البعيد (RDP) من عميل عالي الدقّة (بما أنّ RDP ينقل دقّة DPI الخاصّة بالعميل، فإنّ «الطبيعيّ على وحدة تحكّم الخادم لكن منكسر عبر RDP» تقرير شائع)
عندما يصل تقرير بأنّ «الانكسار يحدث فقط عند 125%»، فإنّ إنشاء ذلك التحجيم فعليّاً ومشاهدته هو الأسرع في النهاية، وفق الخبرة. يمكن أيضاً تغيير إعداد التحجيم في الآلة الافتراضيّة، لذا فإنّ تجهيز بيئات تحقّق بنسب 100 / 125 / 150 / 200% يُسرِّع التمييز.
8. الخلاصة
«النِّيَة» في بيئة الدقّة العالية إجراء إنقاذ من نظام التشغيل (الافتراض الوهميّ لـ DPI)، و«الانكسار» دعم DPI ناقص ─ إن أمسكتَ هذه العلاقة وحدها، يمكنك عكس المسار من العرَض إلى السبب والحلّ. طريقة الإعداد تختلف حسب الجيل: في .NET يُستخدَم ApplicationHighDpiMode في ملفّ المشروع، وفي .NET Framework 4.7 فما بعده app.config (بدون استخدام dpiAware في المانيفست معه)، و4.6 فما دون يقف الخطّ الواقعيّ عند System Aware عبر المانيفست. بالإضافة إلى ذلك، فإنّ توحيد AutoScaleMode.Font وقاعدة تشغيليّة تقضي بفتح المصمِّم بدقّة 100% أمران بسيطان لكنّهما الأكثر فاعليّة في تقليل الحوادث.
بعد ذلك، حدِّد مدى العمق المطلوب من المراحل الثلاث في الفصل 7. البدء بالتحوّل إلى System Aware لجعل الشاشة الرئيسيّة واضحة، ثمّ الانتقال إلى PMv2 إذا تناسبت بيئة الاستخدام وعمر التطبيق ─ هذا هو النهج ذو المرحلتين الذي نوصي به فعليّاً في مشاريع التعديل التي نتولّاها. إن كان الوقت قد حان لإعادة النظر في إطار الواجهة نفسه (WPF مصمَّم منذ البداية بقدرة قويّة على التعامل مع DPI)، فإنّ «كيف نختار بين WinForms / WPF / WinUI» أيضاً مادّة جيّدة للنظر فيها. إن ترددتَ في تحديد إلى أيّ مرحلة يمكن إصلاح تطبيقك الحاليّ، يمكننا المساعدة ابتداءً من جرد بنية الشاشات وعناصر التحكّم.
مقالات ذات صلة
- كيف نختار بين WinForms / WPF / WinUI - جدول قرار
- هل تُبقي على ActiveX/OCX أم تُغلِّفه أم تستبدله - جدول قرار
- قائمة فحص ما قبل الترحيل من .NET Framework إلى .NET
- ما هو MFC في Windows - ما هو وكيف يجب التعامل معه اليوم
مجالات الاستشارة ذات الصلة
تتعامل شركة Komura Soft LLC مع دعم الدقّة العالية لتطبيقات WinForms / MFC القديمة (المسح الحاليّ، تحديد مستوى المعالجة، تعديل التخطيط)، وتحقيق أسباب أعطال العرض المصاحبة لاستبدال الحواسيب، واستشارات تجديد الواجهة.
- الاستشارة التقنيّة ومراجعة التصميم
- الاستفادة من الأصول القائمة ودعم الترحيل
- تطوير تطبيقات Windows
- التواصل معنا
المراجع
-
Microsoft Learn، High DPI Desktop Application Development on Windows. حول خلفيّة تحجيم DPI، وسلوك كلّ وضع من أوضاع إدراك DPI، وآليّة تكبير التطبيقات غير الداعمة لـDPI كصورة نقطيّة، ونقاط الاختبار في بيئة DPI مختلطة. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn، Setting the default DPI awareness for a process. حول طريقة الإعلان عبر عنصريّ dpiAware / dpiAwareness في المانيفست، وعلاقة الأولويّة بينهما، وعدم استحسان الإعلان عبر API. ↩ ↩2
-
Microsoft Learn، What’s new in Windows Forms .NET 6. حول التمهيد (bootstrap) عبر ApplicationConfiguration.Initialize، وإعداد ApplicationHighDpiMode في ملفّ المشروع (الافتراضيّ SystemAware)، وتحسين تحجيم PerMonitorV2 في .NET 6. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn، High DPI support - Windows Forms. حول محتوى تعزيز الدقّة العالية في .NET Framework 4.7، وSystem.Windows.Forms.ApplicationConfigurationSection في app.config (DpiAwareness=PerMonitorV2)، وعدم استحسان الإعلان عبر المانيفست لأنّه يُبطِل app.config، وأحداث سلسلة DpiChanged وDeviceDpi. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn، Fix DPI display issues in Windows Form Designer. حول عدم دعم مصمِّم WinForms لـDPI، والشريط المعلوماتيّ الذي يظهر على الشاشات عالية الدقّة لإعادة التشغيل بتحجيم 100%، وdevenv /noScale، وForceDesignerDPIUnaware لمشاريع .NET 6+. ↩ ↩2 ↩3
-
Microsoft Learn، DPI_AWARENESS_CONTEXT handle. حول تعريف وسلوك كلّ سياق من Unaware / System Aware / Per-Monitor / Per-Monitor V2 / UNAWARE_GDISCALED (تحجيم GDI، من Windows 10 1809 فما بعده). ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn، Mixed-Mode DPI Scaling and DPI-aware APIs. حول مزج أوضاع إدراك DPI على مستوى النافذة العلويّة عبر SetThreadDpiAwarenessContext، وواجهات API الداعمة لـDPI مثل GetDpiForWindow. ↩
-
Microsoft Learn، SetProcessDpiAwareness function. حول ضبط إدراك DPI الافتراضيّ للعمليّة عبر API، واستحسان الإعلان عبر المانيفست، وعدم إمكانيّة التغيير بعد الضبط مرّة واحدة. ↩
-
Microsoft Learn، Automatic form scaling - Windows Forms. حول سلوك التحجيم التلقائيّ عبر AutoScaleMode / AutoScaleDimensions / CurrentAutoScaleDimensions، وعدم دعم مزج وضعَي Font وDpi. ↩ ↩2
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
التعامل مع الدقّة العالية (DPI) في WPF ── أسباب الضبابيّة والتلطّخ رغم أنّه «يُفترَض أن يكون محصّناً ضدّ DPI» وطرق العلاج
WPF مصمَّم بحيث يعي System DPI، لكن نقل النافذة إلى شاشة بدقّة DPI مختلفة يجعل الشاشة كلّها تتلطّخ، وتصبح الصور النقطيّة ضبابيّة. نُنظّم ...
دمج مصادقة Entra ID في تطبيقات WinForms/WPF ── التشكيل العمليّ لـ MSAL.NET ووسيط WAM
نُنظّم خطوات دمج مصادقة Entra ID في تطبيقات WinForms/WPF لسطح المكتب. نشرح مفهوم العميل العامّ، وتسجيل التطبيق، وAcquireTokenSilent في MS...
التاريخ والوقت والمناطق الزمنية في تطبيقات الأعمال ── من فخاخ DateTime إلى مبدأ التخزين بتوقيت UTC وتصميم الاختبارات
ينزاح الوقت 9 ساعات بعد نقل الخادم ── نرتّب أسباب أعطال التاريخ والوقت انطلاقًا من خاصيّة Kind في DateTime والتحويل الضمنيّ. نشرح التمييز...
أيقونات علبة النظام والإشعارات المنبثقة في تطبيقات Windows — مزالق NotifyIcon وكيفية اختيار AppNotification المناسب
دليل عملي لإبقاء تطبيق Windows الخاص بالأعمال مقيمًا في علبة النظام (منطقة الإشعارات) وإخطار المستخدم عبر الإشعارات المنبثقة (Toast). يتن...
كيف تفهم عزل الجلسات في Windows — Session 0 وRDP وتشغيل عدة مستخدمين في وقت واحد
يوضح هذا المقال مفهوم «الجلسة» (session) في Windows، وهو موضوع يسبب ارتباكًا مستمرًا لمطوري تطبيقات Windows. يتناول المقال سبب وجود عزل S...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
تطوير تطبيقات ويندوز
ندعم تطوير برامج ويندوز للأعمال، وتكامل الأجهزة، وأدوات التواصل.
الأسئلة الشائعة
أسئلة شائعة حول موضوع هذه المقالة.
- لماذا يظهر تطبيق WinForms نيّئاً (بلا وضوح) على شاشة 4K؟
- ليس خللاً برمجيّاً، بل إجراء إنقاذ من نظام التشغيل (الافتراض الوهميّ لـ DPI). بالنسبة للتطبيقات التي لم تُعلن دعمها لـ DPI، يوهم Windows التطبيق بأنّ «الشاشة بدقّة 96 DPI»، ثمّ يعرض ما رسمه التطبيق ظانّاً أنّه بدقّة 96 DPI بوصفه صورة نقطيّة (bitmap) مكبَّرة. لذلك لا ينكسر التخطيط لكنّه يظهر نيّئاً. وفي المقابل، «واضح لكن منكسر» تعني أنّ دعم DPI أُعلن لكنّ التخطيط عجز عن مجاراته، والسبب في هذه الحالة معاكس تماماً. الخطوة الأولى قبل المعالجة هي تمييز أيّ عرَض من الاثنين يظهر.
- كيف يُضبَط دعم الدقّة العالية في WinForms؟
- تختلف الطريقة باختلاف الجيل. في .NET 6 فما بعده تُستخدم خاصّية ApplicationHighDpiMode في ملفّ المشروع (الافتراضيّ SystemAware)، وفي .NET Core 3.1 / .NET 5 يُستدعى Application.SetHighDpiMode قبل إنشاء أيّ نافذة. أمّا .NET Framework 4.7 فما بعده فيُعلَن فيه توافق Windows 10 عبر المانيفست (manifest) ثمّ يُستخدم إعداد DpiAwareness في app.config، لكن بما أنّ وصف dpiAware في المانيفست يُبطِل إعداد app.config، فالموصى به رسميّاً عدم استخدامهما معاً. أمّا 4.6 فما دون، فالخطّ الواقعيّ يقف عند إعلان System Aware عبر المانيفست.
- أيّهما يجب اختياره، System Aware أم Per-Monitor V2؟
- نوصي بمرحلتين. المرحلة الأولى هي التحوّل إلى System Aware، حيث يُطبَّق التحجيم وفق دقّة الشاشة الرئيسيّة عند بدء التشغيل، فيظهر واضحاً على الشاشة الرئيسيّة. تتمحور حول الإعلان والفحص، ومخاطر الفشل فيها صغيرة، وبالنسبة لتطبيقات العمل الداخليّة القائمة على سطح مكتب ثابت، تكتمل عمليّاً بهذا وحده. أمّا Per-Monitor V2 فيجعل كامل الشاشة واضحاً حتّى عند الانتقال بين الشاشات، لكنّه يتطلّب فحصاً شاملاً للتخطيط، ودعم DPI للرسم الذاتيّ وأصول الصور، ودعم حدث DpiChanged، ما يعني حجم عمل كبير، وإن كانت عناصر تحكّم من طرف ثالث غير داعمة، فذلك يصبح السقف. القرار يُتَّخذ حسب عمر التطبيق وبيئة الاستخدام وميزانيّة التعديل.
- لماذا ينكسر التخطيط عند حفظ نموذج (form) من المصمِّم (Designer)؟
- عند فتح مصمِّم WinForms في Visual Studio على شاشة عالية الدقّة (مثل 150%) وحفظ النموذج، تُعاد كتابة AutoScaleDimensions في Designer.cs بقيمة 150%، وتُحفَظ الإحداثيّات والأحجام أيضاً بقيمة مضروبة في 1.5. عندما يبني عضو من الفريق يعمل ببيئة 100% هذا النموذج، يظهر كلّ شيء منكمشاً. الحلّ هو فتح المصمِّم بدقّة 100% (96 DPI)، وعلى الشاشات عالية الدقّة يمكن إعادة التشغيل بتحجيم 100% من الشريط الأصفر المعلوماتيّ. في مشاريع .NET 6 فما بعده يمكن أيضاً استخدام إعداد ForceDesignerDPIUnaware. من المفيد أيضاً بناء آليّة ترصد عبر CI أو pre-commit أيّ فرق غير متوقَّع في AutoScaleDimensions.
الملف الشخصي للمؤلف
صفحة الملف الشخصي لمؤلف المقالة.
غو كومورا
مؤسّس شركة كومورا سوفت ذ.م.م.
يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.
روابط عامة