دوشنبه ۹ اسفند ۱۳۹۵
 
 
 
کلمه عبور خود را فراموش کرده اید؟
 

 
 
 چیدمان و طراحی کنترل ها در WPF
WPF Graphics
تاریخ ثبت:  ۸۷/۹/۱۰
تعداد نمایش:  ۱۰۵۹۱
  نویسنده: مهدی کیانی
 
   ۱۷  نفر تا این لحظه به این مقاله امتیاز داده اند.
 
   Bookmark and Share

مقدمه

در بخش هاي قبلي، مقدماتي در مورد تکنولوژي WPF و زبان XAML که در اين تکنولوژي بسيار مورد استفاده قرار مي گيرد، صحبت کردم. در اين بخش و بخش هاي بعدي، نحوه استفاده از کنترل هاي Container را جهت چيدمان ساير کنترل ها بر روي پنجره ها مورد بررسي قرار خواهم داد.

اما قبل از آن نگاهي گذرا به نحوه ايجاد يک برنامه WPF در محيط ويژوال استوديو 2008 خواهيم داشت.

ايجاد برنامه هاي WPF

نحوه ايجاد يک پروژه WPF دقيقا مانند نحوه ايجاد پروژه هاي WinApp مي باشد که قبلا نيز بسيار از آن استفاده کرده ايد. تنها ذکر چند نکته ضروري مي باشد که در ادامه خواهيم ديد.

ابتدا براي ايجاد يک پروژه WPF بايستي به پنجره New Project برويد. اين پنجره را به روش ها مختلفي مي توانيد باز کنيد ( که حتما با آن ها آشنايي داريد).

اين پنجره را در شکل زير مشاهده مي کنيد:

 

همانطور که در شکل نشان داده شده است، دو قالب کلي براي ايجاد برنامه هاي WPF موجود مي باشد. اولين قالب گزينه WPF Application مي باشد. که موضوع اصلي ما نيز همين گزينه است. و ديگري گزينه WPF Browser Application مي باشد. در ادامه توضيحات مختصري در مورد هر يک از اين دو قالب برنامه نويسي WPF خواهم داد. نکته ديگري که در ويژوال استوديو 2008 قابل توجه است، اين است که شما مي توانيد نسخه دات نت فريم ورک خود را انتخاب کنيد، و برنامه خود را بر طبق آن نسخه پياده سازي کنيد. ( به اين قابليت اصطلاحا Multi targeting ) مي گويند.

قالب WPF Application

اين مدل از برنامه نويسي WPF ، شباهت بسيار زيادي با مدل برنامه نويسي WinApp دارد. در عين حال نيز تفاوت هاي بسياري با آن نيز دارد که مهمترين تفاوت بين آن ها، کنترلي است که به عنوان پدر تمامي کنترل هاي ديگر شناخته مي شود. در برنامه نويسي WinApp تمامي کنترل هاي بايستي، بر روي آبجکتي از کلاسي به نام Form قرار بگيرند. در حالي که در WPF اين کنترل، آبجکتي از کلاس Window مي باشد. زماني که يک پروژه WPF Application ايجاد مي کنيد، يک آبجکت از کلاس Window ساخته مي شود که به صورت پيش فرض نام آن Window1 مي باشد. هر کلاس Window داراي دو حالت قسمت مجزا مي باشد. قسمتي مربوط به کد نويسي و ايجاد منطق هاي برنامه شما، و قسمت ديگر مربوط به Design برنامه مي باشد، که در اين قسمت دستورات XAML را مي توانيد مشاهده کنيد و اقدام به طراحي برنامه خود نماييد. شکل زير نتيجه حاصل از ايجاد يک پروژه WPF Application را نشان مي دهد.

همانطور که مشاهده مي شود، يک Window به وجود امده است. بخش هاي مختلف روي عکس مشخص شده است. تغييراتي در دو پنجره Toolbox و Properties به وجود امده است که با مشاهده آن، خودتان متوجه تغييرا تخواهيد شد.

نکته اي که مهم است اين است که در بيش از 90 درصد زمان کار با پروژه خودتان، به سراغ پنجره هاي Toolbox و Properties نخواهيد رفت. ( در دات نت 2.0 تقريبا عکس اين موضوع بود) اين موضوع به اين دليل است که تقريبا تمامي کارها در پروژه شما با نوشتن دستورات و کد ها در قسمت XAML صورت مي گيرد. از ايجاد آبجکت ها، تنظيم خواص، رويداد ها و .... ( البته در بعضي موراد هم استفاده از پنجره Properties باعث صرفه جويي در وقت خواهد شد).

قالب WPF Browser Application

اين قالب که يک جنبه جديدي از برنامه نويسي را پيش روي شما قرار مي دهد، شباهت زيادي به برنامه هاي تحت وب دارد. بزرگترين تفاوت آن با مدل WPF Application اين است، که در اين حالت کنترل مادر، به جاي Window ، آبجکتي است که از کلاس Page ارث بري مي کند. اين نوع برنامه ها، مستقيما توسط مرورگرهاي وب از جمله IE و Fire Fox قابل اجرا شدن هستند. البته محدوديت هايي در به کار گيري جنبه هايي از WPF در اين مدل، وجود دارد. به عنوان مثال بسياري از افکت هاي گرافيکي را نمي توان در اين روش به کار برد.

توصيه: هميشه در هنگام ايجاد پروژه ها، نسخه 3.5 از دات نت فريم ورک را انتخاب کنيد. به دليل اينکه WPF 3.5 از لحاظ کارايي نسبت به WPF 3.0 بهتر شده است.

نکته: همچنان مي توانيد در برنامه هاي WPF از فرم هاي ويندوزي سابق نيز استفاده کنيد.

 کلاس APP:

کلاس ديگري که هر پروژه WPF حتما يک نمونه از آن را دارا مي باشد، کلاس APP مي باشد که از کلاس Application ارث بري مي کند. اين کلاس نيز داراي بخشي کد به صورت XAML مي باشد که در زير مشاهده مي کنيد:

