آموزش WPF

آموزش WPF با زبان xaml و VB.Net و C#

آموزش WPF

آموزش WPF با زبان xaml و VB.Net و C#

استیل Style یا سبک در WPF

ترجمه ۴ صفحه از صفحات ۳۵۳ تا ۳۵۶ از کتاب Pro WPF With VB 2008  

در قسمت Resources شما درباره سیستم Resource در WPF یاد گرفتید ، که به شما اجازه تعریف شی در یک مکان و استفاده دوباره آن در تمامی پروژه را می دهد.اگرچه شما می توانید از Resources برای ذخیره ی اشیا نامحدود و متنوع استفاده کنید،یکی از بیشترین چیزهای مشترک که شما می توانید استفاده کنید نگه داشتن استیلها (Style) می باشد.

یک استیل (Style) مجموعه ای از مقادیر خاصیتهاست که می توانند به یک المان اضافه شود می باشد. سیستم استیل (Style) WPF نقشی شبیه به CSS استاندارد در زبان کدHTML را ایفا می کند. مشابه CSS ، استیلها (Styles) در WPF به شما اجازه تعریف مجموعه ای مشترک از مشخصات قالب بندی (فرمت بندی) و اضافه کردن آنها به کلیه برنامه تان (Application) برای تضمین هماهنگی را می دهد. و در نتیجه با  CSS، WPF style می توان بطور خودکار کار کرد، هدف مشخص انواع المان ، و بواسطه المان درختی آبشاری. به هر حال،استیلهای WPF خیلی قدرتمند هستند زیرا با آن می توانند هر خاصیت وابسته را  مقداردهی کنید. این بدین معنی است شما می توانید از آنها  برای استاندارد کردن ویژگیهایی که قالب بندی(فرمت بندی) ندارند استفاده کنید ، به عنوان مثال رفتار یک کنترل. استیلهای WPF همچنین از تریگرها (trigger) نیز پشتیبانی کرده ، که  به شما اجازه  تعویض استیل یک کنترل را وقتی خاصیت دیگری تغییر کرد را می دهد (شما در همین درس خواهید دید)، و آنها می تواند استفاده کند  از templateها ( الگوها) برای تعریف مجدد ظاهر داخلی (توکار) یک کنترل (در درس 15 خواهید دید). این بار شما چگونگی استفاده از استیلها (Styles) را دارید یاد می گیرید، و قطعاٌ  خواهید توانست آنها را در همه برنامه هایتان WPF قرار بدهید.

اساس استیل(Style)

شما بطوریکه در درس قبلی یاد گرفته اید، resource ها مزایای  چند کلید( key ) ، به انضمام کدساده و  نگهدای برنامه ها را ارائه می کند. پس چطور استیلها  (Styles) به تصویر اضافه می شوند؟
برای فهمیدن اینکه به چه دلیل قالبها (
Styles) در برنامه بکار می روند ،  مثالی ساده کمک به درک بهتر مطلب می کند.  تصور کنید شما نیاز به استاندارد نمودن فونت استفاده شده در یک پنجره را دارید.ساده ترین روش برای تعیین خواص فونت درون پنجره این است که خواصی که در کلاس کنترل هستند را تعریف کیند، شامل نوع فونت (FontFamily)، سایز فونت (FontSize)، پهنای فونت (FontWeight) (برای Bold)، سبک فونت (FontStyle) (برای Italics کج) و منبساط کردن فونت (FontStretch) (برای فشرده سازی یا منبسط کردن گوناگون).با این تفاسیر، خصیصه وراثت مقدار خاصیت،زمانی که شما این خواص را در سطح پنجره تعیین می کنید، تمام عناصر داخل پنجره می خواهند مقادیر مشابه ای داشته باشند، مگر آنکه آنها را بکل بی خیال شوید.

نکته: یکی از چندین ویژگی انتخابی در مقدار خاصیت وراثتی

مقدار خاصیت وراثتی یکی از چندین ویژگی انتخابی  آن ، خواص وابستگی (dependency properties) که می تواند فراهم کند می باشد. خواص وابستگی (dependency properties) در فصل 6 توضیح داده شده اند.

