کنترل Grid

در بین انواع مختلف پنل ها، Grid یکی از پیچیده‌ترین و پرکاربردترین آن‌هاست. هر Grid می‌تواند شامل تعدادی سطر و ستون باشد و شما می‌توانید ارتفاع سطرها و عرض ستون‌ها را تعیین کنید. به مثال زیر توجه کنید:

<Grid>
    <Button>Button 1</Button>
    <Button>Button 2</Button>
</Grid>

زمانی که این برنامه را اجرا کنید خروجی زیر را نمایش می‌دهد:

همانطور که مشاهده می‌کنید، ما فقط می‌توانیم آخرین کنترلی که در Grid قرار گرفته را، مشاهده کنیم. این موضوع شاید در بیشتر مواقع برای ما مطلوب نباشد. برای رفع این مشکل از ColumnDefinitions و RowDefinitions استفاده می‌کنیم. به مثال زیر توجه کنید:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
        
    <Button>                Button 1</Button>
    <Button Grid.Column="1">Button 2</Button>
</Grid>

زمانی که این برنامه را اجرا کنید، خروجی زیر را نمایش می‌دهد:

ما در این مثال با استفاده از تکه کد زیر دو ستون را داخل Grid ایجاد کردیم:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

همانطور که پیش‌تر نیز گفته شد، ما می‌توانیم برای ستون‌هایمان یک عرض (Width) و برای سطرهایمان یک ارتفاع (Height) را تعیین کنیم. توجه داشته باشید که، امکان تعریف ارتفاع برای یک ستون و همچنین عرض برای یک سطر وجود ندارد و اگر در این مثال به جای Width از Height استفاده کنید، با خطا رو به رو می‌شوید. شما ابتدا باید تعداد سطرها و ستون‌هایی که می‌خواهید را تعیین کنید و در ادامه مکان کنترل‌های مورد نظر خود را تعیین کنید. در این مثال برای اینکه عرض ستون‌هایمان را یکسان در نظر بگیرد، مقابل Width مقدار “*” را قرار دادیم. در مورد این مقدار جلوتر بیشتر صحبت خواهیم کرد. در ادامه دو دکمه را به صورت زیر تعریف کردیم:

<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>

حال باید مشخص کنیم هر کدام از این این دکمه‌ها در کدام ستون قرار بگیرند. هر کدام از ستون‌هایی که در این Grid تعریف کردیم دارای یک اندیس هستند که، ستون اول از سمت چپ دارای اندیس صفر، ستون دوم از سمت چپ دارای اندیس یک و … می‌باشد. اگر شما کنترلی را تعریف کنید و مشخص نکنید که در کدام ستون قرار بگیرد، به صورت پیش فرص اندیس صفر را به آن اختصاص می‌دهد. در این مثال برای Button 2 اندیس 1 و برای Button 1 اندیسی در نظر نگرفتیم. بنابراین Button 1 در ستون صفرم و Button 2 در ستون یکم قرار می‌گیرد. حال دو دکمه دیگر را نیز به برنامه خود اضافه می‌کنیم:

<Button>                Button 1</Button>
<Button>                Button 3</Button>
<Button>                Button 4</Button>
<Button Grid.Column="1">Button 2</Button>

اگر این برنامه را اجرا کنیم خروجی زیر را به ما نشان می‌دهد:

ما در این مثال برای سه دکمه اول اندیسی را در نظر نگرفتیم، بنابراین به صورت خودکار برای هر سه تای آن‌ها اندیس صفر را در نظر می‌گیرد و از آنجایی که اگر چندین کنترل را در یک ستون قرار دهیم فقط آخرین آن‌ها نشان داده می‌شود، بنابراین فقط Button 2 را می‌توانیم مشاهده کنیم. حال به مثال زیر توجه کنید:

<Button VerticalAlignment="Top" HorizontalAlignment="Center">Button 1</Button>
<Button VerticalAlignment="Center">                          Button 3</Button>
<Button VerticalAlignment="Bottom">                          Button 4</Button>
<Button Grid.Column="1">                                     Button 2</Button>

حال اگر این برنامه را اجرا کنیم خروجی زیر را نشان می‌دهد:

به صورت پیش فرض مقدار VerticalAlignment و HorizontalAlignment برابر با Stretch در نظر گرفته می‌شود و همین دلیل است که کنترل‌های ما تمام فضای ستونی که به آن‌ها اختصاص دادیم را پر می‌کنند. اما شما می‌توانید با تغییر مقدار این خاصیت‌ها نحوه چینش عناصر در صفحه را کنترل کنید. در این مثال برای سه دکمه اول اندیسی را برای ستونشان در نظر نگرفتیم، بنابراین هر سه دکمه در ستون صفر قرار می‌گیرند، ولی با استفاده از خاصیت‌های VerticalAlignment و HorizontalAlignment، به گونه‌ای کنترل‌ها را در صفحه قرار دادیم تا همپوشانی نداشته باشند.

سطر و ستون‌ها در h3