<Application x:Class="WpfApplication1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <Application.Resources>
        
    </Application.Resources>
</Application>

همانطور که مي بينيد، آبجکتي از کلاس Application ايجاد شده است که کلاس App را به عنوان کلاسي که کد هاي آن در آن جا قرار دارد، معرفي کرده است. دو آيتمي که در کد فوق جديد هستند عبارتند از خاصيت StartupUri و تگ Resources .

خاصيت StartupUri ، نام کلاسي را مشخص مي کند که به عنوان اولين پنجره برنامه يا همان پنجره اصلي برنامه نمايش داده خواهد شد.
تگ Resources که مي تواند با خيلي از کنترل هاي به کار رود، منابع برنامه شما را مشخص مي کند. چنانچه اين تگ در کلاس Application و به صورتي که در کد فوق مشاهده مي کنيد، تعريف شود، منابعي که در آن تعريف مي شوند به عنوان منابع کل پروژه مي باشند که در همه جاي پروژه قابل استفاده مي باشند.

اگر بخواهيم، تناسبي بين اين کلاس و کلاسي در دات نت فريم ورک 2.0 ايجاد کنيم، مي توان گفت که کلاس Application در WPF عملکردي مانند کلاس Program در برنامه هاي WinApp دارد. همچنين دستور StartupUri چيزي شبيه به دستور Application.Run در کلاس Program مي باشد.

چيدمان عناصر در WPF

در بخش قبلي، با مقدمات محيط طراحي و کد نويسي ويژوال استوديو 2008 آشنا شديد. در اين بخش به کنترل هاي کانتينر ( کنترل هايي که مي توانند کنترل هاي ديگر، شامل همه کنترل هاي ويژوال و نيز کنترل هاي کانتينر ديگر را در برگيرند) مي پردازيم.

کنترل هاي کانتير اساس برنامه نويسي در WPF محسوب مي شوند. اين کنترل ها، امکانت متعددي را در اختيار شما قرار مي دهند که بتوانيد کنترل هاي خود را به صورت صحيح بر روي فرم خود قراردهيد.
در WPF کنترل هاي کانتينر متعددي وجود دارد که هر يک به نوعي امکانات خاصي را براي چيدمان کنترل هاي شما ايجاد مي کنند. به عنوان مثال توسط کنترل کانتينري به نام StackPanel مي توانيد، کنترل هاي خود را به صورت پشته اي قراردهيد. همچنين کنترلي به نام Grid به شما اجازه قرار دادن و تنظيم کنترل ها را در سلول هايي در سطر ها و ستون هايي که شما تعيين مي کنيد، را مي دهد. اما قبل از وارد شدن به بحث کنترل هاي کانتينر و معرفي ان ها و خواص و امکاناتي که براي شما فراهم مي کنند، بهتر است نگاهي به پايه و اساس قالب بندي يا طرح بندي (Layout) در WPF و تفاوت آن با نسخه هاي قبلي دات نت فريم ورک بياندازيم.

فلسفه چيدمان و قالب بندي در WPF

در دات نت فريم ورک 1.x (1.0 و 1.1) ، دو خاصيتي که در چيدمان عناصر بر روي فرم ها، موثر بودند، خواص Anchor و Dock بودند. توسط اين دو خاصيت مي توانستيد، کنترل ها را بر روي فرم خود، چنان تنظيم کنيد، که در صورت تغيير سايز فرم، کنترل ها نيز به تناسب ان تغيير سايز بدهند و يا محل قرار گيري آ نها به صورت پويا تغيير کنيد. اما باز هم اين خواص جواب گوي نياز هاي شما به صورت کامل نبودند. به ويژوه زماني که کنترل هاي خود را به صورت پويا و در زمان اجراي برنامه ايجاد مي کرديد، اين مسئله بيشتر باعث عذاب و رنجش بود. به صورتي که گاها نياز به کد نويسي هاي بسياري براي چيدمان کنترل ها بر روي فرم بود.

دردات نت فريم ورک 2.0 عناصر ديگري اضافه شدند که مي توانستند، چيدمان عناصر را تا حدي، کنترل نمايند. يکي از اين کنترل ها، کنترل FlowLayoutPanel بود (است). امااين کنترل ها نيز قابليت ها و کارايي بسيار خوبي را مهيا نمي کردند. ودليل ديگر آن اين بود که اين کنترل ها به صورت يک افزونه وارد دات نت 2.0 شده بودن و در واقع جزء هسته اصلي فرم هاي ويندوزي نيستند و به واقع يک افزونه براي آن ها به شمار مي آيند. مانند کنترل هاي بسياري که شرکت هاي ثالث نوشته اند و مي نويسند. علاوه بر اين، اساس اين کنترل ها نيز بر پايه مکان قرار گرفتن کنترل ها مي باشد که اين خود نيز به نوعي محدوديت محسوب مي شود.

تکنولوژي WPF سيستم جديدي را از پايه براي شما فراهم مي کند که به شما اجازه ايجاد برنامه هايي را مي دهد که وابسته به سايز و يا رزولوشن صفحه نمايش نباشد. همانطور که قبلا نيز گفته شد، تعيين سايز و محل قرار گيري کنترل ها به صورت مشخص و ثابت، کارايي برنامه را به شدت کاهش مي دهد.( البته در مواردي اجتناب ناپذير است. به عنوان مثال زماني که از Canvas استفاده مي کنيد، ناچار هستيد که محل قرار گيري کنترل هاي روي آن را صراحتا تعيين کنيد) .
راه حل WPF براي اينکه بتوان بر محل قرارگيري و اندازه کنترل ها نظارت کامل داست، استفاده کردن از کنترل هايي است که بدين منظر ايجاد شده اند.

چند نکته اصلي و مهم در پشت مفهوم فلسفه چيدمان و قالب بندي در WPF وجود دارد که تيتر وار بيان مي شوند:

الف) سايز عناصر نبايستي صراحتا تعيين گردد ( تا جاي که امکان پذير باشد)

ب) محل قرار گيري عناصر نبايد به صورت دستي نسبت به گوشه صفحه نمايش تعيين گردد( تا جايي که ممکن باشد)

