دروس xaml و wpf في بريزم
#1
السلام عليكم
اخواني جاءتني عدت رساءل عن كيف ابدا البرمجة في الدلفي بريسم .
قبل الجواب ماهو دلفي بريسم
إقتباس :http://www.youtube.com/watch?gl=FR&v=3PAB_oF5mtY
اذن اضن انه يجب
1- التمكن من طريقة الكتابة
كود :
http://prismwiki.codegear.com/en/Variable_Completion
2- التمكن من البرمجة الشيئة
3- البداية مع برامج بسيطة على سطر الاوامر Console
4-تعلم ado
5- برمجة winform
6-برمجة الوايب تعلم asp.net
7-....الخ
الرد
#2
شكرا جزيلا لك على هذا الطرح المختصرو المنظم

لكن اعذرني

انا اسمع فقط عن دلفي بريسم و اسمع انه منصة الدوت نات في الدلفي

لكن كيف الحصول عليه ؟ و هل هو اداة تطوير مستقلة ام انه يثبت مع فيزيال ستوديو التابع لميكروسوفت ؟

و شكرا لك
الرد
#3
لكن كيف الحصول عليه ؟
هنا:
كود :
https://downloads.embarcadero.com/free/delphi_prism
إقتباس :و هل هو اداة تطوير مستقلة ام انه يثبت مع فيزيال ستوديو التابع لميكروسوفت ؟
ثبت مع فيزيال ستوديو التابع لميكروسوفت ؟
شكرا
انا افضل تثبيت vs 2010 اولا قم البريسم لان اعمل عل السي شارب ايضا
الرد
#4
السلام عليكم
يا اخ زكيري
هل يمكن تثبيت مكونات vcl عليه ام لا ..؟

لاني لا احب ال ADO.net

هل تعرف لماذا ...؟

لاني واجهت مشكلة مزعجة حيث كان عندي قاعدة بيانات لها علاقات فيما بينها واظطررت الى اضافة المشتريات مثلا رقم الفاتورة وتاريخها تم اضافة مكونات او ماذة الفاتورة الاصناف وغيرها وقبل ان اظيفهااحتاج الى جلب ID الذي يؤسس العلاقة وكذلك احتاج الى اضافة البيانات بجدول المخزن واضافة بجدول الموردين اي من هو المورد وبكل حالة احتاج الى جلب ID .

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

ولو فشلت عملية واحدة ستكون مصيبة لان هناك بيانات تم اضافتها وبيانات لا
بين الانسان والكفر ترك الصلاة فمن تركها فقد كفر .
الرد
#5
اول الدروس هي للمبتديئين

دورة XAML WPF من البداية


ان شاء الله ساقدم دروس عن WPF لكي نتعلمها يجب معرفة مبادء في XAML
اذن ماهو لقد وجدت هذه التعاريف وكتبت الموضوع في منتدى اخر الا اني لم اجد اجابة مما جعلني اكون بينكم لعلي اجد من يحب دلفي بريس


[size=4]ملاحضة الكود بالدلفي و السي شارب [/size]
السلام عليكم
لقد فصلت xml من ندرس wpf لاني ارى انه يستحق اهتمام كبير وباذن الله سنقوم بشرح الامور من 0 ان شاء الله .
تعلم XAML
- اساسيات XAML
- مجالات الأسماء في XAML
- Code-Behind
- تسمية العناصر:
- التعامل مع الخصائص البسيطة:
- محولات الأنواع:
- التعامل مع الخصائص المركبة
- خصائص الأحتواء:
- لخصائص المرفقة (Attached Properties)
- تمديدات الوسوم
- ستخدام فئات من مجالات اسماء اخرى:
- استخدام فئات من مجالات اسماء اخرى
التخطيط في WPF
- فلسفة التخطيط في WPF:
- عملية التخطيط في WPF
ربط البيانات DataBinding في WPF
* مقدمّة
* نظام التبعيّة Dependency System في WPF, ومفاهيم ربط البيانات الأساسية
* ربط البيانات من خلال XAML
* ربط البيانات إجرائيًا
* أوضاع الربط والتحديث Data Binding/Updating Modes
* خيارات الربط Data Binding Options