در بخش قبل شما به صورت مقدماتی با کنترل Grid آشنا شدید. حال در این بخش می‌خواهیم در مورد نحوه چینش سطر و ستون‌ها در یک Grid بیشتر صحبت کنیم. برای شروع به مثال زیر توجه کنید:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*" />
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
    </Grid.ColumnDefinitions>
        
    <Grid.RowDefinitions> 
        <RowDefinition Height="2*" />
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions> 
        
    <Button>                Button 1</Button>
    <Button Grid.Column="1">Button 2</Button>
    <Button Grid.Column="2">Button 3</Button>

    <Button Grid.Row="1">                Button 4</Button>
    <Button Grid.Row="1" Grid.Column="1">Button 5</Button>
    <Button Grid.Row="1" Grid.Column="2">Button 6</Button>
        
    <Button Grid.Row="2">                Button 7</Button>
    <Button Grid.Row="2" Grid.Column="1">Button 8</Button>
    <Button Grid.Row="2" Grid.Column="2">Button 9</Button>
</Grid>

زمانی که این برنامه را اجرا کنیم خروجی زیر را نشان می‌دهد:

در این مثال با استفاده از Grid.ColumnDefinitions و Grid.RowDefinitions سه سطر و سه ستون را تعریف کرده‌ایم. همانطور که در بخش قبلی نیز گفته شد، شما می‌توانید برای ستون‌ها یک عرض (Width) و برای سطرها یک ارتفاع (Height) تعیین کنید. به صورت کلی سه استراتژی برای تعیین سایز در Grid وجود دارد که عبارتند از:
1- سایز ثابت: در این حالت شما یک عدد را به صورت ثابت برای سایز سطرها و ستون‌های خود در Grid در نظر می‌گیرید. به مثال زیر توجه کنید:

 <Grid.ColumnDefinitions>
    <ColumnDefinition Width="90" />
    <ColumnDefinition Width="90" />
    <ColumnDefinition Width="90" />
</Grid.ColumnDefinitions>
    
<Grid.RowDefinitions> 
    <RowDefinition Height="80" />
    <RowDefinition Height="80" />
    <RowDefinition Height="80" />
</Grid.RowDefinitions> 

زمانی که این برنامه را اجرا کنیم خروجی زیر را نشان می‌دهد:

در این مثال برای ستون‌ها عرض ثابت 90 پیکسل و برای سطرها نیز ارتفاع ثابت 80 پیکسل را در نظر گرفتیم. به این ترتیب با تغییر سایز صفحه، عرض و ارتفاع ما ثابت باقی می‌ماند. این استراتژی به دلیل انعطاف پذیری کمی که در اختیار ما قرار می‌دهد معمولاً توصیه نمی‌شود.
2- سایز خودکار: در این حالت هر سطر و ستون دقیقاً همان فضایی را اشغال می‌کند که نیاز دارد و نه بیشتر. به مثال زیر توجه کنید:

 <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions> 
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
</Grid.RowDefinitions> 

زمانی که این برنامه را اجرا کنیم خروجی زیر را نشان می‌دهد:

برای اینکه سایز سطر و ستون‌های ما به صورت خودکار در نظر گرفته شود از مقدار Auto استفاده می‌کنیم. همانطور که در تصویر بالا نیز مشاهده می‌کنید، فضایی که به هر دکمه اختصاص پیدا می‌کند، به اندازه‌ای است که بتواند متن داخلش را به درستی نمایش دهد.
3- سایز متناسب: در این حالت شما می‌توانید فضای اختصاص یافته به سطر و ستون‌ها را، به نسبت دلخواه تعیین کنید. همچنین اگر سایز صفحه تغییر کند، سایز Grid هم به تناسب تغییر می‌کند. به مثال زیر توجه کنید:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="2*" />
    <ColumnDefinition Width="1*" />
    <ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions> 
    <RowDefinition Height="2*" />
    <RowDefinition Height="1*" />
    <RowDefinition Height="1*" />
</Grid.RowDefinitions> 

این همان مثالی است که در ابتدای این بخش مشاهده کردید. حال می‌خواهیم دقیق‌تر آن را مورد بررسی قرار دهیم. برای مثال عرض ستون اول را *2 و عرض ستون دوم و سوم را *1 در نظر گرفتیم که بدین ترتیب عرضی که به ستون اول اختصاص پیدا می‌کند، دو برابر عرضی است که به ستون دوم و سوم اختصاص پیدا می‌کند. شما به جای *1 می‌توانید * خالی نیز قرار دهید و همچنین نسبت‌ها نیز می‌توانند اعداد اعشاری نیز باشند.

ترکیب استراتژی‌های مختلف تعیین سایز Grid

تا اینجا شما با سه استراتژی تعیین سایز در Grid آشنا شدید. حال می‌خواهیم ترکیب استراتژی‌های مختلف را با یک دیگر مورد بررسی قرار دهیم. به مثال زیر توجه کنید:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="100" />
    </Grid.ColumnDefinitions>
            
    <Button>                Button 1                </Button>
    <Button Grid.Column="1">Button 2 with long text </Button>
    <Button Grid.Column="2">Button 3                </Button>