ج) کنترل هاي کانتينر، مي توانند به صورت داخلي قرار بگيرند.( هر کنترل کانتينر مي تواند شامل 0، 1 و يا بيش از يک کنترل کانتينر ديگر باشد)

د) کل فضاي موجود يک کنترل کانتينر بين تمامي کنترل هاي دروني آن (Children Elements ) تقسيم بندي مي شود. اين تقسيم بندي بر اساس نياز هر کنترل به فضايي که نياز دارد تعيين مي گردد و مي تواند به صورت پويا تغيير کند.

 

کنترل هاي کانتينر (Container Controls )

همانطور که قبلا نيز اشاره شد، تمامي کنترل هاي قالب بندي WPF از کنترل پايه اي به نام Panel ارث بري مي کنند. اين کنترل نيز طي ارث بري هايي به آبجکت Dispatcher Object ختم مي شود.
کنترل هاي اساسي کانتينر در WPF عبارتند از:
الف) Stack Panel
ب) Canvas
ج) Dockpanel
د) WrapPanel
ه) UniformGrid
ي) Grid

که در زير توضيح مختصري در مورد هر يک داده شده است. و در ادامه به صورت مفصل به بررسي هريک از اين عناصر با ذکر مثتال هايي خواهم پرداخت .

کنترل StackPanel :
همانطور که از نام آن مشخص است، اين کنترل, عناصر را به صورت پشته اي مرتب مي کند. به دو صورت افقي و عمودي مي توانيد کنترل ها را قرارد هيد.

کنترل Canvas :
ين کنترل اجازه قرار گرفتن کنترل ها را در مکان مشخص و ثابتي مي دهد. پس از قرار گرفتن عناصر بر وري اين کنترل، مکان ان ها براي هميشه ثبت مي ماند.

کنترل DockPanel :
اين کنترل عملکردي شبيه به خاصيت Dock در کنترل هاي دات نت فريم ورک2.0 را دارد. با اين کنترل مي توانيد، عناصر خود را نسبت به لبه هاي مختلف آن تنظيم نماييد.

کنترل WrapPanel :
اين کنترل، عناصر را به صورت سطري و ستوني تا جايي که امکان داشته باشد، قرار مي دهيد. در حالت سطري، کنترل ها تا جايي که بتوانند در يک سطر قرار مي گيرند. اگر فضاي مورد نياز کنترل ها از فضاي موجود در يک سطر بيشتر باشد، بقيه کنترل ها به سطر بعدي منتقل مي شوند. در حالت ستوني نيز عملي مشابه، ولي در مورد ستون ها انجام ميگيرد.

کنترل UniformGrid :
اين کنترل شبيه به کنترل Grid ميباشد. با اين تفاوت که در اين کنترل، سايز تمامي سلول ها يکسان مي باشد.

کنترل Grid :
اين کنترل، از پرکاربرد ترين کنترل هاي کانتينر مي باشد. اين کنترل با ايجاد سطر ها و ستون هايي به شما امکان قرار دادن عناصر خود را در سلول مشخصي از ان مي دهد. اين کنترل
شبيه به کنترل TableLayoutPanel در دات نت فريم ورک 2.0 مي باشد.

کنترل StackPanel

اين کنترل، عناصر داخل خودش را که در خاصيت Children اين کنترل قرار گرفته اند را بر اساس جهتي که شما مشخص مي کنيد ( افقي يا عمودي) به صورت پشته اي مرتب مي کند.

نحوه تعريف StackPanel به صورت زير مي باشد:

<StackPanel>
    <!-- Some Controls Goes Here-->
</StackPanel>

به عنوان مثال کد زير، سه کنترل TextBox و يک کنترل Button بر روي StackPanel قرار مي دهد.

<StackPanel>       
        <TextBox Margin="3" Name="txtNum1"></TextBox>
        <TextBox Margin="3" Name="txtNum2"></TextBox>
        <Button  Margin="3" Name="btnSum" Click="btnSum_Click">Get Sum</Button>
        <TextBox Margin="3" Name="txtResult"></TextBox>
       
</StackPanel>

شکل حاصل از دستورات فوق، مشابه زير خواهد بود:

همانطور که اشاره شد، کنترل StackPanel قابليت چيدن عناصر را به صورتي افقي نيز دارا مي باشد. با به کار گيري خاصيت Orientation از اين کنترل مي توانيد، نحوه قرار گيري عناصر را مشخص سازيد. اين حاصيت داراي دو مقدار Horizontal و Vertical مي باشد. که به ترتيب براي تراز کردن عناصر به صورت افقي و عمودي بر روي StackPanel به کار مي رود.
به عنوان مثال در کدزير، چهار دکمه به صورت افقي قرار گرفته اند:

<StackPanel Margin="5" Orientation="Horizontal" Button.Click="ButtonClick" >
    <Button>First Button</Button>
    <Button>Second Button</Button>
    <Button>Third Button</Button>
    <Button>fourth Button</Button>
</StackPanel>

در اين کد، خاصيت Orientation در تگ آغازين کنرل StackPanel بر روي Horizontal قرار گرفته است.

نکته:
مقدار پيش فرض خاصيت Orientation برابر با Vertical مي باشد. در واقع اگر خاسيت Orientation را براي StackPanel تنظيم نکنيد، عناصر به صورت پشته عمودي قرار خواهد گرفت. هر کنترلي علاوه بر خواص مخصوصي به خودش داراي خواصي مي باشد که تقريبا بين همه کنترل ها مشترک هستند. در واقع خواصي در WPF وجود دارد که اکثر کنترل هاي WPF ، ان خواص را شامل مي شوند. اين خواص در هر کنترلي عملکردي مشابه خواهد داشت. در بخش بعدي به تعدادي از اين خواص اشاره خواهيم کرد.

خواص تراز بندي

دو خاصيت HorizontalAlignment و VerticalAlignment که در موارد متعددي استفاده مي گردند، محل قرار گيري افقي و عمودي کنترل را نسبت به کنترل کانتينر خودش مشخص مي کند.

خاصيت HorizontalAlignment

مقادرير خاصيت HorizontalAlignment عبارتند از :

Left : اين مقدار، باعث مي شود که کنترل مورد نظر از سمت چپ کنترل پدرش تراز شود.
Right : اين مقدار، باعث مي شود که کنترل مورد نظر از سمت زاست کنترل پدرش تراز شود.
Center : اين مقدار، باعث مي شود که کنترل مورد نظر در قسمت وسط کنترل پدرش تراز شود.
Stretch : اين مقدار باعث مي شود که کنترل تمامي عرض کنترل پدرش را پوشش دهد.

عکس زير، موارد گفته شده را نشان مي دهد:

کدي که براي برنامه فوق نوشته شده است:

<Window x:Class="StackPanel.HAlignment"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="HAlignment" Height="300" Width="300">
<StackPanel>
<TextBox HorizontalAlignment="Left" Name="txtNum1">HorizontalAlignment="Left"</TextBox>
<TextBox HorizontalAlignment="Right" Name="txtNum2">HorizontalAlignment="Right"</TextBox>
<Button HorizontalAlignment="Center" Name="btnSum" Click="btnSum_Click">Get Sum(HorizontalAlignment="Center")</Button>
<TextBox Name="txtResult">HorizontalAlignment="Stretch"</TextBox>
</StackPanel>
</Window>

خاصيت VerticalAlignment

اين خاصيت داراي چهار مقدار زير مي باشد :
Top: که باعث مي شود کنترل از سمت بالاي کنترل پدر خويش تراز شود.
Bottom : که باعث مي شود کنترل از سمت پايين کنترل پدر خويش تراز شود
Center: که باعث مي شود کنترل دروسط کنترل پدر خويش تراز شود.
Stretch: که باعث مي شود، کنترل از تمامي فضاي موجود، استفاده کند.

نکته:
کنترل StackPanel ، به کنترل هاي فرزند خود به همان مقدار فضا که نياز دارند، فضا اختصاص مي دهد. به همين دليل اگر دستورات مروبط خاصيت VerticalAlignment را با شکل فوق به کار ببريد، تاثيري در چيدمان کنترل ها نخواهد داشت.

خاصيت Margin

اين خاصيت، فاصله کنترل را از کنترل هاي اطراف خودش مشخص مي کند . اين خاصيت داراي چهار مقدار Left،Top،Bottom و Right مي باشد.
نحوه مقدار دهي اين خاصيت در اسناد XAML به صورت زير مي باشد:

<ElementName ... Margin="5,5,5,5"></ElementName>

با کد فوق، عنصري که براي آن خاصيت Margin مشخص شده است، از هر طرف به مقدار 5 واحد با کنترل هاي اطرافش فاصله خواهد دشت.

نکته:
اگر مقادير فاصله اي که مي خواهيد قرار دهيد براي هر چهار طرف يکسان باشد، کافي است به جاي کد فوق از کد زير استفاده کنيد:

<ElementName ... Margin="5 "></ElementName>

دو قطعه کد فوق يکسان مي باشند. در واقع مي توانيد تنها با قرار دادن يک، هر چهار مقدار اين خاصيت را مقدار دهي کنيد.

شکل زير، نمونه اي از نحوه استفاده از اين خاصيت را مشخص مي کند:

کد مربوط به شکل فوق:

<StackPanel>
<TextBox HorizontalAlignment="Left" Margin="5" Name="txtNum1">Margin="5,5,5,5"</TextBox>
<TextBox HorizontalAlignment="Right" Margin="5,10,0,25" Name="txtNum2">Margin="5,10,0,25"</TextBox>
<Button HorizontalAlignment="Center" Margin="10,0,0,30" Name="btnSum" Click="btnSum_Click">Margin="10,0,0,30"</Button>
<TextBox Name="txtResult" Margin="0,50,0,0" >Margin="0,50,0,0"</TextBox>
</StackPanel>

خواص سايز

شش خاصيت زير براي تنظيم سايز کنترل ها به کار مي روند:

خاصيت Width : اين خاصيت، عرض کنترل را به صورت صريح مشخص مي کند.

خاصيت Height : اين خاصيت به صورت صريح، مقدار ارتفاع کنترل را مشخص مي کند.

خاصيت MinHeight: اين خاصيت مينيمم ارتفاعي را که يک کنترل مي تواند اختيار کند را مشخص مي کند.

خاصيت MinWidth: اين خاصيت مينيمم عرضي را که يک کنترل بايد داشته باشد را مشخص مي کند.

خاصيت MaxHeight: اين خاصيت ماکزيمم ارتفاعي را که يک کنترل مي تواند اختيار کند را مشخص مي کند.

خاصيت MaxWidth: اين خاصيت ماکزيمم عرضي را که يک کنترل بايد داشته باشد را مشخص مي کند.

نکته:
همانور که گفته شد، تا جايي که امکان پذير است، نبايستي از خواص Width و Height براي مقدار دهي عرض و ارتفاع کنترل ها استفاده کرد. يکي از مواردي که اين موضوع مي تواند کارايي برنامه را پايين آورد، زماني است که بخواهيد برنامه خود را Localizable کنيد.

کنترل Canvas

اين کنترل نيز يکي ديگر از کنترل هاي کانتينري مي باشد که عناصر مختلف مي توانند بر روي آن قرار بگيرند. از اين کنترل به ندرت در برنامه ها استفاده مي شود. به اين دليل که اين کنترل، عناصر داخلي خود را بر مبناي مکان آن عنصر که به صورت صريح در خواص آن عنصر ذکر گرديده است، تراز بندي مي کند. به همين دليل در مواقعي که امکان تغيير سايز پنجرها و مقادير عناصر در زمان اجراي برنامه باشد، استفاده از اين کنترل، انتخاب مناسبي نمي تواند باشد.