عبد الكريم كنعان
إقتباس :مقدمة: إن XAML هي اختصار Extensible Application Markup Language حيث تلفظ (XAML) بـ Zamel، وهي تستخدم من أجل بناء واجهات لتطبيقات .NET في الويندوز Vista ولكن يمكن استخدامها مه ويندوز XP وويندوز Server 2003، أتت XAML من أجل الفصل بين واجهات المستخدم والكود مثل ASP.NET حيث يمكنك وضع (كودات) ASP.NET في ملف والكود التنفيذي (مثلا C# أو VB) في ملف آخر، عندما يتم ترجمة ملفات XAML فإنها تترجم إلى BAML حيث أنها مشاهة إلى XAML ولكنها أسهل للقراءة وبالتالي هي أسرع في التنفيذ.
دعنا الان عزيزي المبرمج نكتب سويا أول برنامج في XAML.

تعلم Xaml
الكاتب HassanAlattas
[b
إقتباس :]مقدمة:
[/b]XAML (اختصار لـ Extensible Application Markup Language وتلفظ "زامل")، وهي لغة وسوم لتمثيل الكائنات في الدوت نت، تم إنشائها خصيصاً من اجل WPF وتستخدم في تقنيات اخرى مثل WF (Workflow Foundation) و Silverlight.
في WPF تستخدم XAML اساسا من اجل تعريف واجهات المستخدم والغاية من هذا هو فصل الأجزاء المتعلقة بتعريف الواجهة عن الكود في التطبيق. بحيث يكون بامكان المصممين إنشاء الواجهات باستخدام ادوات مخصصة للتعامل مع الصور والرسومات مثل Microsoft Expression Blend، بينما يقوم المطورين بتعريف منطق وسلوك تلك الواجهات من خلال الكود باستخدام ادوات مثل Visual Studio.

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

وقد يظن البعض ان اعتماد XAML على XML له اثر على الأداء ، فمن المعروف ان XML لديها بعض المشاكل المتعلقة بهذا الشأن نظرا لأن المستند يمكن ان يحتوي على الكثير من الوسوم ما يجعل عملية الأعراب تأخذ وقتا اطول.
وللتغلب على هذه المشكلة فإن WPF تقوم بتحويل مستند XAML إلى الصورة الثنائية المكافئة له والتي تسمى بـ BAML (اختصار لـ Binary Application Markup Language)، وهذه التحويل يحدث بدون ان يشعر المبرمج خلال عملية الترجمة.
الرد
#6
اساسيات XAML:
حتى نفهم XAML ، علينا ان نتذكر القواعد التالية:
- كل عنصر في مستند XAML يتم ترجمته إلى مثيل من فئة في الدوت نت. ودائما يكون اسم العنصر مطابقا لأسم فئة معينة، مثلا العنصر <Button> يمثل امر لـ XAML من اجل إنشاء كائن من الفئة Button.
- كما هو الحال في اي مستند XML ، يمكن للعناصر ان تتداخل، وتقوم XAML بتفسير هذا التداخل على انه احتواء ، فإذا وجدت عنصر Button داخل عنصر Grid ، فإن هذا يعني ان الواجهة سوف تتضمن Grid يحتوي على زر
- يمكن تعيين الخصائص من خلال الواصفات (Attributes) ، لكن في بعض الحالات تكون الواصفة غير كافية لتحديد قيمة الخاصية ، لذا فإننا نستخدم صيغة اخرى تسمى بالعنصر الخاصية (Property Element).

لكن قبل ان ندخل في التفاصيل ، لنحاول اولاً ان نلقي نظرة على مستند XAML يمثل نافذة جديدة في الفيجوال استديو(الأسطر مرقمة للتوضيح فقط):
كود :
1 <Window x:Class="WpfApplication1.Window1"
2 xmlns="[url=http://schemas.microsoft.com/winfx/2006/xaml/presentation]http://schemas.microsoft.com/winfx/2006/xaml/presentation[/url]"
3 xmlns:x="[url=http://schemas.microsoft.com/winfx/2006/xaml]http://schemas.microsoft.com/winfx/2006/xaml[/url]"
4 Title="Window1" Height="300" Width="300">
5   <Grid>

6   </Grid>
7 </Window>
كما تلاحظ إن هذا المستند يحتوي على عنصرين فقط ، هما العنصر الجذر والمتمثل في النافذة والعنصر الآخر هو Grid يمكن وضع عناصر اخرى بداخله مثل الكنترولات والأشكال والصور وغيرها.
وبشكل عام يمكن ان يكون العنصر الجذر من اي نوع ، لكنه في WPF غالبا ما يكون احد الأنواع التالية:
- Window
- Page
- Application
- ResourceDictionary

وكما هو الحال مع اي مستند XML فإن كل مستند XAML يجب ان يحتوي على عنصر جذر واحد فقط ، ما يعني انه بمجرد ان نغلق عنصرالنافذة بالوسم </Window> فإن المستند ينتهي عند هذا الحد ولا يمكن ان يأتي اي شئ بعده.

إذا نظرنا إلى الوسم الأفتتاحي للنافذة فإننا سوف نجد العديد من الواصفات التي تم استخدامها، فهناك واصفة الفئة المقابلة ، وواصفتين من اجل تحديد مجالين للاسماء ، بينما الواصفات:
كود :
4 Title="Window1" Height="300" Width="300">
يمثل كل منها خاصية معينة في النافذة وبالتالي فإن النافذة يكون عنوانها Window1 وحجمها 300 في 300 وحدة.
مجالات الأسماء في XAML
من المعروف ان الفئات في الدوت نت تكون داخل مجالات الأسماء(Namespaces) ، وحتى تستطيع XAML تحديد الفئة المقابلة فإنها تحتاج إلى اسم الفئة واسم المجال الذي يحتويها.
وكما عرفنا إن اسم الفئة يتم تحديده في اسم العنصر ، بينما اسم المجال يتم تحديده من خلال الواصفة xmlns الخاصة بـ XML . وعندما ننظر في مستند XAML السابق فإننا نجد ان هناك مجالين اسماء هما:
كود :
2  xmlns="[url=http://schemas.microsoft.com/winfx/2006/xaml/presentation]http://schemas.microsoft.com/winfx/2006/xaml/presentation[/url]"
3  xmlns:x="[url=http://schemas.microsoft.com/winfx/2006/xaml]http://schemas.microsoft.com/winfx/2006/xaml[/url]"
هذين المجالين سوف نجدهما في معظم مستندات XAML وكل مجال يؤدي وظيفة معينة:
- المجال http://schemas.microsoft.com/winfx/2006/...esentation وهو خاص بـ WPF و يتضمن جميع الفئات في WPF بما فيها الكنترولات التي سوف نستخدمها من اجل إنشاء الواجهة. هذا المجال تم التصريح عنه بدون اي بادئة لذا يتم التعامل معه على انه المجال الأفتراضي في المستند، واي عنصر سوف ينتمي لهذا المجال بشكل افتراضي.

- المجال http://schemas.microsoft.com/winfx/2006/xaml وهو خاص بـ XAML ويتضمن بعض الوظائف والعناصر ال****** في إنشاء المستند. نلاحظ ان هذا المجال قد تم التصريح عنه مع البادئة x ، وهذا يعني انه من اجل استخدام اي عنصر ينتمي له فيجب ان نكتب اسمه مسبوقا بتلك البادئة ، مثل : <x:ElementName>.

هذا النوع من التصريح عن مجال الأسماء يسمى بالمجال القائم على اساس URI ، وهناك نوع آخر سوف نتطرق له لاحقا، لكن ما يميز هذه الطريقة ان المجال في XML يتضمن اكثر من مجال مقابل في الدوت نت ، مثلا http://schemas.microsoft.com/winfx/2006/...esentation يتضمن الكثير من المجالات في الدوت نت (جميعها تبدأ بـ System.Windows).

Code-Behind
نستطيع من خلال XAML إنشاء وتعريف واجهة المستخدم ، لكن من اجل تعريف الوظائف في التطبيق التي ستستجيب لأحداث المستخدم فإننا نحتاج إلى كتابة الكود .
ربط مستند XAML بفئة في كود التطبيق يتم من خلال الواصفة x:Class التي تكون صيغتها بهذا الشكل:
كود :
<object x:Class="namespace.classname"...>
  ...
</object>

في المثال السابق سوف نجد:
كود :
1 <Window x:Class="WpfApplication1.Window1"

وهي تخبر XAML بإن يقوم بإنشاء فئة جديدة اسمها Windows1 في المجال WpfApplication1 وتكون مشتقة من الفئة Window .
لاحظ ان هذه الواصفة تبدأ بـ x ما يعني انها تنتمي إلى المجال الخاص بـ XAML ويمكن استخدامها مع العنصر الجذر فقط.
يتم تجزئة الفئة Windows1 في ملفين هما:
- الملف الأول(Window1.g.cs) : يحتوي على الكود الذي يتم توليده تلقائيا في زمن الترجمة (compile time).
- الملف الثاني (Window1.xaml.cs): من اجل ان نقوم بتعريف الدوال التي تعالج الأحداث التي تصدر من العناصر في النافذة، وهذا الملف هو الذي سنتعامل معه بشكل اساسي.
عندما نقوم بالقاء نظرة على الملف Window1.xaml.cs سوف نجده بهذا الشكل:
كود :
namespace WpfApplication1 ;

interface

type
  Window = public partial class(System.Windows.Window)
  public constructor;
end;
  
implementation

constructor Window;
begin
  InitializeComponent();
end;
  
end.

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

تسمية العناصر:
غالبا ما نحتاج إلى كتابة الكود (Code-Behind) الذي يقوم بتغيير خصائص عنصر او اكثر في واجهة المستخدم ، ويمكننا الوصول إلى اي عنصر بشرط ان نقوم بتسميته.
تسمية العناصر في XAML تتم من خلال الواصفة x:Name التي يمكن استخدامها مع اي عنصر يمثل كائن، فلو اردنا ان نسمي العنصر Grid:
كود :
<Grid x:Name="grid1">
ويقوم XAML تلقائيا بإضافة حقل إلى الفئة يمثل ذلك العنصر:
كود :
internal System.Windows.Controls.Grid grid1;
ومن خلال هذا الحقل يمكننا التعامل مع العنصر Grid
كود :
MessageBox.Show(grid1.ActualHeight.ToString());
تذكر ان الواصفة x:Name تنتمي إلى لغة XAML ، ويمكن تطبيقها على اي عنصر في XAML .

استخدام الخاصية Name في العناصر:
الكثير من العناصر في WPF تحتوي على الخاصية Name . ومثل هذا العناصر يمكن تسميتها سواء باستخدام الواصفة x:Name او باستخدام الخاصية Name .
فالعنصر Grid على سبيل المثال يحتوي على الخاصية Name (المعرفة اساسا في الفئة الأب FrameworkElement) ويمكن تسميته من خلالها بالشكل التالي:
كود :
<Grid Name="grid1">
وسواء استخدمت الواصفة x:Name او الخاصية Name فإن النتيجة تكون متساوية ، حيث يتم تحديد اسم الحقل وتحديد قيمة الخاصية Name .
الرد
#7
التعامل مع الخصائص البسيطة:
اصبح معروفا لدينا ان الواصفات في العنصر تقوم بتعيين الخصائص في الكائن المقابل في الدوت نت.
فلو اردنا إنشاء زر يحتوي على النص "This is a button" ويكون لون الخط احمر وخلفيته زرقاء ، فإننا نكتب:
كود :
<Button Background="Blue" Foreground="Red" Content="This is a button"/>
ويمكن استخدام اي واصفة في XAML ، بشرط ان يكون لها خاصية مقابلة تنتمي إلى فئة الكائن في الدوت نت، وسوف تعترض XAML على اي واصفة لا تكون كذلك.

يمكننا ايضاً عمل نفس الزر السابق من خلال كود C# بالشكل التالي:
كود :
var btn: Button := new Button();
        btn.Background := Brushes.Yellow;
        btn.Foreground := Brushes.Red;
        btn.Content := 'This is a button';

محولات الأنواع:
تكون القيمة الواصفة دائما عبارة عن نص ، و المشكلة ان نوع الخصائص المقابلة قد يكون من اي نوع ، ففي الزر السابق ، سوف نجد ان الخاصية Background من النوع Brush .
وحتى تستطيع XAML تعيين مثل هذه الخصائص فلا بد لها اولا ان تقوم بتحويل القيمة النصية إلى قيمة مكافئة من نوع الخاصية المقابلة.
عملية التحويل تتم من خلال محولات النوع (TypeConverters) التي تقوم اساسا بتحويل قيمة من نوع إلى آخر. مثلا المحول BrushConverter مختص بتحويل القيمة من وإلى كائن من النوع Brush.

إذا لم يستطع المحول تحويل القيمة ، او إذا لم تستطع XAML تحديد المحول المرافق للخاصية (او نوعها) فإنها تقوم بتوليد خطأ وتتوقف العملية.

لاحظ ايضاً ان XAML متحسسة لحالة الأحرف فيما يتعلق باسماء العناصر والواصفات، بينما لا تكون متحسسة لحالة الأحرف مع القيم ، لإن محولات الأنواع يمكنها تحويل القيمة النصية بغض النظر عن حالة الأحرف فيها.

التعامل مع الخصائص المركبة
هناك بعض الخصائص التي لا يمكن تعيينها من خلال الواصفات ، بسبب ان قيمتها قد تمثل كائن او عدة كائنات يصعب التعبير عنها بنص بسيط.
لهذا وفرت XAML صيغة اخرى لتعيين الخصائص في الكائنات تسمى بـ "صيغة العنصر الخاصية" (Property Element Syntax) ، وفيها نقوم بإضافة عنصر XML يمثل الخاصية ويكون اسمه على شكل <TypeName.Property> وينتهي بـ </TypeName.Property> ، ويتم تحديد القيمة او القيم المطلوبة داخل هذا العنصر.
مثلا لو اردنا إنشاء نفس الزر السابق باستخدام العنصر الخاصية فإننا نكتب:
كود :
<Button>
  <Button.Background>
    <SolidColorBrush Color="Blue"/>
  </Button.Background>
  <Button.Foreground>
    <SolidColorBrush Color="Red"/>
  </Button.Foreground>
  <Button.Content>
    This is a button
  </Button.Content>
</Button>
لاحظ انه من خلال "العنصر الخاصية" نستطيع ان نحدد او نخصص نوع الكائن الذي يمثل القيمة واي خصائص اخرى بداخله.
فلو اردنا ان نجعل الزر محتويا على صورة بدل النص فإننا سوف نقوم بإضافة عنصر يمثل الصورة بداخل الخاصية:
كود :
<Button>
    <Button.Content>
        <Image Source="help.png"/>
    </Button.Content>
</Button>

و لو اردنا استخدام Brush من نوع LinearGradientBrush لكي نجعل لون الخلفية بلون متدرج فإننا سوف نستخدم :
كود :
<Button>
  <Button.Background>
    <LinearGradientBrush>
    </LinearGradientBrush>
  </Button.Background>
</Button>
ومن اجل ان يعمل هذا التدرج بشكل سليم، فلا بد من تحديد الألوان في LinearGradientBrush ، من خلال تعبئة الخاصية GradientStops والتي تمثل كولكشن كائنات من النوع GradientStop، ومثل هذه الخاصية يمكن تعيينها في XAML من خلال "العنصر الخاصية" فقط:
كود :
<Button>
    <Button.Background>
        <LinearGradientBrush>
            <LinearGradientBrush.GradientStops>
            </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
    </Button.Background>
</Button>
يمكننا بعد ذلك إضافة الكائنات GradientStop وتحديد الألوان المطلوبة :
كود :
<Button>
    <Button.Background>
        <LinearGradientBrush>
            <LinearGradientBrush.GradientStops>
                <GradientStop Offset="0.00" Color="Red" />
                <GradientStop Offset="0.50" Color="Indigo" />
                <GradientStop Offset="1.00" Color="Violet" />
            </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
    </Button.Background>
</Button>

يكون الكود المكافئ بهذا الشكل:
كود :
var brush: LinearGradientBrush := new LinearGradientBrush();
   var gradientStop1: GradientStop := new GradientStop();
       gradientStop1.Offset := 0;
       gradientStop1.Color := Colors.Red;

     brush.GradientStops.Add(gradientStop1);
  var gradientStop2: GradientStop := new GradientStop();
      gradientStop2.Offset := 0.5;
      gradientStop2.Color := Colors.Indigo;

     brush.GradientStops.Add(gradientStop2);
  var gradientStop3: GradientStop := new GradientStop();
      gradientStop3.Offset := 1;
      gradientStop3.Color := Colors.Violet;
     brush.GradientStops.Add(gradientStop3);
     button.Background := brush


يمكننا ايضاً مع بعض الخصائص (التي يكون لها set) تحديد نوع الكولكشن المستخدم :
كود :
<LinearGradientBrush>
    <LinearGradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Offset="0.00" Color="Red" />
            <GradientStop Offset="0.50" Color="Indigo" />
            <GradientStop Offset="1.00" Color="Violet" />
        </GradientStopCollection>
    </LinearGradientBrush.GradientStops>
</LinearGradientBrush>
الرد
#8
خصائص الأحتواء:
تسمح XAML لأي فئة بإن تحدد احدى الخصائص فيها كخاصية احتواء افتراضية، واي عنصر من تلك الفئة يمكن ان يحتوي على عنصر او عدة عناصر بداخله مباشرة بدون الحاجة إلى تحديد عنصر الخاصية.
مثلا خاصية الأحتواء الأفتراضية في الزر هي الخاصية Content لذا يمكننا عمل نفس الزر السابق بدون تحديد هذه الخاصية :
كود :
<Button>
    <Image Source="help.png"/>
</Button>

ايضا خاصية الأحتواء الأفتراضية في LinearGradientBrush هي GradientStops فيمكننا إنشاء التدرج السابق بالشكل التالي:
كود :
<LinearGradientBrush>
    <GradientStop Offset="0.00" Color="Red" />
    <GradientStop Offset="0.50" Color="Indigo" />
    <GradientStop Offset="1.00" Color="Violet" />
</LinearGradientBrush>

تعددت الطرق والنتيجة واحدة:
مما سبق ، يمكن تعيين اي خاصية باكثر من طريقة ، مثلا من اجل تعيين الخاصية Content في الزر فإننا نستخدم اي طريقة من التالي:
كود :
<Button Content="Click Me"/>

<Button>
    <Button.Content>
        Click Me
    </Button.Content>
</Button>

<Button>
    Click Me
</Button>

الخصائص المرفقة (Attached Properties)
بإلاضافة إلى الخصائص الاعتيادية والتي نتعامل معها دائما ، قامت XAML بإضافة مبدأ جديد يسمى بـ "الخصائص المرفقة" ، وهي خصائص يمكن تطبيقها على العديد من العناصر رغم انها معرفة اصلا في فئات مختلفة.

عادة ما تستخدم الخصائص المرفقة من خلال الواصفات حيث يكون اسم الواصفة على الشكل OwnerType.PropertyName وهذه الصيغة تشبه إلى حد كبير الأسم في "صيغة العنصر الخاصية" لكن الفئة المالكة للخاصية هنا (OwnerType) غالبا ما تكون مختلفة عن فئة العنصر الكائن.

تستخدم الخصائص المرفقة في WPF كثيرا مع الواح التخطيط (Layout Panels) مثل Grid و DockPanel.
مثلا من اجل تحديد رقم الصف الذي سوف يوضع فيه العنصر داخل Grid فإننا نستخدم الخاصية المرفقة Grid.Row:
كود :
<Button Grid.Row="1" Content="Click Me"/>

لا تقوم الفئة المالكة للخاصية المرفقة بتعريف خاصية مقابلة بداخلها ، انما تقوم بتعريف دالة لتعيين القيمة تكون على شكل SetPropertyName() ودالة اخرى لأحضار القيمة تكون على شكل GetPropertyName().
مثلا الخاصية المرفقة Grid.Row يتم تحقيقها بهذا الشكل:
كود :
Grid = public class
    public class method GetRow(element: UIElement): Integer;
    public class method SetRow(element: UIElement; value: Integer);
  end;

كما يمكننا تعيين اي خاصية مرفقة من خلال الكود على هذا النحو:
كود :
Grid.SetRow(btn, 1);

تمديدات الوسوم (Markup Extensions)
من خلال الواصفات او العناصر الخاصية نقوم بتعيين خاصية الكائن إلى قيمة جديدة دائما.
بعض الحالات تتطلب منا تعيين الخاصية إلى قيمة موجودة من قبل ، او تعيينها إلى القيمة الخالية (null)، او ربط الخاصية بخاصية اخرى في كائن آخر ، ومثل هذه العمليات وغيرها يمكن إنجازها من خلال ما يسمى بـ" تمديدات الوسوم" (Markup Extensions) .
جميع التمديدات مشتقة من الفئة MarkupExtension (في المجال System.Windows.Markup)، وغالبا ما يكون اسمها منتهيا باللاحقة Extension التي يمكن اهمالها مع XAML.
غالبا ما تستخدم تمديدات الوسوم (Markup Extensions) مع الواصفات ، حيث يكون تمديد الوسم محاطاً بمربعات متعرجة { }.
المثال التالي على بعض تمديدات الوسوم (Markup Extensions):
كود :
<Button Background="{x:Null}"
        Height="{x:Static SystemParameters.IconHeight}"
        Content="{Binding Path=Height, RelativeSource={RelativeSource Self}}"/>

x:Null
التعيين إلى القيمة الخالية (null). حيث قمنا في هذا المثال بتعيين الخاصية Background إلى القيمة الخالية.
x:Static
التعيين إلى خاصية ساكنة في فئة في الدوت نت. في المثال قمنا بتعيين ارتفاع الزر إلى الخاصية الساكنة IconHeight في الفئة SystemParameters.
Binding
من اجل عمليات الربط (Data Binding) في WPF .

وكما نرى فإن هناك تمديدات تنتمي إلى XAML (تبدأ بـ x) واخرى تنتمي إلى WPF، كما يمكننا تعريف تمديدات مخصصة من خلال الأشتقاق من الفئة MarkupExtension.

ملاحظة:
إذا اردنا ان نعين الواصفة إلى نص يبدأ بقوس الأفتتاح { ، فإن علينا استخدام حروف الهروب.
مثلا لو اردنا تعيين الخاصية Content في الزر إلى النص "{some text}" فإننا نكتبها بهذه الطريقة :
كود :
<Button Content="{}{some text}"/>
ولا نحتاج إلى اي حروف هروب مع العنصر الخاصية:
كود :
<Button>
    {some text}
</Button>

الأحداث
يمكننا من خلال الواصفات ايضاً تحديد الإجراء او الدالة المعالجة لحدث في عنصر معين. وتكون الصيغة بهذا الشكل:
كود :
<Button ... Click="Button_Click ">
ويجب ان يحتوي الكود(Code-Behind) على الدالة Button_Click يتفق توقيعها مع توقيع الحدث:
كود :
method Window1.Button_Click(sender: System.Object; e: System.Windows.RoutedEventArgs);
begin
     MessageBox.Show("coucou");
end;

يقدم فيجوال استديو بعض الأدوات ال****** (IntelliSense) مع الأحداث، فبمجرد ان تكتب اسم الحدث متبوعا بعلامة يساوي ، فإنه تظهر قائمة تتضمن إنشاء دالة حدث جديدة او بعض الدوال الأخرى الموجودة مسبقا .

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

استخدام فئات من مجالات اسماء اخرى:
إلى جانب التصريح عن مجال الأسم من خلال URI ، يوجد نوع آخر من التصريح يستخدم من اجل تحديد مجال اسم بعينه في الدوت نت .
وتكون صيغته بهذا الشكل:
كود :
xmlns:Prefix="clr-namespace:Namespace;assembly=AssemblyName"
حيث:
- Prefix: تمثل البادئة التي نريد استخدامها عند التعامل مع الكائنات التي تنتمي لهذا المجال.
- Namespace: يمثل مجال الأسم الذي نريد التصريح عنه.
- AssemblyName: اسم التجمع الذي يحتوي على مجال الأسم. يمكننا اهمال هذا الجزء إذا كان المجال ينتمي إلى المشروع الحالي.

عادة ما يتم التصريح عن المجالات في العنصر الجذر في المستند.
مثلا من اجل التصريح عن المجال MyNamespace في المشروع الحالي:
كود :
xmlns:local="clr-namespace:MyNamespace"

ومن اجل إنشاء كائن في المجال MyNamespace:
كود :
<local:MyObject ...></local:MyObject>

ومن اجل التصريح عن المجال System في الدوت نت:
كود :
xmlns:sys="clr-namespace:System;assembly=mscorlib"

ومن اجل إنشاء كائن من النوع DateTime :
كود :
<sys:DateTime>10/30/2010 4:30 PM</sys:DateTime>

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

افترض ان لديك:
- خلفية ولو بسيطة عن WPF و XAML
- فيجوال استديو 2008
الرد
#9
لماذا كتبت عن هذا الموضوع؟
ومن وجهة نظري الشخصية ، ان موضوع التخطيط (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>

النتيجة:
[attachment=91210:image002.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>
النتيجة:
[attachment=91212:image004.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>
النتيجة:
[attachment=91211:image006.jpg]
الرد
#10
عندما نقوم بتغيير حجم النافذة فإن العناصر سوف تظهر بنفس الشكل تلقائيا.
فعند تكبير النافذة:
[attachment=91213:image008.jpg]
وعند تصغير النافذة:
[attachment=91214:image010.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>
النتيجة:
[attachment=91215:image012.jpg]
والشكل التالي يوضح كيف تتراكم الهوامش:
[attachment=91216:image014.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>
النتيجة:
[attachment=91219:image016.jpg]

[attachment=91220:image018.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>
الرد


التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم