• 0
ddata11

التخطيط (layout) في Wpf

سؤال

في البداية

يجب ان نعرف بإن المقصود بـ Layout هو عملية تحديد حجم وموقع كل عنصر في واجهة المستخدم بحيث ينتج الشكل النهائي المطلوب لتلك الواجهة. وهناك العديد من الكلمات العربية المرادفة لكلمة Layout مثل تخطيط ، تنظيم، تشكيل . وفي كل الأحوال اخترت في هذه المشاركة ان تكون كلمة تخطيط هي الكلمة المرادفة لـ Layout واعتذر ان كنت قد اخطأت في هذا الأختيار ، ايضاً هناك العديد من الكلمات الأنجليزية الأخرى التي لم استطع تحديد الكلمة العربية المرادفة لها ، او لا توجد كلمة عربية متفقا عليها ، لذا تجدني كثيرا ما اضع الكلمة العربية وبجوارها الكلمة الأنجليزية بين قوسين.

افترض ان لديك:

- خلفية ولو بسيطة عن WPF و XAML

- فيجوال استديو 2008

لماذا كتبت عن هذا الموضوع؟

ومن وجهة نظري الشخصية ، ان موضوع التخطيط (Layout) في WPF هو الصعب السهل ، فهو صعب لإن الطريقة المتبعة في WPF مختلفة بعض الشئ عن ما اعتدنا عليه في تقنيات سابقة مثل Windows Form وغيرها، وسهل لأن العملية بمجملها تعني اختيار احد ألواح التخطيط ثم وضع العناصر بداخلها(كما سنرى). وقد يكون هذا احد الأسباب التي دفعتني لأن اكتب حول هذا الموضوع.

فيما مضى:

تعتبر عملية التخطيط (Layout) من اهم العمليات في تصميم واجة المستخدم حيث اننا نقضي معظم الوقت في تحديد حجم وموضع الكنترولات في النافذة لكي يكون الشكل النهائي جذاب ، عملي ومرن في نفس الوقت. لكن التحدي الحقيقي والصعوبة الحقيقية تكمن في التأكد من ان هذا التخطيط يمكن ان يتكيف تلقائيا عندما يتغير حجم النافذة او تتغير دقة الشاشة.

في الإصدار الأول Windows Form كانت عملية التخطيط تتم عن طريق تحديد موقع وحجم كل كنترول ، بالإضافة إلى امكانية استخدام خصائص الإرساء (anchoring) والرصف (docking) التي ساعدتنا كثيرا خلال هذه العملية. ورغم جمال هاتين الخاصيتين ومساعدتها لنا في إنشاء نوافذ و مربعات حوار بسيطة ، إلا انها لم تكن مفيدة في حالات اخرى كثيرة. مثل تقسيم مساحة من النافذة إلى منطقتين متساويتين ومتجاورتين في نفس الوقت (bi-pane)، كذلك فإنها لم تكن مفيدة في الحالات التي يمكن ان يتغير فيها المحتوى بشكل ديناميكي، على سبيل المثال وضع مربع تسمية (Label) بجوار مربع النص (TextBox) ، قد يؤدي إلى التداخل بينهما إذا تغير مربع التسمية بحيث صار محتويا على نص اطول مما كان متوقعاً.

ولسد هذه الفجوة جاء الإصدار الثاني من Windows Form ليقدم الواح مثل FlowLayoutPanel و TableLayoutPanel ، يمكن من خلالها إنشاء نوافذ متطورة ومشابهة لحد كبير لصفحات الوب.

مثل هذه الألواح تسمح للكنترولات بإن تنمو وتكبر وان تزيح الكنترولات الاخرى المجاورة لها بشكل تلقائي. مما سهل علينا التعامل مع المحتوى الديناميكي ، وإنشاء الواجهات المحلية .

لكن المشكلة ظلت في ان عملية التخطيط (Layout) تعتمد اساسا على أحداثيات ثابتة يصعب التعامل معها من اجل إنشاء واجهات اكثر مرونة.

جاءت WPF لتحل هذه المشكلة ، عن طريق ابتكار نظام تخطيط جديد تأثر كثيرا بالاسلوب السابق في Windows Form ، وقام بتغيير الأسلوب القديم الذي يقوم على اساس الأحداثيات الثابتة ، ليصبح التخطيط قائما على اساس التتبع(flow-based layout) .