قبلا اشاره شد که کنترل هايي که درون کنترل هاي کانتينر قرار مي گيرند، بسته به نوع کنترل کانتينر، خواص جديدي به مجوع خواص آن ها اضافه مي شود. کنترل Canvas نيز از اين امر مستثنا نيست.
چهارخاصيت Left ،Top ، Bottom و Right ، به کنترل هاي فرزندي که درون کنترل Canvas قرار بگيرند، اضافه خواهد شد که توسط اين خواص، محل کنترل فرزند بر روي کنترل Canvas تعيين مي شود.

به نمونه کد زير دقت کنيد:

<Window x:Class="StackPanel.CanvasContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CanvasContainer" Height="300" Width="300">
<Canvas>
<TextBox Canvas.Left="10" Canvas.Top="10" Name="txtNum1">HCanvas.Left="10" Canvas.Top="10"</TextBox>
<TextBox Canvas.Right="30" Canvas.Top="50" Name="txtNum2">Canvas.Right="30" Canvas.Top="50"</TextBox>
<Button Canvas.Left="40" Canvas.Top="90" Name="btnSum" Click="btnSum_Click">Canvas.Left="40" Canvas.Top="90"</Button>
<TextBox Canvas.Right="30" Canvas.Bottom="20" Name="txtResult" >Canvas.Right="30" Canvas.Bottom="20"</TextBox>
</Canvas>
</Window>

همانطور که مي بينيد، مکان هر کنترلي درون کنترل Canvas با خواص پيوست شده ي Left، Top، Right و Bottom مشخص شده است.

شکل نهايي حاصل از اجراي اين کد به صورت زير خواهد بود:

نکته:
دقت داشته باشيد، که در اين حالت، چون سايز کنترل ها پيش فرض بر روي Stretch نيست ( بر خلاف زماني که منترل ها بر روي StackPanel قرار داشتند)، با تغيير محتواي TextBox ها، سايز آن ها نيز تغيير پيدا مي کند.

به عنوام مثال اگر کاربر در دو TextBox بالايي مقادير 10 و 20000 را وارد کند، TextBox ها تغيير اندازه داده و به شکل زير در خواهند آمد:

همچنين اگر مقادير TextBox ها بيش از عرض فعلي آن ها باشد، عرض TextBox ها زياد شده تا بتواند تمامي مقادير را در خود جاي دهد.
براي پيشگيري از تغيير سايز textbox ها، مي توانيد از خواص MaxWidth و MinWidth اين عناصر استفاده کنيد.
براي ثابت نگه داشتن طول textbox مي توانيد خواص MaxWidth و MinWidth را با مقادير يکسان، مقدار دهي کنيد.

در کد زير، که با تغير در کد قبلي به وجود امده است، TextBox بالايي، در اندازه 120 ثابت شده است. اين به اين معني است که با تغيير محتويات داخل TextBox طول TextBox ثابت مي ماند.

<Window x:Class="StackPanel.CanvasContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CanvasContainer" Height="300" Width="300">
<Canvas>
<TextBox Canvas.Left="10" Canvas.Top="10" Name="txtNum1" MaxWidth="120" MinWidth="120">HCanvas.Left="10" Canvas.Top="10"</TextBox>
<TextBox Canvas.Right="30" Canvas.Top="50" Name="txtNum2">Canvas.Right="30" Canvas.Top="50"</TextBox>
<Button Canvas.Left="40" Canvas.Top="90" Name="btnSum" Click="btnSum_Click">Canvas.Left="40" Canvas.Top="90"</Button>
<TextBox Canvas.Right="30" Canvas.Bottom="20" Name="txtResult" >Canvas.Right="30" Canvas.Bottom="20"</TextBox>
</Canvas>
</Window>

نتيجه اجراي حاصل از کد فوق به صورت زير خواهد بود:

همانطور که در شکل فوق مشاهده مي کنيد، تکست باکس بالايي با تغيير مقدار آن به 10 ، تغييري در شول آن صورت نگرفته است.

خاصيت ZIndex

توسط اين خاصيت مي توانيد نحوه چيدمان عناصري را که بر روي هم قرار گرفته اند را مشخص کنيد. هر کنترلي که مقدار ZIndex آن بزگتر باشد، بر روي کنترل هايي که مقدار ZIndex آن ها کوچکتر است قرار خواهد گرفت. به نمونه کد زير دقت کنيد:

<Window x:Class="StackPanel.ZIndexProp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ZIndexProp" Height="300" Width="300">
<Canvas>
<Button Background="Green" Canvas.Left="60" Canvas.Top="24" MinHeight="50" Canvas.ZIndex="0" >My ZIndex Value IS 0</Button>
<Button Background="Red" Canvas.Left="147" Canvas.Top="60" MinHeight="50" Canvas.ZIndex="1">My ZIndex Value IS 1</Button>
<Button Background="Blue" Canvas.Left="129" Canvas.Top="98" MinHeight="50" Canvas.ZIndex="2" >My ZIndex Value IS 2</Button>
<Button Background="Yellow" Canvas.Left="30" Canvas.Top="60" MinHeight="50" Canvas.ZIndex="3" >My ZIndex Value IS 3</Button>
</Canvas>
</Window>

در اين کد که شامل يک کنترل Canvas و چهار کنترل Button بر روي آن مي باشد، دکمه ها داراي خاصيت ZIndex مي باشند. نتيجه اجراي کد فوق رادر شکل زير مشاهده مي کنيد.

همانطور که در شکل فوق نيز مشخص است، دکمه اي که با رنگ زرد مشخص شده است، به دليل اينکه داراي مقدار ZIndex با لاتري نسبت به دکمه هاي ديگر دارد، بر روي تمامي دکمه ها قرار گرفته است.
به دليل مشابهي، دکمه سبز رنگ در زير تمامي دکمه ها قرار گرفته است.

دکمه آبي رنگ داراي مقدار ZIndex برابر با 2 مي باشد. به عمين دليل، قسمتي از آن بالاتر از دکمه قرمز رنگ قرار گرفته است ( چون دکمه قرمز رنگ مقدار ZIndex کتري نسبت به دکمه آبي رنگ دارد) و قسمتي از آن زير دکمه زرد رنگ قرار گرفته است.( به اين دليل که دکمه زرد رنگ داراي خاصيت ZIndex بالاتري نسبت به دکمه آبي رنگ دارد)