اکنون وضعیت متفاوتی را بررسی می کنیم ، که در آن شما می خواهید فونتی که فقط در بخشی از رابط کاربری استفاده شده نگه دارید. اگر شما بتوانید آن عناصر را در یک کانتینر (container)خاص (برای مثال، اگر همه آنها در یک Grid یا StackPanel باشند)نگه دارید،در نتیجه شما می توانید از روشی مشابه برای تعیین خواص فونت در کانتینر((containerاستفاده کنید. هرچند این گونه عمل کردن معمولا به این آسانی نیست.برای مثال ، شاید شما بخواهید برای همه دکمه ها یک سبک حروف ثابت و اندازه متن مستقل از تنظیمات فونتهایی که در دیگر عناصر استفاده شده اند، بدهید.در این موارد شما به راهی برای تعریف این اطلاعات در یک محل و استفاده مجدد از آنها در هر جا که بکار رفته، نیاز دارید.یک راه حل شما گذاشتن در resourceهاست، اما قدری ناشیانه است. زیرا در WPF شی فونت وجود ندارد(فقط مجموعه ای از فونت مربوط به خواص)، شما گیر چندتا تعریف مربوط به resourceها می شوید،مثال زیر این را نشان می دهد:

    <Window.Resources>

        <FontFamily x:Key="ButtonFontFamily">Times New Roman</FontFamily>

        <sys:Double x:Key="ButtonFontSize">18

            </sys:Double>

            <FontWeight x:Key="ButtonFontWeight">Bold</FontWeight>

   </Window.Resources>

این قطعه سه تا resource به صفحه اضافه می کند:یک شی از خانواده فونت(FontFamily) با نام فونت که شما می خواهید استفاده کنید، یک دابل (Double) که عدد 18 را ذخیره می کند و یک شمارنده که مقدار FontWeight.Bold را نگه می دارد. فرض شده که شما در .NET فضای نام system را به فضای نام XML با پیشوند sys ترسیم کردیده اید ، مثال اینجا نشان می دهد.

<Window xmlns:sys="clr-namespace:System;assembly=mscorlib"   >

نکته :

هنگام تنظیم خواصی که در resource استفاده می شود، این مهم است که دقیقاٌ  با نوع داده مطابقت داشته باشد.WPF از تبدیل نوع همانند زمانیکه شما مقدار صفت رو مستقیم تعیین می کنید استفاده نخواهد کرد. به عنوان مثال، شما برای تنظیم ویژگی FontFamily در یک عنصر ، از متن " Times New Roman" می توانید استفاده کنید زیرا FontFamilyConverter یک شی FontFamily که شما نیاز دارید را خلق خواهد کرد. بر هر حال همان جادو(تبدیل خودکار) هر وقت که شما سعی به تعیین خاصیت FontFamily که در یک رشتهresource استفاده کرده اید این حالت اتفاق نمی افتد.و تجزیه کننده XAML یک استثنا (خطا) ایجاد می کند.

هنگامی که شما نیاز به تعریف resourceها را دارید،قدم بعدی در واقع استفاده از resourceها در یک عنصر (Element) است. از آنجا که resourceها در طور حیاتشان در برنامه هرگز تغییر نمی کنند، استفاده عاقلانه resourceهای ثابت (Static Resource) در اینجا نشان داده شده است

    <Button Padding="5" Margin="5" Name="cmd"

FontFamily="{StaticResource ButtonFontFamily}"

FontWeight="{StaticResource ButtonFontWeight}"

FontSize="{StaticResource ButtonFontSize}"

>A Customized Button

    </Button>

این مثال عمل می کند، و جزئیات فونت (به اصطلاح "اعداد جادویی") خارج از کدشما را منتقل می کند ، با این حال دو مشکل جدید وجود دارد:

·         نشانه  روشنی از 3 resource وابسته وجود ندارد (متفاوت از resource نامهای مشابه). این نگهداری نرم افزار را پیچیده می کند. مخصوصا اگر در این مشکل  شما نیاز به تنظیم خواص فونت و یا اگر شما تصمیم به پشتیبانی از تنظیمات مختلف فونت برای انواع عناصر کرده باشد.

·         کد(markup) شما نیاز به استفاده از resourceهایتان به صورت کاملا طولانی دارد. در واقع،  این چیز مختصرتری نسبت  روش جایگزینی است(تعریف خواص فونت به طور مستقیم در عنصر).

شما برای بهبود موضوع اول می توانید یک کلاس تعریف کنید (مثلاٌ FontSetting) آن بسته ای است که همه جزئیات فونت با همدیگر دارد.بعد از آن شما می توانید یک شی FontSetiing  به عنوان یک resource ایجاد کنید و از خواص مختلف اش در کد تان(Markup) استفاده کنید.با این حال، این هنوز کد(Markup) طولانی را برای شما باقی می گذارد و برای ساختن کار خوب کار زیادی می گیرد.

استیل (Style)ها یک راه حل کامل را ارائه می کنند.شما می توانید تنها یک اسیتل (Style) را برای پوششش دادن به همه خواص که شما می خواهید تعیین شوند، تعریف کنید.بدین نحوه: 

    <Window.Resources>

        <Style x:Key="BigFontButtonStyle">

            <Setter Property="Control.FontFamily" Value="Times New Roman" />

            <Setter Property="Control.FontSize" Value="18" />

            <Setter Property="Control.FontWeight" Value="Bold" />

        </Style>

    </Window.Resources>

این کد تنها یک شی   System.Windows.Style در resource ایجاد می کند. این شی استیل (Style) در مجموعه ی Setter خود  3 شی Setter نگه داری میکند، یکی به ازای هر خاصیتی که شما بخواهید آن را تعیین کنید. هر شی Setter دارای  Property  است که در آن نام خاصیت قرار می گیرد و مقدار Vaule به خاصیتی با همان نام اعمال می شود.شبیه به resourceها ، استیل (Style) یک نام کلید(Key) دارد پس شما می توانید آن مجموعه که مورد نیاز است را بیرون بکشید. دراین قالب، نام کلید(key) ، BigFontButtonStyle است.(تطبق قرار داد ، نامهای کلید (Key) برای استیل (Style) معمولا با “Style” پایان می یابد.)

هر عنصر WPF می تواند از تنها یک استیل (Style) ( یا هیچ استیلی) استفاده کند. عنصر درون  استیل (Style) کاملا به خاصیت درون عنصر (Element) متصل می شود. (که در کلاس پایه FrameworkElement تعریف شده است).

برای مثال، برای پیکربندی یک دکمه ،برای استفاده از استیلی (Style) که قبلا ایجاد شده است، شما استیل (Style) را همانند زیر به resource متصل کنید:

    <Button Padding="5" Margin="5" Name="cmd"

Style="{StaticResource BigFontButtonStyle}"

>A Customized Button

    </Button>

البته، شما همچنین می توانید از طریق برنامه نویسی استیل (Style) را قرار بدهید. همه شما نیاز به بیرون کشیدن استیل (Style) از نزدیکترین مجموعه resourceهای با استفاده از متد آشنا FindResource() دارید. با کد موجود شما از استیل شی دکمه  با نام cmd استفاده خواهید کرد.

cmdButton.Style = CType(cmd.FindResource("BigFontButtonStyle"), Style)

شکل 12-1 یک صفحه را با دو Button وکه از BigFontButtonStyle استفاده کرده است نشان می دهد.

 

شکل 12-1 . Buttonها با استفاده مجدد از یک استیل (Style) تنظیم شده اند.

نکته

استیل (Style) ها در ظهور اولیه یک عنصر (Element) نشانده می شوند، اما شما برای نشاندن و باز نویسی ویژگیهای آن آزادید. بعنوان مثال، اگر شما استیل (Style) BigFontButtonStyle را اضافه کنید وخاصیت  FontSize را صریحاٌ قرار دهید، سایز فونت ، تحت الشعاع استیل (Style) در تگ دکمه Button تنظیم می شود. تصور کنید، شما نمی خواهید به این رفتار استناد کنید ، در عوض ، شما با خلق استیل (Style) های بیشتر می تواند بسیاری از جزئیاتی که در سطح استیل (Style)هست قرار دهید.این کار انعطاف بیشتری برای تنظیم رابط کاربریتان را در آینده با حداقل شکست میسر می کند.

سیستم استیل (Style) مزایا زیادی را می افزایند. نه تنها به شما اجازه ایجاد گروهی از تنظیمات که به وضوح وابسته هستند می دهد، همچنین خطوط جریان کد نویسی تان بواسطه ترکیبش برای بکار بردن تنظیمات آسانتر است.بهتر از همه ، شما  می توانید یک استیل (Style) را بدون نگرانی در مورد مجموعه خواصش بکار ببرید.در مثال قبلی تنظیمات فونت در استیلی (Style) به نام BigFontButtonStyle سازماندهی شده بود. اگر شما بعدا تصمیم به فونت بزرگ برای دکمه هاتون داشتید در نتیجه به Padding و Margin با فاصله بیشتر نیاز دارید، شما می توانید در setterها   خواص Margin و Padding را به خوبی اضافه کنید. همه دکمه ها که از استیل (Style) استفاده می کنند تنظیمات جدید استیل (Style) را به طور خود کار دریافت می کنند.

مجموعه Setterها بیشترین خاصیت در کلاس استیل (Style) را دارند. اما روی هم رفته 5 خواص کلید (key) وجود دارد ، که در این درس ملاحظه خواهید کرد. جدول 12-1 یک نمایش سریعی را نشان می دهد.

کشیدن مربع و مستطیل با کنترل Rectangle

 اشکال در WPF فقط می توانند درون کانتینرها یا کنترلهای دیگری که از Panel مشتق شده اند  قرار بگیرند.   

کشیدن مربع و مستطیل با کنترل  Rectangle

برای کشیدن مربع از این کنترل استفاده می شود. برای کشیدن مربع باید دو خاصیت  Height (عرض) و Width (طول) مربع را مشخص کنید. و همچنین اگر مربع تو پر باشد باید خاصیت Fill را با رنگ مورد نظر مقدار دهی کنید و اگر می خواهید حاشیه نیز داشته باشد خاصیت strokeThickness را با رنگ دلخواه مقدار دهی کنید.

به شکل زیر توجه کنید 

  <StackPanel>

       <Rectangle Margin="10" StrokeThickness="3"  Stroke="Black" Fill="Yellow" Height="40" Width="150" />

        <Rectangle Margin="10" StrokeThickness="10" Stroke="Blue" Fill="Purple" Height="40" Width="150" />       

        <Rectangle Margin="10" StrokeThickness="1"  Stroke="Cyan" Fill="Pink" Height="40" Width="150" />

        <Rectangle Margin="10" StrokeThickness="5"  Stroke="Red" Fill="Gray" Height="40" Width="150" />

        <Rectangle Margin="10" StrokeThickness="0"  Stroke="Green" Fill="Black" Height="40" Width="150" />

    </StackPanel>

مثال در VB.Net

        Dim rec As New Rectangle

        Dim colorRec As New SolidColorBrush

        rec.Height = 50

        rec.Width = 100

        colorRec.Color = Colors.Blue

        rec.Fill = colorRec

  grid1.Children.Add(rec)

کشیدن چند ضلعی با کنترل Polygan

 اشکال در WPF فقط می توانند درون کانتینرها یا کنترلهای دیگری که از Panel مشتق شده اند  قرار بگیرند. 

کشیدن چند ضلعی  Polygon

برای کشیدن چند ضلعی از کنترل Polygon استفاده می شودکه همانند کنترل Polyline دارای خاصیت آرایه ای به نام Points برای نشان دادن نقاطی که قرار است خطوط بین آنها کشیده شود ،دارد. تفاوت این کنترل (Polygon) با کنترل Polyline در این است که از Polygon برای کشیدن اشکال چند ضلعی به صورت بسته استفاده می شود.(یعنی بطور خودکار خطی از انتها به ابتدا کشیده می شود).

نحوه دادن اطلاعات نقاط به آرایه Points بدین صورت است که به ازای هر X,Y یک نقطه ایجاد می شود و برای جدا کردن نقاط از فاصله استفاده کنید

<Canvas Height="300" Width="300">

<!--  Polyline Left , Top -->  

    <Polygon Points="10,130 60,30 110,130" Fill="Blue" />

   

<!-- Polyline Right , Top -->

    <Polygon Points="10,110 110,110 110,10"

        Fill="Blue"

        Canvas.Left="160" Canvas.Top="20" />

   

<!-- Polyline Left , Bottom -->

    <Polygon Points="0,0 50,-50 100,-50 150,0 100,50 50,50"

        Fill="Blue" Stroke="Black" StrokeThickness="4"

    Canvas.Top="220" Canvas.Left="10" />

<!-- Polyline Right , Bottom -->

    <Polygon Points="10,110 110,110 110,10"

        Stroke="Black" StrokeThickness="4"

        Canvas.Left="160" Canvas.Top="150" />

</Canvas>

توضیحات بیشتر در شکل

مثال در VB.Net

        Dim poly As New Polygon

        Dim po As Point

        po.X = 100

        po.Y = 100

        poly.Points.Add(New Point(0, 0))

        poly.Points.Add(New Point(50, 100))

        poly.Points.Add(po)

        poly.Stroke = Brushes.Red

        grid1.Children.Add(poly)

نکته :

چون از کانتینر Canvas استفاده شده است مختصات داده شده ثابت هستند و با توجه به مقادیر Canvas.Left (فاصله از سمت چپ) و Canvas.Top (فاصله از بالا) به مقادیر نقاط داده شده اضافه می شود(در واقع Canvas.Left و Canvas.Top نقطه صفر برای کشیدن اشکال را مشخص می کنند و بصورت پیش فرض صفر می باشند)

کشیدن چند خط صاف پشت سر هم با کنترل Polyline

 اشکال در WPF فقط می توانند درون کانتینرها یا کنترلهای دیگری که از Panel مشتق شده اند  قرار بگیرند.   

کشیدن چندین خط صاف در امتداد هم  Polyline

برای کشیدن خطوطی که پشت سر هم رسم می شوند این از این کنترل استفاده می کنند که برای کشیدن باید خاصیت آرایه ای Points که نشاندهنده نقاط است را باید مقدار دهی کرده و خطوط بین نقاط رسم می شود. نحوه دادن اطلاعات نقاط به آرایه Points بدین صورت است که به ازای هر X,Y یک نقطه ایجاد می شود و برای جدا کردن نقاط از فاصله استفاده کنید 

        <Canvas Margin="10" Height="300" Width="300">

            <!--  Polyline Left , Top -->

            <Polyline    

                Points="10,110 110,20"                 

                Stroke="Black" StrokeThickness="4"  />

   

            <!-- Polyline Right , Top -->

   

            <Polyline   

                Points="10,110 110,110 110,10"        

                Stroke="Red" StrokeThickness="4"

                Canvas.Left="150" />

   

            <!-- Polyline Left , Bottom -->

   

            <Polyline

                Points="10,100 50,110 50,50 100,34"

                Stroke="Blue" StrokeThickness="4"

                Canvas.Left="0" Canvas.Top="120"  />

   

            <!-- Polyline Right , Bottom -->

            <Polyline   

                Points="10,110 110,110 110,10 10,20 10,50 70,60"      

                Stroke="Green" StrokeThickness="4"

                Canvas.Top="120" Canvas.Left="150" />

        </Canvas>

توضیحات بیشتر در شکل زیر

نکته :

چون از کانتینر Canvas استفاده شده است مختصات داده شده ثابت هستند و با توجه به مقادیر Canvas.Left (فاصله از سمت چپ) و Canvas.Top (فاصله از بالا) به مقادیر نقاط داده شده اضافه می شود(در واقع Canvas.Left و Canvas.Top نقطه صفر برای کشیدن اشکال را مشخص می کنند و بصورت پیش فرض صفر می باشند)

مثال در VB.Net

        Dim poly As New Polyline

        Dim po As Point

        po.X = 100

        po.Y = 100

        poly.Points.Add(New Point(10, 10))

        poly.Points.Add(New Point(100, 10))

        poly.Points.Add(po)

        poly.Points.Add(New Point(200, 200))

        poly.Stroke = Brushes.Black

        grid1.Children.Add(poly)

اشکال در WPF فقط می توانند درون کانتینرها یا کنترلهای دیگری که از Panel مشتق شده اند  قرار بگیرند.

رسم دایره و بیضی با کنترل Ellipse در WPF

 اشکال در  WPF فقط می توانند درون کانتینرها یا کنترلهای دیگری که از Panel  مشتق شده اند  قرار بگیرند.

رسم دایره و بیضی  Ellipse

برای رسم بیضی که توسط Ellipse صورت می گیرد نیاز به تعیین طول و عرض مستطیلی که دایره در آن قرار می گیرد دارید. با دو خاصیت Height (عرض( و Width(طول) مستطیل را مشخص می شود

 Height : عرض مرزهایی که در آن بیضی قرار می گیرد را مشخص می کند

Width : طول مرزهایی که در آن بیضی قرار می گیرد را مشخص می کند

در شکل زیر می توانید یک نمونه از شکل بیضی کشیده شده را ببینید. 

    <StackPanel>

        <!--           Ellipse 1         -->

        <Ellipse Margin="5"

            Fill="Yellow"

            Height="50"

            Width="200"

            StrokeThickness="2"

            Stroke="Black"/>

        <!--           Ellipse 2         -->

        <Ellipse Margin="5"

            Fill="Green"

            Height="30"

            Width="150"

            StrokeThickness="2"

            Stroke="Red"/>

        <!--            Ellipse3         -->

        <Ellipse Margin="5"

            Fill="LightBlue"

            Height="75"

            Width="75"

            StrokeThickness="2"

            Stroke="Gray"/>

    </StackPanel>

نمایش با توضیح تصویری 

مثال در VB.Net

        Dim MyEllipse As New Ellipse

        MyEllipse.Width = 50

        MyEllipse.Height = 150

        MyEllipse.Fill = Brushes.Red

        grid1.Children.Add(MyEllipse)