والنتيجة انه اصبح بامكاننا إنشاء واجهات اكثر تطورا واكثر تعقيدا من السابق، لها ان تعمل بشكل ممتاز مهما كانت دقة الشاشة المستخدمة ، ومهما كان التغيير الحاصل في حجم النافذة .

فلسفة التخطيط في WPF:

لو نظرنا إلى النوافذ في WPF سوف نجد ان كل نافذة يمكن ان تحتوي على عنصر واحد فقط (كون النوافذ مشتقة من الفئة ContentControl). ومن اجل ان نقوم بإضافة اكثر من عنصر اليها فلا بد اولا من ان نضع فيها احد الألواح ثم نضيف اليه العناصر المطلوبة.

التخطيط في WPF بشكل عام يعتمد على هذه الفكرة ، وهي اختيار اللوح المناسب ثم اضافة العناصر اليه.

ومن الجيد هنا ان نذكر بعض القواعد الهامة التي يفضل اتباعها عند تصميم الواجهة:

- يجب ان لا نحدد حجم العناصر بشكل صريح، وبدلا من هذا فإن كل عنصر يمكنه ان يحدد الحجم المناسب له استنادا على ما يحتويه ، فالزر مثلا يمكن ان يتسع تلقائيا كلما زدنا من طول النص بداخله.

- موقع اي عنصر لا يتم تحديده على اساس الاحداثيات (س،ص)، واللوح هو من يقوم بترتيب العناصر وتحديد موضعها في النافذة استنادا على: 1) حجم كل عنصر، 2) ترتيبه داخل اللوح ،3) بعض المعلومات الأخرى التي يتم تزويد اللوح بها من خلال الخصائص المرفقة (Attached Properties).

- تقوم الالواح بتقسيم المساحة المتاحة لها على عناصرها الأبناء، حيث تحاول ان تعطي كل عنصر الحجم الذي يناسبه(استنادا على ما يحتويه العنصر).

- الألواح يمكن ان تتداخل فيما بينها، حيث ان اي لوح يمكن ان يحتوي بداخله على لوح آخر ويقوم اللوح الأب بالتعامل مع اللوح الأبن بنفس الطريقة التي يتعامل بها مع اي عنصر ابن آخر.

عملية التخطيط في WPF

تمر عملية التخطيط (Layout) في WPF بمرحلتين هما: مرحلة القياس (measure) ومرحلة الترتيب (arrange) ، في مرحلة القياس يقوم اللوح بالمرور على العناصر بداخله ويسئل كل عنصر عن الحجم الذي يناسبه. وفي مرحلة الترتيب يقوم اللوح بوضع كل عنصر في مكانه المناسب.

خلال هذه العملية ليس من الضروري ان يتم اعطاء العنصر الحجم الذي يريده تماما ، فقد لا يكون اللوح كافياً لمثل هذا العنصر وفي هذه الحالة يحدث اقتصاص لبعض أجزاء العنصر.

ملاحظة هامة:

تذكر ان الالواح لا تدعم عملية التمرير (scrolling). وان هناك عنصر خاص بهذه العملية هو ScrollViewer يمكن استخدامه في اي مكان وداخل اي عنصر آخر.

الواح التخطيط

جميع الألواح في WPF مشتقة من الفئة المجردة Panel (تقع في المجال System.Windows.Controls)،

ولعل الخاصية Children هي اهم خاصية فيها حيث تمثل كولكشن يحتوي على العناصر الأبناء داخل اللوح.

اهم الفئات المشتقة من Panel هي:

- StackPanel: تقوم بتكديس العناصر بشكل عمودي او افقي.

- WrapPanel: تقوم بترتيب العناصر على شكل اسطر، حيث يتم تعبئة السطر الأول ثم الثاني وهكذا.

- DockPanel: تقوم برصف العناصر في جانب من النافذة ، وتجعل العنصر الأخير يشغل المساحة المتبقية.

- Grid: تقوم بترتيب العناصر على شكل صفوف واعمدة.

- UniformGrid: تقوم بترتيب العناصر على صفوف واعمدة ، لكن جميع الخلايا فيها يكون لها نفس الحجم.

- Canvas: تسمح بوضع العناصر على اساس الأحدثيات (س،ص) . وهذا اللوح يشبه إلى حد كبير الطريقة المستخدمة في WinForm لكن لا يوجد دعم لمميزات anchoring و docking