کنترل DockPanel

در دات نت 1.x و 2.0 با خاصيتي به نام Dock آشنا شديد. اين خاصيت براي هر کنترلي که تنظيم مي شد ( مي شود)، با عث مي شد (مي شود) که کنترل مورد نظر بر اساس مقداري که براي خاصيت Dock آن تنظيم شد است، به يکي از گوشه هاي کنترل پدر خودش وصل شود. به عنوان مثال اگر کنترلي داراي مقدار Top براي خاصيت Dock باشد، واين کنترل مستقيما بر روي فرم قرار گرفته باشد، اين کنترل به گوشه بالايي فرم متصل مي شود. در نتيجه با تغيير عرض فرم، اين کنترل به صورت اتوماتيک نيز تغيير سايز مي دهد و عرض خودش را با عرض فرم مجددا تنظيم مي کند.از اين خاصيت در برنامه ها، زياد استفاده مي شود، به عنوان مثال کنترل Status Bar که معمولا در پايين فرم، Dock مي شود، ويا منوي برنامه که در گوشه بالايي فرم Dock مي شود از اين نمونه هستند.

کنترل DockPanel نيز عملکري مشابه با عملکر خاصيت Dock دارد. با اين تفاوت که قدرت بسيار بالاتر و امکانات بسيار بيشتري را در اختيار شما قرار مي دهد. هر کنترلي که در کنترل DockPanel قرار بگيرد، خاصيتي به نام Dock به آن پيوست خواهد شد. اين خاصيت داراي چهار مقدار Left، Top، Bottom و Right مي باشد. توسط اين مقادير مي توانيد کنترل هاي خود را در کنترل DockPanel تنظيم نماييد.

به نمونه کد زير دقت کنيد:

<Window x:Class="DockPanel.DockPanelContainer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DockPanelContainer" Height="300" Width="300">
    <DockPanel>
        <Button DockPanel.Dock="Right">"Right"</Button>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
            <TextBlock Margin="3">sample TextBlock</TextBlock>
            <Button HorizontalAlignment="Right" Margin="3">button</Button>
        </StackPanel>
       
        <Menu DockPanel.Dock="Bottom" >
            <MenuItem Header="Item0">
                <MenuItem Header="Item00">
                    <MenuItem Header="Item000"></MenuItem>
                </MenuItem>
                <MenuItem Header="Item01"></MenuItem>
                <MenuItem Header="Item02"></MenuItem>
                <MenuItem Header="Item03"></MenuItem>
            </MenuItem>
            <MenuItem Header="Item1">
                <MenuItem Header="Item10">
                    <MenuItem Header="Item100"></MenuItem>
                </MenuItem>
                <MenuItem Header="Item11"></MenuItem>
                <MenuItem Header="Item12"></MenuItem>
                <MenuItem Header="Item13"></MenuItem>
            </MenuItem>
        </Menu>
        <TextBox TextWrapping="Wrap" MaxWidth="80" DockPanel.Dock="Left">DockPanel.Dock="Left"</TextBox>
        <TextBox TextAlignment="Center" VerticalAlignment="Center">Dock value Is Fill</TextBox>
    </DockPanel>
</Window>

در بالاترين، سطح از اين کنترل ها، کنترل DockPanel قرار گرفته است. پنج کنترل ديگر به عنوان فرزندان مستقيم کنترل DockPanel قرار گرفته اند که بعضي از اين کنترل ها، خود نيز شامل چندين کنترل ديگر مي باشند. تمامي کنترل هاي فرزندف داراي خاصيت پيوست شده Dock مي باشند. به عنوان مثال قطعه کد زير:

<Button DockPanel.Dock="Right">"Right"</Button>

دکمه اي را به عنوان فرزند کنترل DockPanel تعريف مي کند که در سمت راست خودش قرار گرفته است. دستور DockPanel.Dock="Right" باعث مي شود که کنترل، به گوشه سمت راست کنترل DockPanel قرار گيرد.

نتيجه حاص از اجراي کد فوق در شکل زير مشخص شده است:

ترتيب در Dock کردن کنترل ها:

ترتيب تنظيم خاصيت Dock مربوط به کنترل ها در کنترل DockPanel مهم مي باشد. به عنوان مثال دو قعطه کد زير را نظر بگيريد:

<Window x:Class="DockPanel.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <DockPanel>
        <Button Background="Green" DockPanel.Dock="Top">button1</Button>
        <Button Background="Blue" DockPanel.Dock="Left">button2</Button>
        <Button DockPanel.Dock="Right">button3</Button>
        <Button DockPanel.Dock="Bottom">button4</Button>
        <Button >button5</Button>       
    </DockPanel>
</Window>

شکل حاصل از اجراي قطعه کد فوق مشابه زير خواهد بود:

در کد فوق، دکمه اي که با رنگ سبز مشخص شده است، به دليل اينکه قبل از دکمه آبي رنگ تعريف شده است، کل فضاي گوشه بالايي را به خود اختصاص داده است. حال اگر جاي تعريف اين دو دکمه (button1 و button2) را در کد عوض کنيم، يعني داشته باشيم:

<Window x:Class="DockPanel.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <DockPanel>
        <Button Background="Blue" DockPanel.Dock="Left">button2</Button>
        <Button Background="Green" DockPanel.Dock="Top">button1</Button>       
        <Button DockPanel.Dock="Right">button3</Button>
        <Button DockPanel.Dock="Bottom">button4</Button>
        <Button >button5</Button>       
    </DockPanel>
</Window>

نتيجه حاصل مشابه زير خواهد بود:

مقدار Fill در خاصيت Dock

