نظرات مطالب
کنترل DatePicker شمسی مخصوص Silverlight 4
احتمالا از نسخه‌ی سیلورلایت 4 استفاده می‌کنید. بهتر است سورس نهایی را از اینجا دریافت و کامپایل کنید. این سورس به روزتر است از DLLهای منتشر شده. خصوصا نسخه‌ی WPF آن تغییرات زیادی داشته‌است که فقط از قسمت سورس‌ها قابل دریافت است.
مطالب
بررسی مباحث Streaming در ‎‎‎.NET - مقدمه

هدف بررسی کامل مباحث Streaming در دات نت فریمورک می‌باشد.

Stream چیست؟

دنباله‌ای از بایت‌ها که می‌توان آنها را از یک backing store (انبار پشتیبان) خواند یا در آن نوشت.

Backing Store 

یک رسانه ذخیره سازی از جمله Disk-Drive، Memory و Network Location می‌باشد که به عنوان منبع یا مقصدی برای خواندن و نوشتن بایت‌ها به صورت دنباله‌ای، می‌توان از آن استفاده کرد.


زمانی که قرار است داده ذخیره شده به صورت Stream مصرف شود، مزیت مقیاس پذیری را نیز خواهید داشت. لذا لازم نیست با مشکل محدودیت حافظه نیز درگیر شوید.

آشنایی با معماری Streaming در دات نت

Streaming در دات نت، توسط سه مفهوم: backing store، decorators و adapters در برگرفته شده است. 

کلاسی به نام Stream در دات نت، برای ارائه یکسری متد مشترک برای Reading، Writing و Positioning در نظر گرفته شده است که همچنین کلاس پایه Backing Store Streams و Decorator Streams نیز می‌باشد. 

اعضای کلاس Stream را می‌توان به شکل زیر گروه بندی کرد:


در نظر داشته باشید که Stream ها، دارای اشاره گری به مکان جاری تحت عنوان Pointer نیز می‌باشند. مقدار پیش فرض آن «صفر» می‌باشد و زمانی که شروع به خواندن از Stream کنید، این خواندن از مکانی شروع می‌شود که Pointer به آنجا اشاره می‌کند. به شکل زیر توجه کنید:

اگر قرار باشد 3 بایت اول خوانده شود، لذا حالت زیر را خواهیم داشت: 

همانطور که مشخص است، Pointer مربوط به Stream به اولین خانه‌ای اشاره می‌کند که در Read‌های بعدی قرار است خوانده شود. در نهایت با خواندن دو بایت دیگر، حالت زیر را خواهیم داشت:

برای Reading و Writing متدهای زیر در کلاس System.IO.Stream در نظر گرفته شده‌اند:

(Read(byte[] buffer,int offset,int count

buffer: آرایه‌ای از بایت‌ها برای نگهداری داده‌ی خوانده شده از Stream
offset: برخلاف تصور، اندیسی است که مکان شروع ذخیره سازی در buffer را مشخص می‌کند و نه مکان شروع خواندن از Stream
count: بیشترین تعداد بایت برای خواندن از Stream می‌باشد. با توجه به اینکه ممکن است به انتهای Stream رسیده باشیم یا اینکه در شرایطی مثلا در Network Streamها چه بسا خود Stream تصمیم بگیرد تعداد بایت کمتری از این مقدار Count را برای ما ارائه دهد. از این رو همیشه مقداری که برای Count مشخص می‌کنید همان مقداری نیست که متد Read برای شما برگشت خواهد داد.
return: تعداد بایت‌هایی که خوانده شده است یا اگر به انتهای Stream رسیده باشیم «0» برگشت خواهد داد. از این رو تکه کد زیر برای خواندن کل داده به یکباره، قابل اطمینان نخواهد بود. 

byte[] dataToRead=new byte[stream.Length];
int bytesRead=stream.Read(dataToRead,0,dataToRead.Length);

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

static byte[] ReadBytes(Stream stream)
    {
        // dataToRead will hold the data read from the stream
        byte[] dataToRead = new byte[stream.Length];
        //this is the total number of bytes read. this will be incremented 
        //and eventually will equal the bytes size held by the stream
        int totalBytesRead = 0;
        //this is the number of bytes read in each iteration (i.e. chunk size)
        int chunkBytesRead = 1;
        while (totalBytesRead < dataToRead.Length && chunkBytesRead > 0)
        {
            chunkBytesRead = stream.Read(dataToRead, totalBytesRead, 
                dataToRead.Length - totalBytesRead);
            totalBytesRead = totalBytesRead + chunkBytesRead;
        }
        return dataToRead;
    }
در کد بالا تا زمانیکه مجموع تعداد بایت‌های خوانده شده کوچکتر از طول Stream باشد و همچنین به انتهای Stream نرسیده باشیم (chunkBytesRead>0)، عملیات خواندن انجام خواهد گرفت. خوشبختانه در کلاس BinaryReader متدی برای این کار در نظر گرفته شده است که در آینده با آنها بیشتر آشنا خواهیم شد.
byte[] data = new BinaryReader (s).ReadBytes (1000);
ReadByte

return: یک بایت را از مکان فعلی که Pointer به آن اشاره می‌کند، می‌خواند. اگر خروجی «-1» باشد، به انتهای Stream رسیده اید.
برخلاف انتظار، خروجی این متد از نوع int می‌باشد؛ چرا که لازم است «-1» را نیز در برگیرد.

CanRead
ممکن است یک Stream از عملیات خواندن پشتیبانی نکند؛ این محدودیت از طریق حالت جاری Backing Store تعیین می‌شود. برای مثال:

با توجه به حالت FileStream که فقط برای Append کردن وهله سازی شده است، امکان خواندن را نخواهید داشت. بنابراین زمانیکه از کلاس شخص ثالثی برای خواندن از Stream استفاده می‌کنید، به‌صلاح است (به منظور Defensive Programming) که از متد CanRead قبل خواندن بهره ببرید.

(Write(byte[] array,int offset,int count

array: آرایه ای از بایت‌ها که قرار است در Stream درج شوند.
offset: اندیس شروع array برای درج کردن در Stream را مشخص می‌کند.
count: بیشترین تعداد بایتی که از array در Stream درج خواهد شد.

WriteByte

برای درج یک بایت در Stream استفاده می‌شود.

CanWrite

برای تشخص پشتیبانی کردن Stream از عملیات درج کردن مورد استفاده قرار خواهد گرفت.

عملیات Seeking 

با انجام هر یک از عملیات Read  و Write برروی Stream، باعث تغییر مکان Pointer مربوط به آن خواهید شد. در صورتیکه نیاز است به صورت انتخابی مکان خاصی از Stream را برای شروع درج کردن یا خواندن انتخاب کنید، Seeking کمک کننده خواهد بود.

باید توجه داشت که پشتیبانی از این عملیات به backing store مورد استفاده وابسته می‌باشد. از این رو باید دانست که MemoryStream و FileStream از Seeking پشتیبانی کرده ولی در مقابل NetworkStream، PipeStream و همچنین Decorator Streams به غیر از BufferedStream قابلیت Seeking را ندارند. BufferedStream با ایجاد پوششی برروی یک Stream به اصطلاح non-seekable، امکان Seeking درون Buffer داخلی خود را مهیا خواهد کرد.

برای عملیات Seeking نیز اعضایی در کلاس پایه System.IO.Stream در نظر گرفته شده است:

(Seek(long Offset,SeekOrigin origin

برای تنظیم مکان Pointer در Stream استفاده خواهد شد. 

(SetLength(long value

متدی برای تنظیم طول Stream، که اگر value ارسال شده کوچکتر از طول فعلی Stream باشد، آن را کوتاه کرده و در غیر این صورت، Stream موردنظر گسترش خواهد یافت. برای استفاده از این متد، Stream مورد نظر باید قابلیت Writing و Seeking را داشته باشد.

Length

پراپرتی فقط خواندنی که طول Stream را مشخص می‌کند. در صورتیکه Stream مورد نظر Seekable باشد، می‌توان از این پراپرتی بهر برد؛ این بدین معنی است که اگر با یک Stream از نوع non-seekable کار می‌کنید، در صورت استفاده از این خصوصیت، تمام بایت‌های Stream خوانده شده و بعد از قرار گرفتن در  یک buffer (به عنوان مثال در memory)، محاسبه خواهد شد.

Position

پراپرتی برای خواندن یا تنظیم مکان فعلی Pointer مربوط به Stream، می‌باشد. برای استفاده از آن لازم است Stream مورد استفاده Seekable باشد.

CanSeek

مشخص می‌کند که Stream مورد استفاده Seekable  می باشد یا خیر.

تفاوت متد Seek و پراپرتی Position برای عملیات Seeking

به طور خلاصه با استفاده از متد Seek انعطاف پذیری بالایی خواهید داشت. با مقدار دهی پراپرتی Position، این مقدار همیشه نسبت به ابتدای Stream در نظر گرفته خواهد شد (شکل زیر)؛ این در حالی است که با استفاده از متد Seek می‌توان مشخص کرد که مقدار Offset تنظیم شده نسبت به ابتدا، مکان جاری و یا انتهای Stream می‌باشد.

مثال:

        using (FileStream fs = File.Create(@"C:\files\testfile3.txt"))
        {
            // position is 0
            long pos = fs.Position;
            // sets the position to 1
            fs.Position = 1; 
         
            byte[] arrbytes = { 100, 101 };
            //writes the content of arrbytes into current position - which is 1
            fs.Write(arrbytes, 0, arrbytes.Length);
            //position is now 3 as its advanced by write
            pos = fs.Position;
            fs.Position = 0;
            byte[] readdata1 = ReadBytes(fs);
        }
در تکه کد بالا قصد داریم تعدادی بایت را در یک فایل متنی ذخیره کنیم. برای نشان دادن عملیات Seeking، ابتدا Position را با عداد «1» تنظیم کرده‌ایم. با استفاده از متد Write عمل درج بایت‌ها با شروع از مکان اندیس «1» را انجام داده‌ایم. در این لحظه، Position عدد «3» را نشان می‌دهد. حال برای خواندن Stream لازم است Position را با «0» مقدار دهی کنیم تا Pointer دوباره به ابتدای Stream اشاره کند و عملیات خواندن را انجام داده‌ایم. اگر تکه کد بالا را دیباگ کنیم، به نتیجه نشان داده شده در شکل زیر خواهیم رسید:

Closing and Flushing 

کلاس پایه System.IO.Stream اینترفیس IDisposable را پیاده سازی کرده است؛ لذا بهتر است برای آزاد سازی منابع از جمله: file handle در FileStream یا socket handle در NetworkStream، بعد از استفاده، متد Dispose آنها را فراخوانی کنید یا با وهله سازی آنها در بدنه using، این فراخوانی به صورت ضمنی انجام شود. 

نکته: باید توجه کنید که با Close (معادل Dispose) شدن decorator streamها ، backing store stream داخلی آنها نیز Close خواهد شد.

با توجه به اینکه I/O عملیات پرهزینه‌ای می‌باشد، برخی از انواع Stream‌ها به منظور بهبود کارآیی از یک مکانیزم بافر داخلی استفاده می‌کنند. به این شکل که عملیات Write، داده را به جای آنکه درون backing store ذخیره سازی کند، درون این بافر ذخیره سازی خواهد کرد. زمانیکه این بافر پر شود یا به صورت صریح متدهای Flush یا Close فراخوانی شده باشند، داده موجود در بافر درون backing store ذخیره خواهد شد. در نتیجه عملیات Read هم می‌تواند به بخشی از داده اصلی که هم اکنون درون بافر می‌باشد، دسترسی سریع‌تری داشته باشد. به عنوان مثال FileStream از این مکانیزم داخلی برخوردار است. سایز پیش فرض این بافر ‏‏4KB (قابل تنظیم است) می‌باشد. برای سایر مواردی که این امکان برایشان وجود ندارد، می‌توان از BufferedStream برای Decorate کردن Stream مورد نظر خود استفاده کرد.

نکته: به صورت پیش فرض، Streamها thread-safe نیستند و امکان خواندن و نوشتن همزمان توسط چند thread برروی یک stream مشترک را نخواهید داشت. برای حل این موضوع، متد استاتیکی در کلاس Stream تحت عنوان Synchronized در نظر گرفته شده است که یک thread-safe wrapper را به برروی stream ورودی در نظر گرفته و آن را به عنوان خروجی برگشت خواهد داد. 

 [HostProtection(SecurityAction.LinkDemand, Synchronization = true)]
    public static Stream Synchronized(Stream stream)
    {
      if (stream == null)
        throw new ArgumentNullException("stream");
      if (stream is Stream.SyncStream)
        return stream;
      return (Stream) new Stream.SyncStream(stream);
    }
نظرات مطالب
استفاده از Froala WYSIWYG Editor در ASP.NET
- سورس انتهای بحث را دریافت کنید. به خاصیت buttons آن (که در View برنامه موجود است)، مقدار insertHTM اضافه می‌شود. همچنین یک خاصیت جدید هم به نام customButtons با مقداری که مشخص شده، باید در کنار سایر خواص این افزونه، اضافه شود.
- سایر نظرات تکمیلی و نگارش‌های بهبود یافته را هم مدنظر داشته باشید.
نظرات مطالب
بهبود SEO در ASP.NET MVC
من از پروژه سورس باز LowercaseRoutesMVC که در انتهای مطلب معرفی شد، استفاده می‌کنم. ضمنا این تنظیم، بدون تعریف canonical urls ناقص است. یعنی در عمل بر اساس گزارش‌های Google webmaster tools به این نتیجه رسیده‌ام که گوگل، دیتابیس آدرس‌های تکراری را بر اساس تنظیمات canonical urls، به روز و اصلاح می‌کند.
نظرات مطالب
SFDown
فعلا که گوگل و سورس فورج این توانایی رو پیدا کردن. دسترسی به گوگل کد و امکانات سورس فورج گاهی از اوقات با وی پی ان هم میسر نیست
مطالب
آشنایی با WPF قسمت چهارم: کنترل ها
WPF همانند Windows Form شامل ابزارها یا کنترل‌های داخلی است که می‌توانند در تهیه‌ی یک برنامه بسیار کارآمد باشند. در این بخش به بررسی تعدادی از این کنترل‌ها می‌پردازیم و مابقی آن‌ها را در قسمت‌های آینده بررسی خواهیم کرد. در این نوشتار سعی بر این است که یک فرم ساده را با آن ایجاد کرده و مورد استفاده قرار دهیم.
این فرم دارای اطلاعاتی شامل : نام، جنسیت ، زمینه‌های کاری، کشور، تاریخ تولد و تصویر می‌باشد.

TextBlock

همان Label قدیمی خودمان است که برای نمایش متون کاربر دارد. متن داخل آن بین دو تگ قرار می‌گیرد و یا از خاصیت Text آن کمک گرفته خواهد شد. حتما از خاصیت Width و height آن برای مقداردهی کمک بگیرید، زیرا در غیر آن صورت کل Container خود را خواهد پوشاند. در صورتی که متنی در مکان خود جا نشود می‌توان از دو ویژگی استفاده کرد. آن را برش داد یا به خطوط بعدی شکست. برای حذف یا برش باقی مانده متن می‌توان از خصوصیت TextTrimming استفاده کرد که سه مقدار می‌گیرد:

None مقدار پیش فرض

CharacterEllipsis با نزدیک شدن به آخر پهنای کار از ... استفاده می‌نماید. در صورتی که لیستی یا مورد مشابهی دارید میتواند بسیار کاربردی باشد.

WordEllipsis این گزینه هم مانند مورد بالاست با این تفاوت که سعی دارد تا آنجا که ممکن است خود را به آخرین حرف کلمه برساند تا شکستگی در وسط کلمه اتفاق نیفتد و آخرین کلمه کامل دیده شود و بعد ... قرار بگیرد؛ هر چند در تست‌های خودم تفاوتی مشاهده نکردم.

گزینه TextWrapping جهت شکستن یک خط به خطوط است؛ موقعی که متن شما به انتهای صفحه می‌رسد، این ویژگی باعث می‌شود متن به بیرون از پنجره نرفته و یک خط به سمت پایین حرکت کند. این گزینه سه مقدار را دارد:

تصویر زیر حالت اصلی نمایش بدون نیاز به Wrap شدن است:

None: مقدار پیش فرض که خصوصیت Wrap را به همراه ندارد.

Wrap: فعال سازی ویژگی TextWrapping

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

خصوصیت LineStackingStrategy:

این خصوصیت فاصله‌ی بین خطوط را با استفاده از یک واحد منطقی dp مشخص می‌کند. هر چند دو گزینه دیگر هم دارد که دو تصویر زیر را در این صفحه به شما نمایش می‌دهد:

برای ساخت فرم از یک گرید با سه ستون و 6 سطر استفاده می‌کنم.

<Grid Margin="5">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        
        </Grid.RowDefinitions>
</Grid>
در ستون اول نام فیلدهای مورد نظر را می‌نویسیم و در ستون دوم هم کنترل‌های مد نظر هر فیلد را قرار خواهیم داد. در صورتی که دوست دارید کار از راست به چپ پشتیبانی کند از گزینه OverflowDirection در تگ پنجره Window استفاده نمایید.
در داخل گرید بعد از تعریف سطر و ستون، همانطور که قبلا توضیح دادیم کنترل‌های TextBlock را اضافه می‌کنیم:
<TextBlock Grid.Column="0"  Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" >Name</TextBlock>
        <TextBlock Grid.Column="0"  Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Left" >Gender</TextBlock>
        <TextBlock Grid.Column="0"  Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" >Field Of Work</TextBlock>
        <TextBlock Grid.Column="0"  Grid.Row="3" VerticalAlignment="Center" HorizontalAlignment="Left" >Country</TextBlock>
        <TextBlock Grid.Column="0"  Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" >Birth Date</TextBlock>

<TextBox Grid.Row="0" Grid.Column="1" Name="Txtname" HorizontalAlignment="Left" Margin="5" Width="200" ></TextBox>
برای فیلد نام، از کنترل TextBox استفاده کردم که با محدود کردن Width آن اندازه ثابت به آن دادم. در صورتی که width ذکر نشود یا به Auto ذکر شود، در صورتی که متنی که کاربر تایپ می‌کند، بیش از اندازه تعیین شده کنترل Textbox باشد، کنترل هم همراه متن بزرگتر خواهد شد و تا پایان محدوده سلولی اش در گرید کش خواهد آمد.

Buttons 
برای فیلد جنسیت Gender هم از RadioButton کمک گرفتم که با استفاده از خاصیت GroupName می‌توان دسته‌ای از این کنترل‌ها را با هم مرتبط ساخت تا با انتخاب یک آیتم جدید از همان گروه، آیتم قبلی که انتخاب شده بود از حالت انتخاب خارج شده و آیتم جدیدی انتخاب شود. از خاصیت IsChecked می‌توان برای انتخاب یک آیتم بهره برد.

به صورت کلی دکمه‌ها به چند دسته زیر تقسیم می‌شوند:

  • Button
  • ToggleButton
  • CheckBox
  • RadioButton

که همگی این عناصر از کلاسی به نام ButtonBase مشتق شده اند. کد زیر RadioButton‌ها را به صورت عمودی چینش کرده است:

<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1" Margin="10">
            <RadioButton GroupName="Gender" Name="RdoMale" IsChecked="True" >Male</RadioButton>
            <RadioButton GroupName="Gender" Name="RdoFemale" Margin="0 5 0 0" >Female</RadioButton>
        </StackPanel>
برای فیلد زمینه کاری ، لیست کشورها و تاریخ تولد از کدهای زیر کمک گرفتم:
<StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="1" Margin="10">
            <CheckBox Name="ChkActor" >Actor/Actress</CheckBox>
            <CheckBox Name="ChkDirector" >Director</CheckBox>
            <CheckBox Name="ChkProducer" >Producer</CheckBox>
        </StackPanel>

        <ListBox Grid.Row="3" Grid.Column="1" Margin="10"  Height="80">
        <ListBoxItem>
                <TextBlock>UnitedStates</TextBlock>
            </ListBoxItem>
            <ListBoxItem>
                <TextBlock >UK</TextBlock>
            </ListBoxItem>
            <ListBoxItem>
                <TextBlock >France</TextBlock>
            </ListBoxItem>
            <ListBoxItem>
                <TextBlock >Japan</TextBlock>
            </ListBoxItem>
        </ListBox>

        <Calendar Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left" Margin="10"></Calendar>
برای لیست کشورها می‌توان از یک ListBox یا ComboBox استفاده کرده که هر آیتم داخل آنها در یک تگ ListBoxItem یا ComboBoxItem قرار می‌گیرد. اگر از حالت ListBox استفاده می‌کنید، در صورتی که آیتم‌ها از ارتفاع لیست بیشتر شود به طور خودکار یک Scrollbar برای آن‌ها در نظر گرفته خواهد شد و نیازی نیست که آن را دستی اضافه کنید.
برای تصویر شخص، قصد دارم آن را در گوشه‌ی سمت راست و بالا قرار دهم. برای همین محل ستون آن را ستون سوم یا اندیس دوم انتخاب کرده و از آنجا که این عکس حالت پرسنلی دارد، می‌تواند چند سطر را به خود اختصاص دهد که با کمک خاصیت Rowspan، چهار سطر، کنترل را ادامه دادم. برای ستون‌ها هم می‌توان از خاصیت ColumnSpan استفاده کرد. همچنین دوست دارم یک دکمه هم روی تصویر در گوشه‌ی سمت چپ و پایین قرار داده که کاربر با انتخاب آن به انتخاب عکس یا تغییر آن بپردازد. برای همین از یک پنل گرید استفاده کردم و کنترل دکمه را روی تصویر قرار دادم. همپوشانی کنترل‌ها در اینجا صورت گرفته است.

 <Grid Grid.Row="0" Grid.Column="2" Grid.RowSpan="4">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Image HorizontalAlignment="Right" Source="man.jpg" Stretch="UniformToFill" VerticalAlignment="Top" Width="100" Height="150"></Image>
            <Button Width="25" Height="15"    Padding="0"  HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0,0,0,83">
                 <TextBlock VerticalAlignment="Center" Margin="0 -7 0 0">...</TextBlock>
            </Button>
        </Grid>
خاصیت Stretch کنترل Image در بالا، نحوه‌ی نمایش تصویر را نشان می‌دهد که چهار مقدار دارد:
None: تصویر، اندازه‌ی اصلی خود را حفظ کرده و هر مقدار آن که در کنترل جا شود، نمایش می‌یابد و بسته به سایز تصویر ممکن است گوشه هایی از تصویر نمایش نیابد.
Fill: تصویر را داخل کنترل به زور جا داده تا پهنا و ارتفاع عکس، هم اندازه کنترل می‌شود.
Uniform: تصویر بزرگ را با در نظر گرفتن نسبت پهنا و ارتفاع تصویر، با یکدیگر در کنترل جا می‌دهد.
UniformToFill: تصویر، کل کنترل را می‌گیرد ولی نسبت پهنا و عرض را حفظ کرده ولی قسمت هایی از تصویر در کنترل دیده نمی‌شود.

همانطور که قبلا هم گفتیم، خود کنترل دکمه شامل زیر کنترل‌هایی می‌شود که یکی از آن‌ها TextBlock است و از طریق خصوصیت *.TextBlock دیگر خصوصیات آن قابل تنظیم است و البته برای خصوصی سازی بیشتر هم می‌توان یک TextBlock را به صورت Nested یعنی داخل تگ Button تعریف کنید که ما همین کار را کرده ایم.
فرم نهایی ما به صورت زیر است:


در صورتی که دوست دارید جهت ListBox را از عمودی به افقی تغییر دهید می‌توانید از پنل‌های Stack یا Wrap استفاده کنید که تعریف آن به شکل زیر است:
<ListBox>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

بدین صورت ListBox به شکل زیر تغییر می‌یابد:



و در صورتی که می‌خواهید Scroll حذف شود و از Wrap استفاده کنید، کد را به شکل زیر تعریف کنید. فراموش نکنید که اسکرول افقی را غیرفعال کنید؛ وگرنه نتیجه کار به شکل بالا خواهد بود.
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>
نتیجه:

Calendar
تقویم یکی دیگر از کنترل‌های موجود است که شامل خصوصیات زیر است:
DisplayDate: تاریخ پیش فرض و اولیه تقویم را مشخص می‌کند؛ در صورتی که ذکر نشود تاریخ جاری درج می‌شود.
<Calendar DisplayDate="01.01.2010" />
از خصوصیات دیگر در این زمینه می‌توان به DisplayDateStart و DisplayDateEnd اشاره کرد که محدوه‌ی نمایش تاریخ تقویم را مشخص می‌کند. کد زیر تنها تاریخ‌های روز اول ماه ابتدای سال 2015، تا روز اول ماه پنجم 2015 را نمایش می‌دهد:
<Calendar DisplayDateStart="01.01.2015" DisplayDateEnd="05.01.2015" />


SelectionMode: نحوه‌ی انتخاب تاریخ را مشخص می‌کند:
SingleDate: فقط یک تاریخ قابل انتخاب است.
SingleRange: می‌توانید از یک تاریخ تا تاریخ دیگر را انتخاب کنید. ولی نمی‌توانید مجددا چند انتخاب دیگر را در جای جای تقویم داشته باشید. مثلا از تاریخ 5 آپریل تا 10 آپریل را انتخاب کرده‌اید؛ ولی دیگر نمی‌توانید تاریخ 15 آپریل یا محدوده‌ی 15 آپریل تا 20 آپریل را انتخاب کنید. چون تنها قادر به انتخاب یک رنج یا محدوده تاریخی هستید.
MultipleRanges: بر خلاف گزینه‌ی بالایی هر محدوده تاریخی قابل انتخاب است.
<Calendar SelectionMode="MultipleRange" />

نکته بعدی در مورد غیرفعال کردن بعضی از تاریخ هاست که شما قصد ندارید به کاربر اجازه دهید آن‌ها را انتخاب کند. برای مثال تاریخ‌های 1 آپریل تا 10 آپریل را از دسترس خارج کنید. برای همین از خصوصیت BlackoutDates استفاده می‌کنیم که نحوه‌ی تعریف آن به شرح زیر است که در این کد دو محدوده‌ی تاریخی غیر فعال شده اند:
<Calendar>
    <Calendar.BlackoutDates>
        <CalendarDateRange Start="01/01/2010" End="01/06/2010" />
        <CalendarDateRange Start="05/01/2010" End="05/03/2010" />
    </Calendar.BlackoutDates>
</Calendar>



DisplayMode
: به طور پیش فرض، تقویم ماه‌ها را نشان می‌دهد ولی میتوانید آن را توسط این خصوصیت روی سال یا دهه و ماه هم تنظیم کنید.
با انتخاب سال Year، تقویم ماه‌های یک سال را نمایش می‌دهد.
با انتخاب دهه Decades سال‌های یک دهه‌ی تعیین شده را نشان می‌دهد و با انتخاب ماه Month روز‌های هر ماه در آن نمایش داده می‌شود.
در هنگام انتخاب این گزینه، به داخل تقویم نگاه نکنید، بلکه به سر تیتر آن نگاه کنید.
<Calendar DisplayMode="Year" />



مطالب
توسعه سرویس‌های مبتنی بر REST در AngularJs با استفاده از RestAngular : بخش دوم
در بخش پیشین  کلیات کتابخانه‌ی Restangular  را بررسی کردیم. در این بخش قصد داریم تا در طی یک پروژه، امکانات و قابلیت‌های بی‌نظیر این سرویس را در یک پروژه‌ی واقعی مشاهده کنیم.

کلیات پروژه

در این پروژه قصد داریم تا لیست کتاب‌های یک کتابخانه را نمایش دهیم. این کتابها قابلیت ویرایش نام دارند و همچنین شما می‌توانید کتابهای جدیدی را به لیست کتابها اضافه نمایید. تصویر زیر خروجی این پروژه است:

پایگاه داده‌ی برنامه با نام LibDb درون پوشه‌ی app_data قرار داده شده‌است. این پایگاه داده تنها دارای یک جدول است؛ با نام Books که دیاگرام آن را در شکل زیر مشاهده می‌کنید:


پیاده سازی

در ابتدا یک پروژه‌ی Empty را با رفرنس web API ایجاد می‌کنیم. حال درون فایل WebApiConfig.cs تکه کد زیر را اضافه می‌کنیم. این تکه کد فیلدها و آبجکت‌هایی را که از سمت سرور بازگشت داده می‌شوند، به صورت camelCase تبدیل می‌کند.
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();

jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
در ادامه مدل edmx را ساخته و پس از آن Books Web Api را درون پوشه‌ی کنترلر ایجاد می‌کنیم. این کنترلر به صورت Default web Api Scaffold ساخته شده است و به دلیل اینکه به بحث ما مرتبط نیست؛ از توضیح بیشتر آن می‌گذریم.
حال پوشه‌ای را با نام app برای نگه داری فایل‌های AngularJs اضافه می‌کنیم و درون آن فایل app.js را ایجاد می‌کنیم:
var angularExample = angular.module('angularexample', ["restangular"])
angularExample.config(["RestangularProvider", function (RestangularProvider) {
    //RestangularProvider.setRestangularFields({
    //    id: "id"
    //});
    RestangularProvider.setBaseUrl('/api');
}]);

angularExample.controller("MainCtrl", ["Restangular", "$scope", function (Restangular, $scope) {
    var resource = Restangular.all('books');
    resource.getList().then(function (response) {
        $scope.books = response;
    });
    $scope.add = function () {
        resource.post($scope.newBook).then(function (newResource) {
            $scope.books.push(newResource);
        })
    }
}]);
محتویات فایل app.js را مشاهده می‌کنید. در ادامه درباره‌ی این قسمت بیشتر صحبت می‌کنیم.
حال در روت پروژه فایل index.html را ایجاد می‌کنیم:
<!DOCTYPE html>
<html ng-app="angularexample" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Rest Angular Sample</title>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
    <script src="http://cdn.jsdelivr.net/underscorejs/1.5.1/underscore-min.js"></script>
    <script src="/Scripts/restangular.min.js"></script>
    <script src="/app/app.js"></script>
</head>
<body>
    <div ng-controller="MainCtrl">
        <div ng-repeat="item in books">
            name is: {{item.name}}<br />
            change name: <input type="text" ng-model="item.name" /><button type="submit" ng-click="item.put();">update</button>
        </div>
        <div>
            add new: <br />
            <input type="text" ng-model="newBook.name" /><button type="submit" ng-click="add()">add</button>
        </div>
    </div>
</body>
و در نهایت در پوشه‌ی Scripts فایل‌های سرویس Restangular را قرار می‌دهیم.
تا به اینجای کار تمامی کارهای مورد نیاز تشکیل پروژه را انجام داده‌ایم. حال به بررسی بیشتر سرویس‌های این پروژه می‌پردازیم؛ یعنی کدهای درون فایل app.js.
ببینیم که برای دریافت لیست تمامی کتابها، ما چه کارهایی را انجام داده‌ایم! به تکه کد زیر دقت کنید:
    var resource = Restangular.all('books');
    resource.getList().then(function (response) {
        $scope.books = response;
    });
این تمامی آن چیزی است که ما برای دریافت لیست تمامی کتابها انجام داده‌ایم. به همین سادگی! در خط اول از متد all که در بخش قبل توضیح مختصری راجع به آن داده بودم برای دریافت لیست تمامی کتابها استفاده کردم که پارامتر درون آن آدرس Web Api است. البته همانطور که می‌دانید در ASP.NET Web Api ما همیشه به base address یک api نیز اضافه می‌کنیم. حال اینکه چرا api در اینجا نیامده در ادامه و در بخش تنظیمات کلی Restangular توضیح می‌دهم. در خط دوم نیز از اشاره‌گر resources متد getList را فراخوانی کرده و لیست کتابها را در response دریافت می‌کنیم.
پس از آن می‌خواهیم ببینیم که عملیات ایجاد یک کتاب جدید چگونه انجام می‌گردد. تکه کد زیر این عملیات را انجام می‌دهد:
    $scope.add = function () {
        resource.post($scope.newBook).then(function (newResource) {
            $scope.books.push(newResource);
        })
    }
ما یک متد با نام add ایجاد کرده‌ایم که در سمت View توسط دایرکتیو ng-click آن را فراخوانی می‌کنیم.
همانطور که مشاهده میکنید درون app.js متدی برای update موارد قبلی نیست. بیایید سری به View بزنیم. به المنت div زیر توجه کنید. همانطور که می‌بینید تمامی عملیات update با یک دستور ساده item.put حل و فصل شده.
        <div ng-repeat="item in books">
            name is: {{item.name}}<br />
            change name: <input type="text" ng-model="item.name" /><button type="submit" ng-click="item.put();">update</button>
        </div>
تمامی آنچه که گفته شد تنها بخشی از قابلیت‌های شگفت انگیز این افزونه بود. امیدوارم که مطلب مفید واقع شده باشد. سورس این پروژه را می‌توانید از لینک زیر دریافت کنید.

سورس پروژه: RestangularSample.rar  

مطالب
مقایسه‌ای کوتاه بین WCF و ASMX

ویژگی WCF ASMX
حداقل پیشنیاز دات نت سه دات نت یک
هدف جایگزینی یکپارچه‌ی فناورهای قبلی شامل
ASMX ، WSE ،
MSMQ ، COM+ Eenterprise
services
و .NET Remoting
ارائه وب سرویس
پروتکل‌های پشتیبانی شده HTTP
TCP
Named pipes
MSMQ
Custom
UDP
HTTP only
پشتیبانی از WS-* standards بلی خیر
پشتیبانی از اطلاعات بایناری بلی خیر
پشتیبانی از REST بلی خیر
میزبان‌های مهیا در هر نوع برنامه‌ی تهیه شده با دات 3 به بعد قابل
میزبانی است، مانند یک برنامه کنسول، یک سرویس ویندوز ان تی و غیره. به این لیست IIS را هم می‌توان اضافه کرد.
فقط IIS
سرعت WCF Services‌ نسبت به ASMX Web Services از 25
تا 50 درصد سریعتر هستند + و +

نحوه‌ی پاسخ دهی به درخواست‌ها (یا ایجاد یک وهله جدید) Singleton / private session / per call per-call
پشتیبانی از تراکنش‌ها (transaction) پشتیبانی تو کار + خیر
امنیت پشتیبانی تو کار + خودتان باید فکری برای این موضوع نمائید.
بسط پذیری بلی + خیر
مدت زمان یادگیری حداقل یک ماه یک روز!

مطالب
ساخت یک گزارش ساز به کمک iTextSharp و Open Office

iTextSharp پایه کار با فایل‌های PDF را ارائه می‌دهد اما ابزاری را جهت ساده‌تر سازی تولید فایل‌های PDF به همراه ندارد؛ هر چند مثلا امکان تبدیل HTML به PDF را دارا است اما باید گفت: «تا حدودی البته». اگر نیاز باشد جدولی را ایجاد کنیم باید کد نویسی کرد، اگر نیاز باشد تصویری اضافه شود به همین ترتیب و الی آخر. البته این را هم باید در نظر داشت که کد نویسی انعطاف قابل توجهی را در اختیار برنامه نویس قرار می‌دهد؛ شاید به همین دلیل این روزها مباحث «Code first» بیشتر مورد توجه برنامه نویس‌ها است، تا مباحث «Wizard first» یک دهه قبل!
اما باز هم داشتن یک طراح بد نیست و می‌تواند در کاهش مدت زمان تولید نهایی یک فایل PDF مؤثر باشد. برای این منظور می‌توان از برنامه‌ی رایگان و معروف Open office استفاده کرد. توسط آن می‌توان یک فرم PDF را طراحی و سپس فیلدهای آن‌را (این قالب تهیه شده را) با iTextSharp پر کرد. این مورد می‌تواند برای تهیه گزارش‌هایی که تهیه آن‌ها با ابزارهای متداول گزارش سازی عموما میسر نیست،‌ بسیار مناسب باشد.


طراحی یک فرم PDF با استفاده از برنامه Open Office

آخرین نگارش برنامه Open office را از اینجا می‌توانید دریافت کنید و آنچنان حجمی هم ندارد؛ حدودا 154 مگابایت است.
پس از نصب و اجرای برنامه، حداقل به دو طریق می‌توان یک فرم جدید را شروع کرد:
الف) آغاز یک XML Form document جدید در Open office سبب خواهد شد که نوارهای ابزار طراحی فرم، مانند قرار دادن TextBox ، CheckBox و غیره به صورت خودکار ظاهر شوند.
ب) و یا آغاز یک سند معمولی و سپس مراجعه به منوی View->Toolbars->Form Controls هم همان حالت را به همراه خواهد داشت.


در اینجا برای طراحی یک گزارش یا فرم جدید تنها کافی است همانند روش‌های متداول تهیه یک سند معمولی رفتار کنیم و مواردی را که قرار است توسط iTextSharp مقدار دهی کنیم، با کنترل‌های نوار ابزار Form آن بر روی صفحه قرار دهیم که نمونه‌ی ساده آن‌را در شکل زیر ملاحظه می‌کنید:


برای گزارش‌های فارسی بهتر است Alignment یک کنترل به Right تنظیم شود و Border به حالت Without frame مقدار دهی گردد. نام این کنترل را هم بخاطر بسپارید و یا تغییر دهید. از این نام‌ها در iTextSharp استفاده خواهیم کرد. (صفحه خواص فوق با دوبار کلیک بر روی یک کنترل قرار گرفته بر روی فرم ظاهر می‌شود)

مرحله بعد، تبدیل این فرم به فایل PDF است. کلیک بر روی دکمه تهیه خروجی به صورت PDF در نوار ابزار اصلی آن برای اینکار کفایت می‌کند. این گزینه در منوی File نیز موجود است.


فرم‌های PDF تهیه شده در اینجا، فقط خواندنی هستند. مثلا یک کاربر می‌تواند آن‌ها را پر کرده و چاپ کند. اما ما از آن‌ها در ادامه به عنوان قالب گزارشات استفاده خواهیم کرد. بنابراین جهت ویرایش فرم‌های تهیه شده بهتر است فایل‌های اصلی Open Office مرتبط را نیز درجایی نگهداری کرد و هر بار پس از ویرایش، نیاز است تا خروجی جدید PDF آن‌ها تهیه شود.


استفاده از iTextSharp جهت مقدار دهی فیلدهای یک فرم PDF

در ادامه می‌خواهیم این قالب گزارشی را که تهیه کردیم با کمک iTextSharp پر کرده و یک فایل PDF جدید تهیه کنیم. سورس کامل اینکار را در ذیل مشاهده می‌کنید:


using System;
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace PdfForm
{
class Program
{
//روش صحیح ثبت و معرفی فونت در این کتابخانه
public static iTextSharp.text.Font GetTahoma()
{
var fontName = "Tahoma";
if (!FontFactory.IsRegistered(fontName))
{
var fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\tahoma.ttf";
FontFactory.Register(fontPath);
}
return FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
}

static void Main(string[] args)
{
string fileNameExisting = @"form.pdf";
string fileNameNew = @"newform.pdf";

using (var existingFileStream = new FileStream(fileNameExisting, FileMode.Open))
using (var newFileStream = new FileStream(fileNameNew, FileMode.Create))
{
var pdfReader = new PdfReader(existingFileStream);
using (var stamper = new PdfStamper(pdfReader, newFileStream))
{
//نکته مهم جهت کار با اطلاعات فارسی
//در غیراینصورت شاهد ثبت اطلاعات نخواهید بود
stamper.AcroFields.AddSubstitutionFont(GetTahoma().BaseFont);

//form.Fields.Keys = تمام فیلدهای موجود در فرم
var form = stamper.AcroFields;

//مقدار دهی فیلدهای فرم
form.SetField("TextBox1", "مقدار1");
form.SetField("TextBox2", "مقدار2");

// "Yes" and "Off" are valid values here
form.SetField("Check Box 1", "Yes");

// "" and "Off" are valid values here
form.SetField("Option Button 1", "");

// نحوه مقدار دهی لیست
form.SetListOption("ListBox1", new[] { "1مقدار یک", "مقدار دو1" }, null);
form.SetField("ListBox1", null);

// به این ترتیب فرم دیگر توسط کاربر قابل ویرایش نخواهد بود
//stamper.PartialFormFlattening --> جهت غیرقابل ویرایش نمودن فیلدی مشخص
stamper.FormFlattening = true;

stamper.Close();
pdfReader.Close();
}
}

Process.Start("newform.pdf");
}
}
}

توضیحات:
چون در اینجا فایل PDF، از پیش تهیه شده است، پس باید از اشیاء PdfReader و PdfStamper جهت خواندن و نوشتن اطلاعات در آن‌ها استفاده کرد. سپس توسط شیء stamper.AcroFields می‌توان به این فیلدها یا همان کنترل‌هایی که در برنامه‌ی Open office بر روی فرم قرار دادیم، دسترسی پیدا کنیم.
در ابتدا نیاز است فونت این فیلدها توسط متد AddSubstitutionFont مقدار دهی شود. این مورد برای گزارش‌های فارسی الزامی است؛ در غیراینصورت متنی را در خروجی مشاهده نخواهید کرد.
ادامه کار هم مشخص است. توسط متد form.SetField مقداری را به کنترل‌های قرار گرفته بر روی فرم نسبت می‌دهیم. آرگومان اول آن نام کنترل است و آرگومان دوم، مقدار مورد نظر می‌باشد. اگر کنترل CheckBox را بر روی صفحه قرار دادید، تنها مقدارهای Yes و Off را می‌پذیرد (آن هم با توجه به اینکه به کوچکی و بزرگی حروف حساس است). اگر یک Radio button یا در اینجا Option button را بر روی فرم قرار دادید، تنها مقدارهای خالی و Off را قبول خواهد کرد. نحوه‌ی مقدار دهی یک لیست هم در اینجا ذکر شده است.
در پایان چون نمی‌خواهیم کاربر نهایی قادر به ویرایش اطلاعات باشد، FormFlattening را true خواهیم کرد و به این ترتیب، کنترل‌ها فقط خواندنی خواهند شد. البته اگر همانطور که ذکر شد، border کنترل‌ها را در حین طراحی حذف کنید، PDF نهایی تولیدی یکپارچه و یک دست به نظر می‌رسد و اصلا مشخص نخواهد بود که این فایل پیشتر یک فرم قابل پر کردن بوده است.

مطالب
آموزش فایرباگ - #7 - CSS Panel
پنل CSS مانند پنل جانبیِ Style که در مقاله‌ی قبل بررسی کردیم است با این تفاوت که امکانات بیشتری برای افرادی که قصد تصریف استایل دارند محیا کرده است.
در این پنل می‌توان به اضافه ، ویرایش و حذف استایل هایی که به صفحه‌ی جاری توسط فایل‌های مختلف اضافه شده اند و یا داخل خود صفحه تعریف شده اند پرداخت.



همچنین در این پنل امکان ویرایش یک فایل css بصورت کامل وجود دارد ، به این صورت که می‌توانید تمام محتویات فایل مورد نظر را در یک Text area ویرایش کنید.

مطابق با روالی که در قسمت قبل پیش گرفتیم عمل می‌کنیم و به ترتیب به تشریح ابزار پنل ، خود پنل ، منوی راست کلیک و پنل جانبی ِ Elements می‌پردازیم.


Options Menu
با راست کلیک کردن بروی تب CSS و یا کلیک کردن بروی فلش کوچک روی تب CSS قابل دسترس است و امکانات زیر را محیا می‌کند:

  • Expand Shorthand Properties : نمایش دستورات css بصورت کامل ، به این معنی که دستوراتی مانند margin که هم بصورت خلاصه و هم بصورت کامل تعریف می‌شوند را بصورت کامل نمایش می‌دهد. مثلا margin را چهار مقدار margin-top , margin-right , margin-bottom , margin-left نمایش می‌دهد.

  • Color As Hex , Color As RGB , Color As HSL : با انتخاب یکی از سه مقدار ذکر شده ، فرمت نمایش رنگ‌ها به حالت انتخاب شده تغییر می‌کند.
    مثلا دستور color : #000000 به این صورت نمایش داده می‌شود :‭ color : rgb(0, 0, 0) 

  • Refresh : این گزینه محتویات پنل را بروز می‌کند.

Panel Toolbar
ابزاری موجود در این پنل مشابه پنل‌های دیگر در بالای پنل و در زیر تب پنل‌ها قرار دارد و شامل ابزارهای زیر می‌شود:

  • Edit Button : این ابزار به دو صورت Live Edit و Source Edit در دسترس هست که با کلیک بروی فلش کوچکی که در سمت راست دکمه قرار دارد می‌توان نوع آن را تغییر داد.
    انتخاب حالت Source Edit ، باعث می‌شود سورس فایل به همان صورتی که به مرورگر ارسال شده نمایش داده شود. ( کامنت‌ها ، فرمت فایل و ... حفظ می‌شود. )
    حالت Live Edit هم باعث نمایش محتویات فایل بصورت مرتب شده می‌شود. ( کامنت‌ها و دستوراتی که توسط مرورگر تفسیر نشده اند نمایش داده نمی‌شوند. )



  • CSS Location Menu : نام فایل جاری که در پنل در حال نمایش است را نمایش می‌دهد و همچنین با کلیک بروی آن ، فایل‌های استایل دیگری که در صفحه بارگزاری شده اند را نمایش می‌دهد. با کلیک بروی هرکدام از فایل‌های نمایش داده شده ، همان فایل در پنل باز می‌شود.

    استایل هایی که در خود صفحه تعریف شده اند با نام خود صفحه در این قسمت نمایش داده می‌شوند و اگر استایل‌های در چندین تگ style تعریف شده باشند ، دومین تگ با #2 ، سومین با #3 و ... مشخص می‌شوند.

    هنگام باز بودن :
    1- فایل هایی که از پوشه‌های مختلف در صفحه بارگذاری شده اند ، با نام پوشه از هم تفکیک شده اند:



    2- با تایپ کردن عبارت دلخواه می‌توان نتایج را محدود کرد:



Panel
منظور از پنل ، قسمتی هست که استایل بصورت فرمت شده و نمایش داده شده است.


 Infotips
توسط این قابلیت ، زمانی که موس را بروی آدرس تصاویر ، نوع فونت و ... ببرید ، پاپ آپ کوچکی باز می‌شود و اطلاعاتی در مورد مقادیر می‌دهد. مثلا اینکه آیا تصویر مورد نظر به درستی بارگذاری شده یا نه ، نمای کوچکی از تصویر ، شکل فونت و ...

 Editing rules
برای ویرایش تعاریف CSS شامل Selector‌ها ، دستورات و مقادیر ، این پنل ابزارهای مفیدی ارائه می‌کند.
برای ویرایش یک selector ، دستور یا مقدار آن بروی آن عبارت کلیک کنید ، در همین حال یک text box ظاهر می‌شود و می‌توانید مقدار جدید را وارد کنید. پس از انجام ویرایش مورد نظر بروی قسمتی از صفحه کلیک کنید یا کلید Tab سپس Esc را بزنید. برای ویرایش دستورات بعدی ، کلید Tab را بزنید و برای لغو تغییر جاری ، کلید Esc را بزنید.

برای ایجاد یک rule جدید ، بروی قسمتی از پنل راست کلیک کرده و سپس گزینه‌ی "New Rule..." را برگزینید.
برای ایجاد یک property هم چند راه وجود دارد:

  • بروی قسمت از فضای خالی تعریف یک استایل دوبار کلیک کنید.
  • در قسمتی از تعریف یک استایل راست کلیک کرده و گزینه‌ی "New Property..." را انتخاب کنید.
  • بروی مقدار آخرین property کلیک کرده و کلید Tab را بزنید.


هنگام ویرایش یا ایجاد یک Rule , Propery یا مقدار بصورت inline ، حاشیه‌ی text box متناسب با مقدار وارد شده رنگی را که نمایانگر حالت ذخیره‌ی مقدار وارد شده است نمایش می‌دهد. برای مثال اگر مقداری که برای یک selector وارد شده است نامعتبر باشد ، رنگ حاشیه‌ی text box قرمز می‌شود.
جدول زیر حالت‌های مختلف را شرح می‌دهد:

رنگ حاشیه
Selectorها
نام Properyها
مقادیر Propertyها و Ruleها
 خاکستری تغییری ایجاد نشده استتغییری ایجاد نشده است
تغییری ایجاد نشده است
 قرمز selector نامعتبر است
نام نامعتبر است
مقدار نامعتبر است
 زرد selector صحیح است اما بروی Element فعلی تاثیر ندارد
نام صحیح است اما مقدار Property غیر مجاز است یا وارد نشده است
 
 سبز selector صحیح است نام و مقدار صحیح هستند
مقدار صحیح است


Auto-completion
زمانی که در حال ایجاد/ویراش کردن یک Rule, Propery یا مقدار آنها هستید ، میتوانید از این قابلیت استفاده کنید. مثلا با وارد کردن # تمام Selector هایی که می‌توانند با # شروع شوند در دسترس شما هستند و با دکمه‌های Up/Down می‌توانید مقادیر ممکن را مرور کنید.
اگر در حال ویرایش یک مقدار عددی هستید ، می‌توانید با دکمه‌های Up/Down مقادیر را یک واحد یک واحد افزایش دهید. با نگه داشتن کلید Shift و فشردن Up/Down می‌توانید مقادیر را 10تا 10تا تغییر دهید و با نگه داشتن Ctrl بجای Sihft ، یک دهم یک دهم.

Toggling styles
با این امکان می‌توانید یک Property را بطور موقت فعال/غیرفعال کنید. با حرکت موس از یک Property یک آیکون قرمز رنگ در کنار آن نمایش داده می‌شود که با کلیک بروی آن ، Property و مقدار آن کمرنگ شده و آیکون قرمز رنگ کنار آن ثابت می‌شود. با کلیک مجدد بروی آن ، Property فعال می‌شود.



Context Menu
این منو زمانی که در پنل راست کلیک کنید ظاهر می‌شود و نسبت به منطقه (Context)ای که در آن راست کلیک کرده اید ، گزینه‌های متفاوتی را مشاهده خواهید کرد. در جدول زیر ، گزینه‌ها ، Contextشان و توضیح هر گزینه آمده است.

 گزینهContext
توضیحات
Copy Location
CSS Location Menuآدرس فایل استایل را در حافظه کپی می‌کند.
Open in New TabCSS Location Menuفایل استایل را در یک تب جدید باز می‌کند.
Copy Image Location
image valuesآدرس تصویر را در حافظه کپی می‌کند.
Open Image in New Tabimage valuesتصویر را در یک تب جدید باز می‌کند.
Copy Colorcolor valuesمقدار رنگ را در حافظه کپی می‌کند.
Copy Rule DeclarationCSS selectorSelector و Propertyها را در حافظه کپی می‌کند.
Copy Style DeclarationCSS selectorفقط Propertyها را در حافظه کپی می‌کند.
New Rule...
همه جای پنل
یک Rule جدید بالای قسمتی که راست کلیک شده ایجاد می‌کند.
Delete "<selector>"
CSS selectorRule را حذف می‌کند.
New Property...
CSS rule
یک Property جدید در Ruleی که در آن راست کلیک شده ایجاد می‌کند.
Edit "<property name>"...
CSS property
Property فعلی به حالت ویرایش درمی آید. ( راه ساده‌تر ، کلیک بروی Property است. )
Delete "<property name>"...CSS propertyProperty فعلی را حذف می‌کند.
Disable "<property name>"...
CSS property
Property فعلی را غیرفعال می‌کند.
Refreshهمه جای پنل
محتویات پنل را بروز رسانی می‌کند.
Inspect in DOM panel
CSS Location Menu, CSS rule
فایل استایل یا Rule را در پنل DOM باز می‌کند.


Elements Side Panel
در این پنل که سمت راست پنل CSS قرار دارد ، با وارد کردن یک CSS Selector می‌توانید Elementهایی که در صفحه با آن مطابقت دارند را مشاهده کنید.
برای وارد کردن CSS Selector هم می‌توان مقدار مورد نظر را در قسمت Try a selector... وارد کرد هم می‌توان بروی یکی از Selectorهای پنل راست کلیک کرد و گزینه‌ی Get Matching Elements را برگزید.
Context Menu این قسمت هم مشابه Context Menu پنل HTML هست و فقط در ورژن 1.11 گزینه‌ی Paste HTML اضافه شده که در این کامنت از مقاله‌ی آموزش فایرباگ - #5 - HTML Panel توضیح داده شده است.