إضافة إلى ان هناك الواح مخصصة لبعض الكنترولات مثل اللوح TabPanel الذي يستخدم في ترتيب التبويبات داخل TabControl، واللوح ToolbarPanel الذي يستخدم في ترتيب الأزرار في شريط الأدوات (Toolbar) ، وغيرها من الألواح.

استخدام StackPanel

يعتبراللوح StackPanel من ابسط الألواح على الأطلاق ، حيث يقوم بترتيب وتكديس العناصر بشكل عمودي او افقي . ويتم تحديد اتجاه التكديس عن طريق الخاصية Orientation التي يمكن ان تكون قيمتها:

- Vertical *( القيمة الأفتراضية): من اجل ترتيب العناصر بشكل عمودي من الأعلى إلى الأسفل .

- Horizontal: من اجل ترتيب العناصر بشكل افقي من اليسار إلى اليمين.

مثال1:

<Window x:Class="SimpleLayout.Window1"
xmlns="[url="http://schemas.microsoft.com/winfx/2006/xaml/presentation"]http://schemas.microsoft.com/winfx/2006/xaml/presentation[/url]"
xmlns:x="[url="http://schemas.microsoft.com/winfx/2006/xaml"]http://schemas.microsoft.com/winfx/2006/xaml[/url]"
Title="مثال بسيط على Layout" Height="300" Width="300">
<StackPanel>
<Label>A Button Stack</Label>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
<Button>Button 4</Button>
</StackPanel>
</Window>

النتيجة:

post-173477-1250596780_thumb.jpg

مثال2:

نفس المثال السابق مع تغيير اتجاه التكديس.

<Window x:Class="SimpleLayout.Window1"
xmlns="[url="http://schemas.microsoft.com/winfx/2006/xaml/presentation"]http://schemas.microsoft.com/winfx/2006/xaml/presentation[/url]"
xmlns:x="[url="http://schemas.microsoft.com/winfx/2006/xaml"]http://schemas.microsoft.com/winfx/2006/xaml[/url]"
Title="مثال بسيط على Layout" Height="300" Width="300">
<StackPanel Orientation="Horizontal">
<Label>A Button Stack</Label>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
<Button>Button 4</Button>
</StackPanel>
</Window>

النتيجة:

post-173477-1250597135_thumb.jpg

خصائص العناصر المتعلقة بالتخطيط :

رغم ان التخطيط هو من مسئولية اللوح بشكل اساسي إلا ان لكل عنصر بعض الخصائص التي يمكن ان تؤثر خلال هذه العملية. هذه الخصائص هي:

- HorizontalAlignment: تحدد الكيفية التي يتم بها وضع العنصر الأبن داخل اللوح عندما تكون له مساحة افقية فائضة . ويمكن ان تأخذ احدى القيم التالية : Left ، Center ، Right او Stretch *.

- VerticalAlignment: تحدد الكيفية التي يتم بها وضع العنصر الأبن داخل اللوح عندما تكون له مساحة رأسية فائضة. ويمكن ان تأخذ احدى القيم التالية: Top ، Center ، Bottom او Stretch *.

- Margin: تحدد حجم الهامش الذي يجب ان يترك في كل جانب من جوانب العنصر . نوع هذه الخاصية هو Thickness وهو عبارة عن سجل يمكن ان يحتوي على رقم محدد لكل جانب من الجوانب الأربعة (يسار، اعلى، يمين ،اسفل)، القيمة الأفتراضية لهذه الخاصية هو (0, 0، 0، 0) ما يعني ان العنصر ليس له اي هامش(تذكر دائما ان القيمة الأفتراضية لإي خاصية قد تختلف في بعض العناصر).

- MinWidth و MinHeight: لتحديد الحد الأدنى لعرض و ارتفاع العنصر.

- MaxWidth و MaxHeight: لتحديد الحد الأعلى لعرض و ارتفاع العنصر.

- Width و Height: لتحديد عرض وارتفاع العنصر بشكل صريح، بمعنى ان العنصر سوف يظهر بذلك الحجم بغض النظر عن محتواه (هل يكفي ام لا؟ ) وبغض النظر عن خصائص المحاذاة الأفقية او الرئيسية.(لهذا ينصح بعدم استخدام خاصيتي العرض او الأرتفاع او التقليل من استخدامها)