خاصيت Dock از کنترل DockPanel داراي مقدار Fill نمي باشد. در واقع به آن نياز ندارد. دليل اين امر به نحوه چيدمان کنترل ها در کنترل DockPanel مربوط مي شود. کنترل DockPanel همواره سعي بر دادن کل فضاي موجود به کنترل هاي فرزند خودش مي باشد. به عنوان مثال اگر کنترل DockPanel فقط داراي يک کنترل Button باشد، اين دکمه کل فضاي موجود بر روي کنترل DockPanel را به خود اختصاص مي دهد حتي اگر خاصيت Dock مربوط به کنترل را مثلا بر روي Left قرار دهيد..(اگر مقادير عرض و ارتفاع براي کنترل Button تعريف نشده باشد)

حال اگر دکمه ديگري با خاصيت Dock برابر با Right به کنترل DockPanel اضافه کنيد، فضاي موجود بر روي کنترل DockPanel به دوقسمت تقسيم بندي مي شوند. در اين حالت مقدار فضايي که دکمه اول احتياج دارد، در اختيارش قرار داده مي شود و بقيه فضاي موجود به دکمه دوم اختصاص داده مي شود.

اين تقسيم بندي براي کنترل هاي فرزند ديگر ( در صورت وجود) نيز انجام مي شود تا نهايتا کل فضاي موجود بر روي کنترل DockPanel بين کليه کنترل هاي فرزندش تقسيم شود.

خاصيت LastChildFill

ذکر اين نکته ضروري است که تمامي مطالب گفته شده در بخش قبلي (ترتيب در Dock کردن کنترل ها) زماني درست مي باشند که خاصيت LastChildFill از کنترل DockPanel بر روي True تنظيم گردد. اگر اين خاصيت True باشد که مقدار پيش فرض آن نيز True مي باشد، آخرين کنترلي که بر روي کنترل DockPanel قرار مي گيرد، کل فضاي باقي مانده از کنترل DockPanel را به خود اختصاص مي دهد. در غير اين صورت همه کنترل ها به اندازه مقدار فضايي که نياز داشته باشند از کنترل DockPanel گرفته و بقيه فضاي باقي مانده ( اگر موجد باشد) بدون استفاده باقي خواهد ماند.

به عنوان مثال اگر در کد فوق دستور LastChildFill="False" را اضافه کنيم:

DockPanel LastChildFill="False">
        <Button Background="Green" DockPanel.Dock="Top">button1</Button>
        <Button Background="Blue" DockPanel.Dock="Left">button2</Button>
        <Button DockPanel.Dock="Right">button3</Button>
        <Button DockPanel.Dock="Bottom">button4</Button>
        <Button >button5</Button>
    </DockPanel>

نتيجه اجرا به صورت شکل زير خواهد بود:

در شکل فوق، آخرين کنترلي که به کنترل DockPanel اضافه شده است، button5 مي باشد. کنترل DockPanel به اين دکمه به اندازه مورد نيازش ( اندازه اي که بتواند متن داخل دکمه مشخص باشد) فضا مي دهد و بقيه فضاي موجود ( کادر زرد رنگ) بدون استفاده باقي خواهد ماند.

 کنترل WrapPanel

کنترل WrapPanel نيز يکي از کنترل هاي کانتينر مي باشد. اين کنترل در طراحي واسط کاربري شما نقش زيادي نمي تواند بازي کند. در واقع مواردي که از اين کنترل مي توان استفاده کرد محدود و در بعضي از کاربرد هاي خاص به کار مي رود.

کنترل WrapPanel عناصر فرزند خود را به دوصورت مي تواند تراز بندي کنيد. اين امر بستگي به خاصيت Orientation از اين کنترل دارد. اگر اين خاصيت بر روي Horizontal باشد ( حالت پيش فرض horizontal مي باشد)، عناصر به صورت سطري و در داخل اولين سطر از اين کنترل قرار ميگيرند. چنانچه مقدار فضاي مورد نياز براي کنترل هاي فرزند، بيش از فضاي موجود بر روي يک سطر باشد، عناصر فرزند به صورت اتواتيک به سطر بعدي شيفت داده مي شوند. اين عمل آن قدر تکرار مي گردد تا تمامي عناصر بر روي کنترل WrapPanel قرار داده شوند.
به کد زير توجه کنيد:

<Window x:Class="WrapPanel.HorizontalWrapPanel"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="HorizontalWrapPanel" Height="300" Width="300">
 
        <WrapPanel>
            <Button Margin="3" MinWidth="32" MaxWidth="32" MinHeight="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/add-file.png"></ImageBrush>
            </Button.Background>
            </Button>
        <Button Margin="3" MinWidth="32" MaxWidth="32" MinHeight="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/copy.png"></ImageBrush>
            </Button.Background>
        </Button>
        <Button Margin="3" MinWidth="32" MaxWidth="32" MinHeight="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/cut.png"></ImageBrush>
            </Button.Background>
        </Button>
        <Button Height="32" MaxWidth="32" MinHeight="32" MinWidth="32" Width="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/zoom+.png" />
            </Button.Background>
        </Button>
        <Button Height="32" MaxWidth="32" MinHeight="32" MinWidth="32" Width="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/zoom-.png" />
            </Button.Background>
        </Button>
        <Button Height="32" MaxWidth="32" MinHeight="32" MinWidth="32" Width="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/search.png" />
            </Button.Background>
        </Button>
    </WrapPanel>
  
</Window>

اين قطعه کد مربوط به پنجره اي است که يک کنترل WrapPanel به عنوان کنترل کانتينر آن قرار داده شده است. درون اين کنترل، شش دکمه قرار داده شده است که هر يک داراي خواص مربوط به خودش مي باشد. نتيجه حاصل از کد فوق در شکل زير نشان داده شده است:

همانطور که در شکل نيز مشخص است، عناصر روي کنترل WrapPanel به صورت سطري قرار گرفته اند. حال اگر در زمان اجرا، عرض پنجره فوق کم شود، بعضي از عناصر به سطر بعدي در کنترل WrapPanel شيفت داده مي شوند:

حال اگر خاصيت Orientation اين کنترل را بر روي Vertical تنظيم کنيد، عناصر به صورت ستوني تراز مي شوند، ابتدا ستون اول و چنانچه فضاي کافي براي قرار گيري عناصر بر روي ستون اول موجود نباشد، بقيه عناصر به ستون بعدي شيفت داده مي شوند.