</Grid>

زمانی که این برنامه را اجرا کنیم خروجی زیر را نشان می‌دهد:

در این مثال ما سه ستون را در Grid خود ایجاد کردیم. عرض ستون اول را *، عرض ستون دوم را Auto و عرض ستون سوم را مقدار ثابت 100 پیکسل در نظر گرفتیم. بنابراین عرض دکمه سوم به صورت ثابت 100 پیکسل، عرض دکمه دوم به صورت خودکار و متناسب با اندازه متنی که داخل آن نوشته شده و عرض دکمه اول نیز به صورت متغیر در نظر گرفته می‌شود. نکته ای که در این مثال وجود دارد این است که، شما اگر سایز پنجره را در زمان اجرا تغییر دهید، عرض دکمه دوم و سوم تغییر نمی‌کند ولی دکمه اول فضای باقیمانده را به خود اختصاص می‌دهد که در تصویر زیر نیز مشخص است:

از این تکنیک می‌توانید در طراحی فرم‌های محاوره‌ای استفاده کنید. برای مثال یک فرم تماس با ما را در نظر بگیرید که شامل سه فیلد نام، ایمیل و توضیحات می‌باشد. شما می‌توانید سایز فیلد نام و ایمیل را به صورت ثابت در نظر بگیرید ولی سایز فیلد توضیحات را با استفاده از * به صورت متغیر در نظر بگیرید تا کاربر بتواند سایز آن را به طور دلخواه تعیین کند.

Spanning در Grid

در یک Grid به صورت پیش فرض، هر کنترل داخل یک سلول قرار می‌گیرید اما شما می‌توانید با استفاده از خاصیت‌های ColumnSpan و RowSpan بیش از یک سلول را پوشش (Span) دهید. به مثال زیر توجه کنید:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
    </Grid.ColumnDefinitions>
        
    <Grid.RowDefinitions> 
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions> 
        
    <Button>                                 Button 1</Button>
    <Button Grid.Column="1">                 Button 2</Button>
    <Button Grid.Row="1" Grid.ColumnSpan="2">Button 3</Button>
</Grid>

زمانی که این برنامه را اجرا کنید خروجی زیر را نشان می‌دهد:

در این مثال ما دو سطر و دو ستون را تعریف کردیم که در مجموع 4 سلول در اختیار داریم. در دکمه Button 1 اندیسی را برای مشخص کردن سطر و ستون آن در نظر نگرفتیم، بنابراین آن را در سطر صفر و ستون صفر قرار می‌دهد. در دکمه Button 2 با استفاده از خاصیت Grid.Column فقط اندیس ستون را برابر با یک قرار دادیم، بنابراین آن را در سطر صفر و ستون یک قرار می‌دهد و در نهایت در دکمه Button 3 اندیس سطر را برابر با یک قرار دادیم. اگر خاصیت Grid.ColumnSpan را در نظر نگیریم این دکمه را در سطر یک و ستون صفر قرار می‌گیرد که خروجی آن به شکل زیر است:

حال با استفاده از خاصیت Grid.ColumnSpan و مقدار 2 برنامه را مجبور می‌کنیم تا در سطری که (Grid.Row=”2″) دکمه ما در آن قرار دارد، دو سلول را به آن اختصاص دهد. در تصویر بالا شماره اندیس سطر و ستون هر دکمه را زیر نام آن مشخص کردیم. برای مثال 0,1 به این معنی است که دکمه Button2 در سطر صفر و ستون یک قرار دارد. برای درک بهتر به مثال زیر توجه کنید:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
        
    <Grid.RowDefinitions> 
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions> 
        
    <Button Grid.ColumnSpan="2">Button 1</Button>
    <Button Grid.Column="3">    Button 2</Button>
    <Button Grid.Row="1">       Button 3</Button>
    <Button Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2">Button 4</Button>
    <Button Grid.Column="0" Grid.Row="2">Button 5</Button>
</Grid>

زمانی که این برنامه را اجرا کنیم خروجی زیر را نشان می‌دهد:

در این برنامه سه سطر و سه ستون را ایجاد کردیم که در مجموع 9 سلول را در اختیار داریم. نحوه تحلیل مکان هر دکمه مانند مثال قبل است اما برای نمونه می‌خواهیم مکان دکمه Button 4 را بررسی کنیم. در دکمه Button 4 اندیس سطر و ستون را با استفاده از خاصیت‌های Grid.Column و Grid.Row برابر با یک در نظر گرفتیم و اگر خاصیت‌های Grid.RowSpan و Grid.ColumnSpan را در نظر نگیریم این دکمه در سطر یک و ستون یک قرار می‌گیرد که خروجی آن به شکل زیر است:

حال با استفاده از خاصیت‌های Grid.RowSpan و Grid.ColumnSpan با مقدار 2، برنامه را مجبور می‌کنیم تا در سطر و ستونی که دکمه ما در آن قرار دارد، دو سلول را به سطر و دو سلول را به ستون اختصاص دهد که در مجموع 4 سلول را پوشش می‌دهد.