جميع هذه الخصائص معرفة في الفئة FrameworkElement والتي تتفرع منها معظم العناصر في واجهة المستخدم ، بما فيها الألواح نفسها.

ولكي نفهم هذه الخصائص فلا نبد ان نتناولها بشئ من التفصيل.

المحاذاة (Alignment):

تحدد خصائص المحاذاة في العنصر اين وكيف يتم وضع العنصر داخل المساحة المعطاه له من قبل اللوح الأب.

بالنسبة للمحاذاة الأفقية (HorizontalAlignment) يمكن ان تأخذ قيمة من التالي:

- Stretch *: وتعني ان العنصر سوف يتم تمديده ليشغل كل المساحة الممنوحة له.

- Left: وضع العنصر في الجانب الأيسر.

- Center: توسيط العنصر

- Right: وضع العنصر في الجانب الأيمن

اما المحاذا الرئيسية (VerticalAlignment) فيمكن ان تكون:

- Stretch *: وتعني ان العنصر سوف يتم تمديده ليشغل كل المساحة الممنوحة له.

- Top: وضع العنصر في الأعلى

- Center: توسيط العنصر

- Bottom: وضع العنصر في الأسفل

الكود التالي يوضح كيفية التعامل مع المحاذاة الأفقية .

مثال3:

<Window x:Class="ATS.WPFLayout2.Phase1.L_StackPanel.L_StackPanel3"
xmlns="[url="http://schemas.microsoft.com/winfx/2006/xaml/presentation"]http://schemas.microsoft.com/winfx/2006/xaml/presentation[/url]"
xmlns:x="[url="http://schemas.microsoft.com/winfx/2006/xaml"]http://schemas.microsoft.com/winfx/2006/xaml[/url]"
Title="خصائص المحاذاة" Height="300" Width="300">
<StackPanel>
<Label HorizontalAlignment="Center">A Button Stack</Label>
<Button HorizontalAlignment="Left">Button 1</Button>
<Button HorizontalAlignment="Right">Button 2</Button>
<Button HorizontalAlignment="Stretch">Button 3</Button>
<Button>Button 4</Button>
</StackPanel>
</Window>

النتيجة:

post-173477-1250596881_thumb.jpg

عندما نقوم بتغيير حجم النافذة فإن العناصر سوف تظهر بنفس الشكل تلقائيا.

فعند تكبير النافذة:

post-173477-1250597222_thumb.jpg

وعند تصغير النافذة:

post-173477-1250597279_thumb.jpg

لاحظ ايضاً انه لوقمنا بتغيير المحاذاة الرأسية في هذا المثال، فإنه لا يكون لها اي تأثير على العناصر، فعندما يكون اتجاه التكديس رأسي (Orientation تساوي Vertical) في StackPanel، فإنها تقوم بأعطاء كل عنصر الأرتفاع الذي يريده تماما.

وبنفس الطريقة ايضاً فإن المحاذاة الأفقية لا يكون لها اي تأثير على العناصر عندما يكون اتجاه التكديس افقي لأن StackPanel تعطي كل عنصر العرض الذي يريده تماماً.

الهوامش(Margin)

لو عدنا إلى المثال1 ، سوف نجد ان العناصر تلتصق ببعضها البعض، وقد يكون من الأفضل لو اننا استطعنا ان نضع فراغ بسيطا بينها . وهنا يأتي دور الخاصية Margin، فعن طريقها يمكن تحديد الهامش المطلوب لأي جانب من جوانب العنصر الأربعة (يسار، اعلى، يمين ، اسفل) .

توجد مرونة كبيرة في تحديد قيمة الخاصية Margin ، حيث يمكننا اعطاء نفس الهامش لكل الجوانب دفعة واحدة بالشكل التالي:

<Button Margin="5">Button 3</Button>

او تعيين الجوانب الأفقية (left و right) بهامش معين ، والجوانب الرأسية (top و bottom) بهامش آخر :

<Button Margin="5,10">Button 3</Button>

كما يمكننا اعطاء هامش مختلف لكل جانب وفق الترتيب left، top، right، bottom :

<Button Margin="5,10,5,10">Button 3</Button>

وتعيين الهوامش من خلال الكود C# يكون بالشكل التالي:

button1.Margin = new Thickness(5);
//Or
button1.Margin = new Thickness(5, 5, 5, 5);