براي اعمال اين تغيير کافيست تگ آغازين کنترل WrapPanel را به صورت زير تغيير دهيد:

<WrapPanel Orientation="Vertical">
        <Button Margin="3" MinWidth="32" MaxWidth="32" MinHeight="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/add-file.png"></ImageBrush>
            </Button.Background>
        </Button>
        <Button Margin="3" MinWidth="32" MaxWidth="32" MinHeight="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/copy.png"></ImageBrush>
            </Button.Background>
        </Button>
        <Button Margin="3" MinWidth="32" MaxWidth="32" MinHeight="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/cut.png"></ImageBrush>
            </Button.Background>
        </Button>
        <Button Height="32" MaxWidth="32" MinHeight="32" MinWidth="32" Width="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/zoom+.png" />
            </Button.Background>
        </Button>
        <Button Height="32" MaxWidth="32" MinHeight="32" MinWidth="32" Width="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/zoom-.png" />
            </Button.Background>
        </Button>
        <Button Height="32" MaxWidth="32" MinHeight="32" MinWidth="32" Width="32">
            <Button.Background>
                <ImageBrush ImageSource="./Images/search.png" />
            </Button.Background>
        </Button>
    </WrapPanel>

دو شکل زير نمايي از اجراي کد قبل را با تغييري که در تگ آغازين کنترل WrapPanel داده شده است را نشان مي دهد.

يکي از کاربر هايي که از WrapPanel ها مي تواند در آن بهره جست، ايجاد کنترل هايي مانند Tool strip مي باشد. (البته ابزار هاي مجزايي براي toolbar ها نيز موجود است).

نکته:
خاصيت ديگري که اکثر کنترل هاي WPF ، از جمله کنترل WrapPanel دارامي باشند، خاصيت Flow Direction مي باشد. اين خاصيت داراي دو مقدار Left To Right و Right To Left مي باشد که مقدار پيش فرض آن Left To Right مي باشد. اين خاصيت جهت تراز بندي کنترل ها را نشان مي دهد. بري برخي از زبان ها از جمله زبان فارسي، اين خاصيت بسيار پر کاربرد مي باشد.

به عنوان مثال مي توانيد با اضافه کردن دستور

FlowDirection="RightToLeft"

يک تگ آغازين کنترل WrapPanel ، ستون آغازين را براي قرار گيري کنترل ها را از سمت راست به چپ تعيين کنيد.

کنترل UniformGrid

اين کنترل ظاهري شبيه به عنصر Gird (که در بخش بعدي توضيح داده خواهد شد) دارد. اين کنترل به تعدادي سطر و ستون با اندازه هاي يکسان تقسيم بندي مي شود. عناصر فرزند اين کنترل مي توانند در هريک از اين سلول ها قرار بگيرند.
سلول هاي حاصل از ايجاد اين کنتنرل، همگي داراي اندازه هاي يکسان مي باشند.

نحوه استفاده از اين کنترل به صورت زير مي باشد:

<UniformGrid Roes="5" Columns="5">
.
.
.
</UniFormGrid>

که شامل تعريف خود کنترل، تعداد سطر ها و تعداد ستون هاي آن مي باشد.

اين کنترل براي موارد خاصي به کار برده مي شود و به ندرت در طراحي واسط هاي برنامه شما به کار برده مي شود. به عنوان مثال شکل زير يک جدول ضرب 5*5 را نشان مي دهد.

<Window x:Class="UniformGrid.UniformGridContainer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="UniformGridContainer" Height="200" Width="200">
    <Window.Resources>
        <SolidColorBrush x:Key="btnBack" Color="Coral"></SolidColorBrush>
    </Window.Resources>
    <UniformGrid Rows="6" Columns="6">
        <Button  Background="Red" >*</Button>
        <Button  Background="{StaticResource btnBack}">1</Button>
        <Button Background="{StaticResource btnBack}">2</Button>
        <Button Background="{StaticResource btnBack}">3</Button>
        <Button Background="{StaticResource btnBack}">4</Button>
        <Button Background="{StaticResource btnBack}">5</Button>
        <Button Background="{StaticResource btnBack}">1</Button>
        <Button >1</Button>
        <Button >2</Button>
        <Button >3</Button>
        <Button >4</Button>
        <Button >5</Button>
        <Button Background="{StaticResource btnBack}">2</Button>
        <Button >2</Button>
        <Button >4</Button>
        <Button >6</Button>
        <Button >8</Button>
        <Button >10</Button>
        <Button Background="{StaticResource btnBack}">3</Button>
        <Button >3</Button>
        <Button >6</Button>
        <Button >9</Button>
        <Button >12</Button>
        <Button >15</Button>
        <Button Background="{StaticResource btnBack}" >4</Button>
        <Button >4</Button>
        <Button >8</Button>
        <Button >12</Button>
        <Button >16</Button>
        <Button >20</Button>
        <Button  Background="{StaticResource btnBack}">5</Button>
        <Button >5</Button>
        <Button >10</Button>
        <Button >15</Button>
        <Button >20</Button>
        <Button >25</Button>
    </UniformGrid>
</Window>

نکته:
در اين کنترل، صراحتا نمي توانيد مشخص کنيد که کدام کنترل در چه سلولي قرار بگيرد. در واقع سلول هر کنترل بر اساس ترتيبي که آن کنترل در کنترل هاي فرزند کنترل UniformGrid دارد، مشخص مي شود.

سورس برنامه

  کیفیت مقاله ارائه شده از نظر شما   
برای دادن رتبه به این مقاله می بایست Login کرده باشید.
  درباره نویسنده
مهدی کیانی
همه مقاله های نوشته شده توسط این کاربر (۴)
 
  پیام جدید
هیچ سؤال یا نظری برای این موضوع فرستاده نشده است.

 عنوان فرستنده تاریخ

Copyright © 2006 - 2016 All Rights Reserved.
Please direct your questions or comments to