تذكر دائما ان الهوامش بين العناصر تكون تراكمية ، فإذا وضعنا الزر 2 اسفل الزر 1 وكان الهامش السفلي للزر رقم 1 يساوي 5 والهامش العلوي للزر 2 ايضاً يساوي 5 فإن الهامش النهائي بين الزرين سيكون مساويا لـ 10.

مثال 4:

<Window x:Class="SimpleLayout.ElementsMargin"
xmlns="[url="http://schemas.microsoft.com/winfx/2006/xaml/presentation"]http://schemas.microsoft.com/winfx/2006/xaml/presentation[/url]"
xmlns:x="[url="http://schemas.microsoft.com/winfx/2006/xaml"]http://schemas.microsoft.com/winfx/2006/xaml[/url]"
Title="الهوامش- Margin" Height="300" Width="300">
<StackPanel Margin="3">
<Button Margin="3">Button 1</Button>
<Button Margin="3">Button 2</Button>
<Button Margin="3">Button 3</Button>
<Button Margin="3">Button 4</Button>
</StackPanel>
</Window>

النتيجة:

post-173477-1250597586_thumb.jpg

والشكل التالي يوضح كيف تتراكم الهوامش:

post-173477-1250597661_thumb.gif

خصائص الحجم:

كل عنصر في WPF لديه الخاصتين Width و Height والتي تسمح لنا بتحديد عرض وارتفاع العنصر بشكل صريح ومباشر. وكما ذكرنا سابقا ان مثل هذه التحديد غير مفضل في WPF .

إذا كان من الضروري تقييد او حصر حجم العنصر فإنه من الأفضل استخدام الخصائص :

- MinWidth و MinHeight من اجل تحديد الحد الأدنى لعرض وارتفاع العنصر.

- MaxWidth و MaxHeight من اجل تحديد الحد الأعلى لعرض وارتفاع العنصر.

مثال5:

لنفرض في مثال "المكدس والأزرار" انه قد نقرر ان الأزرار يجب ان تتسع باتساع StackPanel لكن بشرط ان لا يزيد عرضها عن 200 وحدة ولا يقل عن 100 وحدة .

<Window x:Class="SimpleLayout.ElementsSize"
xmlns="[url="http://schemas.microsoft.com/winfx/2006/xaml/presentation"]http://schemas.microsoft.com/winfx/2006/xaml/presentation[/url]"
xmlns:x="[url="http://schemas.microsoft.com/winfx/2006/xaml"]http://schemas.microsoft.com/winfx/2006/xaml[/url]"
Title="حجم العناصر" Height="300" Width="300">
<StackPanel Margin="3">
<Label Margin="3" HorizontalAlignment="Center">
A Button Stack</Label>
<Button Margin="3" MaxWidth="200" MinWidth="100">Button 1</Button>
<Button Margin="3" MaxWidth="200" MinWidth="100">Button 2</Button>
<Button Margin="3" MaxWidth="200" MinWidth="100">Button 3</Button>
<Button Margin="3" MaxWidth="200" MinWidth="100">Button 4</Button>
</StackPanel>
</Window>

النتيجة:

post-173477-1250597775_thumb.jpg

post-173477-1250597804_thumb.jpg

التداخل في الألواح:

كما ذكرنا سابقاً انه يمكن لأي لوح ان يحتوي على لوح آخر ، ويقوم اللوح الأب بالتعامل مع اللوح الأبن بنفس الطريقة التي يتعامل بها مع اي عنصر ابن آخر.

واستخدام اكثر من لوح هو امر شائع في WPF من اجل إنشاء التخطيط المطلوب، فعلى سبيل المثال لو اردنا إنشاء مربع حوار يتكون من زرين موافق والغاء الأمر يكونان في الأسفل ومربع نص يشغل المساحة المتبقية في النافذة فإننا نستخدم:

<DockPanel LastChildFill="True">
<StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right" Orientation="Horizontal">
<Button Margin="10,10,2,10" Padding="3">OK</Button>
<Button Margin="2,10,10,10" Padding="3">Cancel</Button>
</StackPanel>
<TextBox DockPanel.Dock="Top" Margin="10">This is a test.</TextBox>
</DockPanel>

النتيجة

post-173477-1250886392_thumb.png

استخدام Grid:

يعتبر هذا اللوح من افضل الألواح على الأطلاق ويمكننا بواسطته عمل كل شئ يقوم به اي لوح آخر(تقريباً).

يقوم هذا اللوح بتقسيم المساحة المعطاة له إلى صفوف واعمدة غير مرئية ، ويمكن وضع العناصر داخل الخلايا (الناتجة من تقاطع الصف مع العمود) . والجميل هنا انه يمكن وضع اكثر من عنصر في نفس الخلية، وبشكل افتراضي كل Grid يتكون من صف واحد وعمود واحد ، ما يعني بانه يتكون من خلية واحدة بشكل افتراضي.

من اجل اضافة الصفوف و الأعمدة إلى Grid ، فإن علينا استخدام الخاصيتين Grid.RowDefinitions و Grid.ColumnDefinitions ، فلو اردنا اضافة صفين وثلاثة اعمدة فإننا نستخدم:

<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
</Grid>

تكون الصفوف متساوية في الأرتفاع ، والأعمدة متساوية في العرض بشكل افتراضي.

ملاحظة:

لاحظ انه يجب استخدام العنصر Grid.RowDefinitions ، والعنصر Grid.ColumnDefinitions من اجل تحديد الصفوف والأعمدة المطلوبة. تسمى هذه الصيغة في Xaml بـ "صيغة العنصر الخاصية" (Property Element Syntax) وهي طريقة اخرى لتعيين الخصائص في الكائن إلى جانب "صيغة الواصفة" (Attribute Syntax) .

بعد ذلك يمكننا إضافة العناصر إلى Grid وتحديد الصف والعمود الذي يقع فيه كل عنصر عن طريق الخصائص المرفقة Grid.Row و Grid.Column:

<Grid>
………
<Button Grid.Row="0" Grid.Column="0">Top Left</Button>
<Button Grid.Row="0" Grid.Column="1">Middle Left</Button>
<Button Grid.Row="1" Grid.Column="2">Bottom Right</Button>
<Button Grid.Row="1" Grid.Column="1">Bottom Middle</Button>
………
</Grid>

الصفوف والأعمدة في Grid ترقم على الأساس الصفري ، بمعنى ان الصف الأول يكون رقمه 0 والصف الثاني يكون رقمه 1 وهكذا.

إذا لم نقم بتحديد الصف او العمود لعنصر معين فإن هذا العنصر يتم وضعه في الصف الأول والعمود الأول ، بسبب ان القيمة الأفتراضية للخصائص المرفقة Grid.Row و Grid.Column هي صفر(بمعنى الأول).

post-173477-1250886558_thumb.png

حجم الأعمدة والصفوف:

تقدم Grid ثلاث طرق لتحديد ارتفاع الصف وعرض الأعمدة:

- الحجم المطلق (Absolute size): حيث يتم تعيين رقم يمثل عدد الوحدات التي يشغلها العرض او الأرتفاع

<ColumnDefinition Width="100"/>

- الحجم التلقائي(Automatic size): حيث يعطى الصف او العمود القدر الذي يحتاج اليه تماما (استنادا على حجم المحتوى)

 <ColumnDefinition Width="Auto"/>

- الحجم النسبي(Proportional size): حيث يتم تقسيم المساحة المعطاة على الصفوف اوالأعمدة

 <ColumnDefinition Width="*"/>

وبشكل افتراضي، يكون التناسب متساويا ما لم نقم بإضافة رقم معين يسبق النجمة مثل:

<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>

بهذا تكون نسبة الصف الأول إلى الصف الثاني هي 1 إلى 2.

عمل مربع الحوار السابق باستخدام Grid:

باستخدام هذه الطرق في التحجيم فإنه يمكننا استخدام Grid من اجل إنشاء نفس مربع الحوار السابق على النحو التالي :

<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBox Margin="10" Grid.Row="0">This is a test.</TextBox>
<StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal">
<Button Margin="10,10,2,10" Padding="3">OK</Button>
<Button Margin="2,10,10,10" Padding="3">Cancel</Button>
</StackPanel>
</Grid>

الخاصية ShowGridLines:

يمكن عرض خطوط الشبكة في Grid بتعيين هذه الخاصية إلى True (كما يظهر في المثال السابق).

الخصائص المرفقة Grid.RowSpan و Grid.ColumnSpan

يمكننا ان نجعل العنصر يشغل اكثر من صف واحد او عمود واحد من خلال الخصائص Grid.RowSpan و Grid.ColumnSpan، فعلى سبيل المثال لو اردنا ان يكون الزر في الصف الأول والعمود الأول ويشغل صفين وعمودين فإننا نكتب :

<Button Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2">Span Button</Button>

تقسيم النوافذ باستخدام GridSplitter

باستخدام GridSplitter يمكننا ان نجعل المستخدم قادرا على تغيير عرض العمود او ارتفاع الصف بنفس الطريقة التي تظهر في نوافذ مثل Windows Explorer حيث يكون بالأمكان تغيير عرض قائمة المجلدات عن طريق سحب حافتها في الأتجاه المطلوب.

post-173477-1250886672_thumb.png

إضافة GridSplitter إلى Grid عملية سهلة رغم ان الطريقة غريبة بعض الشئ،

ومن الجيد ان نتذكر التالي:

- يجب وضع GridSplitter داخل خلية في Grid ، هذه الخلية يمكن ان تحتوي على عناصر اخرى وفي هذه الحالة يجب ان نتأكد من هذه العناصر لا تقوم بإخفاء GridSplitter (بمعنى تغطيه) عن طريق تعيين الهوامش (Margin). والأفضل ان نقوم بعمل عمود او صف مخصص لـ GridSplitter

- لا يقوم GridSplitter بتعديل حجم الخلية فقط انما يقوم بتعديل حجم الصف او العمود بالكامل، ولكي نجعل هذا السلوك ينسجم مع المظهر في UI فإن علينا ان نجعل GridSplitter يمتد على طول الصف او العمود المطلوب باستخدام الخصائص Grid.RowSpan و Grid.ColumnSpan.

- مبدأيا يكون GridSplitter غير مرئيا ، ومن اجل ان نجعله مرئيا فلا بد من اعطائه حجم معين ينسجم مع الأتجاه الذي يعمل عليه. عن طريق اعطائه عرض معين (مع الأعمدة) او طول معين (مع الصفوف).

- تحدد محاذاة GridSplitter طريقة عمله ، بمعنى هل سيعمل كمقسم افقي (لتغيير حجم الصفوف) او كمقسم رأسي (لتغيير حجم الأعمدة) ، فمن اجل ان يعمل كمقسم افقي فإنه يجب تعيين الخاصية VerticalAlignment إلى Center بحيث يتم تغيير حجم الصف في الأعلى والصف في الأسفل. ومن اجل ان يعمل كمقسم رأسي فإنه يجب تعيين الخاصية HorizontalAlignment إلى Center بحيث يتم تغيير حجم العمود في اليسار والعمود في اليمين. (يمكن ايضاً استخدام الخصائص ResizeDirection و ResizeBehavior في GridSplitter من اجل تحديد السلوك المطلوب)

المثال التالي يوضح كيفية عمل مقسم رأسي لتغيير حجم الأعمدة :

<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="100"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition MinWidth="50"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Margin="3">Left</Button>
<Button Grid.Row="0" Grid.Column="2" Margin="3">Right</Button>
<Button Grid.Row="1" Grid.Column="0" Margin="3">Left</Button>
<Button Grid.Row="1" Grid.Column="2" Margin="3">Right</Button>
<GridSplitter Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"
Width="3" VerticalAlignment="Stretch" HorizontalAlignment="Center"
ShowsPreview="False"></GridSplitter>
</Grid>

post-173477-1250886672_thumb.png

الخاصية ShowsPreview :

تكون قيمة الخاصية ShowsPreview في GridSplitter هي False بشكل افتراضي ، مايعني ان GridSplitter سوف يقوم بتغيير حجم العمود او الصف مباشرة خلال عملية السحب، وعند تغيير هذه الخاصية إلى True فإن GridSplitter سوف يسمح للمستخدم ان يقوم بمعاينة الحجم المحدد اولا وعند تحرير زر الماوس فإن الحجم الجديد يتم تطبيقه.

سوف احاول إن شاء الله ان اضع الجزء الثاني المكمل في اقرب وقت.

تم تعديل بواسطه زكيري عبد العالي
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

2 إجابة على هذا السؤال .

  • 0

جزاك الله خيرا ... ننتظر الجزء التانى .. فعلا موضوع مشوق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

مجهود أكثر من رائع ,كنت ابحث عن مواضيع عن هذه التقنيه ولكن كانت كلها باللغة الانجليزية , بارك الله فيك يا اخى وجعله الله فى ميزان حسناتك

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .