اشتراک‌ها
کتاب Bing Maps V8 Succinctly

At least 80% of all information being collected by enterprises includes geolocation data. The Bing Maps V8 library is a very large collection of JavaScript code that allows web developers to place a map on a webpage, query for data, and manipulate objects on a map, creating a geo-application. In Bing Maps V8 Succinctly, James McCaffrey takes readers through utilizing this library, from creating the simplest application that uses it, to mastering more advanced functions like creating color-gradient legends and custom-styled Infobox objects.

Table of Contents
  1. Getting Started
  2. Fundamental Techniques
  3. Working with Data
  4. Advanced Techniques 
کتاب Bing Maps V8 Succinctly
اشتراک‌ها
تمرکز اصلی در امکانات پیش روی Visual Studio بر DotNET Core میباشد

.NET Core, the reinvention of the Microsoft .NET Framework as an open source, cross-platform development choice, is a key focus of the upcoming features planned for the Visual Studio IDE.

In conjunction with .NET Standard -- a spec detailing what .NET APIs should be available on all .NET implementations -- .NET Core retains compatibility with .NET Framework, Xamarin and Mono while letting developers use Windows, macOS or Linux machines to code for mobile, cloud and embedded/IoT projects.

While still primarily driven by Microsoft dev teams, .NET Core is hosted on a GitHub repository and is supported by the .NET Foundation, an independent organization created by Microsoft three years ago to improve its open source development and collaboration.

Peeking at the Visual Studio Roadmap (updated last week) reveals .NET Core figures prominently in upcoming functionality for the IDE, both in the near-term and long:  

تمرکز اصلی در امکانات پیش روی Visual Studio بر DotNET Core میباشد
اشتراک‌ها
لیستی از SQL Memes

A meme is an idea, behavior, or style that spreads from person to person within a culture—often with the aim of conveying a particular phenomenon, theme, or meaning represented by the meme.

لیستی از SQL Memes
اشتراک‌ها
فرآیند رندر شدن در Angular2
So how exactly is Angular2 built such that it allows for custom renderers to be created? The first thing to understand is that the internal bits of Angular2 are split into two areas: the worker (core) area and the UI area. The worker (core) area is responsible for building out the components, directives, filters, services and bootstrap code; The UI area is responible for rendering out the application in the DOM.
فرآیند رندر شدن در Angular2
مطالب
Blazor 5x - قسمت 18 - کار با فرم‌ها - بخش 6 - حذف اطلاعات
در این قسمت می‌خواهیم اطلاعات اتاق‌های ثبت شده را به همراه تصاویر مرتبط با آن‌ها، حذف کنیم و همچنین به یک خطای مهم در حین کار با EF-Core برسیم و متوجه شویم که روش کار با DbContext در برنامه‌های مبتنی بر Blazor Server .... با روش کار متداول با آن در برنامه‌های Web API، یکی نیست!


مشکل حذف تصاویر آپلود شده

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


حذف اطلاعات تصاویر، در حالت ثبت اطلاعات


زمانیکه قرار است اطلاعات اتاقی برای اولین بار ثبت شود، حذف تصاویر آپلود شده‌ی مرتبط با آن ساده‌است؛ چون هنوز اصل رکورد اتاق ثبت نشده‌است و این تصاویر در این لحظه، به رکوردی تعلق ندارند. بنابراین ابتدا متد رویدادگردان DeletePhoto را به دکمه‌ی حذف اطلاعات هر تصویر نمایش داده شده، انتساب می‌دهیم:
@if (HotelRoomModel.HotelRoomImages.Count > 0)
{
    var serial = 1;
    foreach (var roomImage in HotelRoomModel.HotelRoomImages)
    {
        <div class="col-md-2 mt-3">
            <div class="room-image" style="background: url('@roomImage.RoomImageUrl') 50% 50%; ">
                <span class="room-image-title">@serial</span>
            </div>
            <button type="button"
                    @onclick="()=>DeletePhoto(roomImage)"
                    class="btn btn-outline-danger btn-block mt-4">Delete</button>
        </div>
        serial++;
    }
}
و سپس آن‌را به صورت زیر تکمیل می‌کنیم:
@code
{
    private const string UploadFolder = "Uploads";

    private void DeletePhoto(HotelRoomImageDTO imageDto)
    {
        var imageFileName = imageDto.RoomImageUrl.Replace($"{UploadFolder}/", "", StringComparison.OrdinalIgnoreCase);
        if (HotelRoomModel.Id == 0 && Title == "Create")
        {
            FileUploadService.DeleteFile(imageFileName, WebHostEnvironment.WebRootPath, UploadFolder);
            HotelRoomModel.HotelRoomImages.Remove(imageDto);
        }
    }
}
- با هر بار کلیک بر روی دکمه‌ی Delete، شیء HotelRoomImageDTO متناظری به متد DeletePhoto ارسال می‌شود.
- در این شیء، مقدار خاصیت RoomImageUrl، همواره با نام پوشه‌ای که فایل‌های تصویری در آن آپلود شده‌اند، شروع می‌شود. به همین جهت نام پوشه را از آن حذف کرده و بر این اساس، متد FileUploadService.DeleteFile را فراخوانی می‌کنیم تا تصویر جاری را از سرور حذف کند.
- سپس با فراخوانی متد Remove بر روی لیست تصاویر موجود، سبب به روز رسانی UI نیز خواهیم شد و به این ترتیب، تصویری که فایل آن از سرور حذف شده، از UI نیز حذف خواهد شد.


حذف تصاویر، در زمان ویرایش اطلاعات یک اتاق تعریف شده

همانطور که در ابتدای بحث نیز عنوان شد، نمی‌خواهیم در حالت ویرایش یک رکورد، با کلیک بر روی حذف یک تصویر، بلافاصله آن‌را از سرور نیز حذف کنیم. چون ممکن است کاربری تصویری را حذف کند، اما بجای ذخیره سازی اطلاعات رکورد، بر روی دکمه‌ی back کلیک کند. بنابراین در اینجا حذف تصاویر را صرفا به حذف آن‌ها از UI محدود می‌کنیم و حذف نهایی را به زمان کلیک بر روی دکمه‌ی ذخیره سازی اطلاعات در حال ویرایش، موکول خواهیم کرد.
به همین جهت در ابتدا با کلیک بر روی دکمه‌ی حذف، ابتدا با حذف آن تصویر از HotelRoomImages، سبب به روز رسانی UI خواهیم شد، اما این تصویر را واقعا حذف نمی‌کنیم. در اینجا فقط نام آن‌را در یک لیست، برای حذف نهایی، ذخیره سازی خواهیم کرد:
@code
{
    private List<string> DeletedImageFileNames = new List<string>();

    private void DeletePhoto(HotelRoomImageDTO imageDto)
    {
        var imageFileName = imageDto.RoomImageUrl.Replace($"{UploadFolder}/", "", StringComparison.OrdinalIgnoreCase);
        if (HotelRoomModel.Id == 0 && Title == "Create")
        {
            // ...              
        }
        else
        {
            // Edit Mode
            DeletedImageFileNames.Add(imageFileName);
            HotelRoomModel.HotelRoomImages.Remove(imageDto); // Update UI
        }
    }
به این ترتیب اگر کاربر بر روی دکمه‌ی back کلیک کند، اتفاق خاصی رخ نمی‌دهد؛ نه رکوردی از بانک اطلاعاتی و نه فایل تصویری از سرور حذف می‌شود.

سپس در جائیکه کار مدیریت ثبت اطلاعات صورت می‌گیرد، پس از به روز رسانی رکورد متناظر با یک اتاق، بر اساس لیست DeletedImageFileNames، فایل‌های علامتگذاری شده‌ی برای حذف را نیز واقعا از سرور حذف می‌کنیم:
    private async Task HandleHotelRoomUpsert()
    {
        // ...
 
        if (HotelRoomModel.Id != 0 && Title == "Update")
        {
            // Update Mode
            var updatedRoomDto = await HotelRoomService.UpdateHotelRoomAsync(HotelRoomModel.Id, HotelRoomModel);

            foreach(var imageFileName in DeletedImageFileNames)
            {
                FileUploadService.DeleteFile(imageFileName, WebHostEnvironment.WebRootPath, UploadFolder);
            }

            // await AddHotelRoomImageAsync(updatedRoomDto);
            await JsRuntime.ToastrSuccess($"The `{HotelRoomModel.Name}` updated successfully.");
        }
        else
        {
           // ... 
        }
    }
}
در اینجا باز هم نیازی نیست تا یک حلقه را تشکیل دهیم و اطلاعات را مستقیما از جدول تصاویر حذف کنیم. HotelRoomModel ارسال شده‌ی به متد UpdateHotelRoomAsync، چون به همراه لیست جدید HotelRoomImages است (که توسط فراخوانی HotelRoomModel.HotelRoomImages.Remove به روز شده‌است)، در حین Update، تصاویری که در این لیست وجود نداشته باشند، به صورت خودکار توسط EF-Core از سر دیگر رابطه حذف می‌شوند.


نمایش «لطفا منتظر بمانید» در حین آپلود تصاویر

در ادامه می‌خواهیم تا پایان نمایش آپلود تصاویر، پیام «لطفا منتظر بمانید» را به همراه یک spinner نمایش دهیم. بنابراین در ابتدا کلاس‌های جدید زیر را به فایل wwwroot\css\site.css اضافه می‌کنیم:
.spinner {
  border: 16px solid silver !important;
  border-top: 16px solid #337ab7 !important;
  border-radius: 50% !important;
  width: 80px !important;
  height: 80px !important;
  animation: spin 700ms linear infinite !important;
  top: 50% !important;
  left: 50% !important;
  transform: translate(-50%, -50%);
  position: absolute !important;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}
سپس برای مدیریت نمایش spinner فوق، در ابتدای کار آپلود، فیلدIsImageUploadProcessStarted را به true تنظیم کرده و در پایان کار، آن‌را false می‌کنیم. به همین جهت نیاز به یک try/finally خواهد بود:
@code
{
    private bool IsImageUploadProcessStarted;

    private async Task HandleImageUpload(InputFileChangeEventArgs args)
    {
        try
        {
            IsImageUploadProcessStarted = true;
            // ...
        }
        finally
        {
            IsImageUploadProcessStarted = false;
        }
    }
}
پس از آن فقط کافی است بر اساس مقدار جاری این فیلد، ذیل فیلد InputFile، پیامی را نمایش دهیم:
<InputFile OnChange="HandleImageUpload" multiple></InputFile>
<div class="row">
@if (IsImageUploadProcessStarted)
{
    <div class="col-md-12">
        <span><i class="spinner"></i> Please wait.. Images are uploading...</span>
    </div>
}

دریافت تائیدیه‌ی حذف، پس از کلیک بر روی دکمه‌های حذف تصاویر


در قسمت 12 این سری، کامپوننت Confirmation.razor را توسعه دادیم. در اینجا می‌خواهیم با کلیک بر روی دکمه‌ها‌ی حذف تصاویر، ابتدا توسط این کامپوننت، تائیدیه‌ای دریافت شود و در صورت تائید، آن تصویر انتخابی را حذف کنیم.
به همین جهت در ابتدا فایل Confirmation.razor را به پوشه‌ی جدید Pages\Components کپی می‌کنیم. سپس فضای نام آن‌را به فایل BlazorServer\BlazorServer.App\_Imports.razor اضافه می‌کنیم تا در تمام کامپوننت‌های برنامه قابل استفاده شود:
@using BlazorServer.App.Pages.Components
سپس در ابتدا کامپوننت Confirmation را به صورت زیر اضافه می‌کنیم:
<Confirmation @ref="Confirmation1"
    OnCancel="OnCancelDeleteImageClicked"
    OnConfirm="@(()=>OnConfirmDeleteImageClicked(ImageToBeDeleted))">
    <div>
        Do you want to delete @ImageToBeDeleted?.RoomImageUrl image?
    </div>
</Confirmation>
- ref تعریف شده سبب می‌شود تا بتوان متدهای عمومی تعریف شده‌ی در این کامپوننت، مانند Show و Hide را فراخوانی کرد.
- سپس روال‌های رویدادگردان OnCancel و OnConfirm به متدهایی در کامپوننت جاری متصل شده‌اند.
- در آخر پیامی تعریف شده‌است.

برای اینکه کامپوننت فوق عمل کند، نیاز است تغییرات زیر را به قسمت کدها اعمال کنیم:
    private Confirmation Confirmation1;
    private HotelRoomImageDTO ImageToBeDeleted;

    private void OnCancelDeleteImageClicked()
    {
        // Confirmation1.Hide();
    }

    private void DeletePhoto(HotelRoomImageDTO imageDto)
    {
        ImageToBeDeleted = imageDto;
        Confirmation1.Show();
    }

    private void OnConfirmDeleteImageClicked(HotelRoomImageDTO imageDto)
    {
- توسط وهله‌ی Confirmation1، می‌توان متد Show را زمانیکه بر روی دکمه‌ی Delete هر تصویر کلیک می‌شود، فراخوانی کنیم. قبل از آن مشخصات شیء تصویر درخواستی را در فیلد ImageToBeDeleted ذخیره می‌کنیم تا پس از تائید کاربر، دقیقا بر اساس اطلاعات آن بتوانیم متد OnConfirmDeleteImageClicked را پردازش کنیم.
- در اینجا محتوای متد DeletePhoto اصلی را (متدی را که تا پیش از این مرحله تکمیل کردیم) به متد جدید OnConfirmDeleteImageClicked منتقل کرده‌ایم. یعنی در ابتدا فقط یک modal نمایش داده می‌شود. پس از اینکه کاربر عملیات حذف را تائید کرد، رویداد OnConfirm، سبب فراخوانی متد OnConfirmDeleteImageClicked خواهد شد (که همان DeletePhoto قبل از این تغییرات است).


حذف کامل یک اتاق به همراه تمام تصاویر منتسب به آن

مرحله‌ی آخر این قسمت، اضافه کردن دکمه‌ی حذف، به ردیف‌های کامپوننت نمایش لیست اتاق‌ها است که این مورد نیز باید به همراه دریافت تائیدیه‌ی حذف و همچنین حذف تمام وابستگی‌های اتاق ثبت شده باشد:
<td>
    <NavLink href="@($"hotel-room/edit/{room.Id}")" class="btn btn-primary">Edit</NavLink>
    <button class="btn btn-danger" @onclick="()=>HandleDeleteRoom(room)">Delete</button>
</td>
در کامپوننت BlazorServer\BlazorServer.App\Pages\HotelRoom\HotelRoomList.razor، دکمه‌ی Delete را به نحو فوق اضافه کرده‌ایم که با کلیک بر روی آن، روال رویدادگردان HandleDeleteRoom اجرا شده و room متناظری را دریافت می‌کند.
اکنون برای مدیریت دریافت تائیدیه‌ی حذف از کاربر، کامپوننت Confirmation را اضافه کرده:
<Confirmation @ref="Confirmation1"
    OnCancel="OnCancelDeleteRoomClicked"
    OnConfirm="OnConfirmDeleteRoomClicked">
    <div>
        Do you want to delete @RoomToBeDeleted?.Name?
    </div>
</Confirmation>
و به نحو زیر تکمیل می‌کنیم:
@code
{
    private List<HotelRoomDTO> HotelRooms = new List<HotelRoomDTO>();
    private HotelRoomDTO RoomToBeDeleted;
    private Confirmation Confirmation1;

    private void OnCancelDeleteRoomClicked()
    {
        // Confirmation1.Hide();
    }

    private void HandleDeleteRoom(HotelRoomDTO roomDto)
    {
        RoomToBeDeleted = roomDto;
        Confirmation1.Show();
    }

    private async Task OnConfirmDeleteRoomClicked()
    {
        if(RoomToBeDeleted is null)
        {
            return;
        }

        await HotelRoomService.DeleteHotelRoomAsync(RoomToBeDeleted.Id);
        HotelRooms.Remove(RoomToBeDeleted); // Update UI
    }
با کلیک بر روی دکمه‌ی حذف، متد HandleDeleteRoom اجرا شده و فیلد RoomToBeDeleted را مقدار دهی می‌کند. از این فیلد پس از دریافت تائید، در متد OnConfirmDeleteRoomClicked برای حذف اتاق انتخابی استفاده شده‌است.

مشکل! این روش استفاده‌ی از DbContext کار نمی‌کند!

اگر برنامه را اجرا کرده و سعی در حذف یک ردیف کنیم، به خطای زیر می‌رسیم:
An exception occurred while iterating over the results of a query for context type 'BlazorServer.DataAccess.ApplicationDbContext'.
System.InvalidOperationException: A second operation was started on this context before a previous operation completed.
This is usually caused by different threads concurrently using the same instance of DbContext.
For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
عنوان می‌کند که متد OnConfirmDeleteRoomClicked، بر روی ترد دیگری نسبت به ترد اولیه‌ای که DbContext بر روی آن ایجاد شده، در حال اجرا است و چون DbContext برای یک چنین سناریوهایی، thread-safe نیست، اجازه‌ی استفاده‌ی از آن‌را نمی‌دهد. در مورد روش حل این مشکل ویژه، در قسمت بعد بحث خواهیم کرد.

کدهای کامل این مطلب را از اینجا می‌توانید دریافت کنید: Blazor-5x-Part-18.zip
پاسخ به بازخورد‌های پروژه‌ها
خطا و راهنمایی
جناب نصیری بابت راهنمایی تشکر می‌کنم مشکلات فوق برطرف شد اما یه سری دیگه از خطاها بوجود اومد به شرح زیر لطفا مجددا راهنمایی بفرمائید
خطای زیر در فایل xaml درست عنوان شده اما ...
Error1Cannot create an instance of "Browser"....\Samples\DemosBrowser\MainWindow.xaml99DemosBrowser
Could not find a part of the path 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Pdf\AccountingBalanceSample.pdf'.

   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)

   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)

   at PdfRpt.FluentInterface.DataTemplate.get_PdfStreamOutput() in ...\Lib\FluentInterface\DataTemplate.cs:line 605

   at PdfRpt.PdfReportDocument.createPdf() in ...\Lib\PdfReportDocument.cs:line 119

   at PdfRpt.PdfReportDocument.<runInReleaseMode>b__0(Document pdfDisposable) in ...\Lib\PdfReportDocument.cs:line 113

   at PdfRpt.Core.Helper.Guard.SafeUsingBlock[TDisposable,T](TDisposable disposable, Action`1 action, Func`2 unwrapper) in ...\Lib\Core\Helper\Guard.cs:line 91

   at PdfRpt.Core.Helper.Guard.SafeUsingBlock[TDisposable](TDisposable disposable, Action`1 action) in ...\Lib\Core\Helper\Guard.cs:line 58

   at PdfRpt.PdfReportDocument.runInReleaseMode() in ...\Lib\PdfReportDocument.cs:line 105

   at PdfRpt.PdfReportDocument.GeneratePdf(Boolean debugMode) in ...\Lib\PdfReportDocument.cs:line 87

   at PdfRpt.FluentInterface.PdfReport.Generate(Action`1 pdfRptFileBuilder, Boolean debugMode) in ...\Lib\FluentInterface\PdfReport.cs:line 90

   at PdfReportSamples.AccountingBalanceColumn.AccountingBalanceColumnPdfReport.CreatePdfReport() in ...\Samples\PdfReportSamples\AccountingBalanceColumn\AccountingBalanceColumnPdfReport.cs:line 17
ارجاع به dllهای زیر درست است اما..
Warning4Could not resolve this reference. Could not locate the assembly "System.Windows.Controls.Toolkit, Version=4.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.SlPdf
Warning5Could not resolve this reference. Could not locate the assembly "System.Windows.Controls.Toolkit.Internals, Version=4.0.5.0, Culture=neutral, PublicKeyToken=2c5c654d367bf4a7". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.SlPdf
Error1The type or namespace name 'BusyIndicator' could not be found (are you missing a using directive or an assembly reference?)...\Samples\SlPdf\SlPdf\obj\Debug\MainPage.g.i.cs3818SlPdf
Warning2The variable 'ex' is declared but never used...\Samples\DemosBrowser\Converters\ShellThumbnailConverter.cs4030DemosBrowser
با تشکر
اشتراک‌ها
Visual Studio 2019 version 16.6.2 منتشر شد

Security Advisory Notice for 16.6.2

CVE-2020-1108 / CVE-2020-1108.NET Core Denial of Service Vulnerability

To comprehensively address CVE-2020-1108, Microsoft has released updates for .NET Core 2.1 and .NET Core 3.1. Customers who use any of these versions of .NET Core should install the latest version of .NET Core. See the Release Notes for the latest version numbers and instructions for updating .NET Core.

CVE-2020-1202 / CVE-2020-1203 Diagnostics Hub Standard Collector Service Elevation of Privilege Vulnerability

An elevation of privilege vulnerability exists when the Diagnostics Hub Standard Collector or the Visual Studio Standard Collector fails to properly handle objects in memory.

CVE-2020-1293 / CVE-2020-1278 / CVE-2020-1257 Diagnostics Hub Standard Collector Service Elevation of Privilege Vulnerability

An elevation of privilege vulnerability exists when the Diagnostics Hub Standard Collector Service improperly handles file operations

Top Issues Fixed in Visual Studio 2019 version 16.6.2

Visual Studio 2019 version 16.6.2 منتشر شد
مطالب
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 6#
در ادامه پست پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 5# ، در این پست به تشریح کلاس دایره و بیضی می‌پردازیم.

ابتدا به تشریح کلاس ترسیم بیضی (Ellipse) می‌پردازیم.
using System.Drawing;

namespace PWS.ObjectOrientedPaint.Models
{
    /// <summary>
    /// Ellipse Draw
    /// </summary>
    public class Ellipse : Shape
    {
        #region Constructors (2)

        /// <summary>
        /// Initializes a new instance of the <see cref="Ellipse" /> class.
        /// </summary>
        /// <param name="startPoint">The start point.</param>
        /// <param name="endPoint">The end point.</param>
        /// <param name="zIndex">Index of the z.</param>
        /// <param name="foreColor">Color of the fore.</param>
        /// <param name="thickness">The thickness.</param>
        /// <param name="isFill">if set to <c>true</c> [is fill].</param>
        /// <param name="backgroundColor">Color of the background.</param>
        public Ellipse(PointF startPoint, PointF endPoint, int zIndex, Color foreColor, byte thickness, bool isFill, Color backgroundColor)
            : base(startPoint, endPoint, zIndex, foreColor, thickness, isFill, backgroundColor)
        {
            ShapeType = ShapeType.Ellipse;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Ellipse" /> class.
        /// </summary>
        public Ellipse()
        {
            ShapeType = ShapeType.Ellipse;
        }

        #endregion Constructors

        #region Methods (1)

        // Public Methods (1) 

        /// <summary>
        /// Draws the specified g.
        /// </summary>
        /// <param name="g">The g.</param>
        public override void Draw(Graphics g)
        {
            if (IsFill)
                g.FillEllipse(BackgroundBrush, StartPoint.X, StartPoint.Y, Width, Height);
            g.DrawEllipse(Pen, StartPoint.X, StartPoint.Y, Width, Height);
            base.Draw(g);
        }

        #endregion Methods
    }
}
این کلاس از شی Shape ارث برده و دارای دو سازنده ساده می‌باشد که نوع شی ترسیمی را مشخص می‌کنند، در متد Draw نیز با توجه به توپر یا توخالی بودن شی ترسیم آن انجام میشود، در این کلاس باید متد HasPointInShape بازنویسی (override) شود، در این متد باید تعیین شود که یک نقطه در داخل بیضی قرار گرفته است یا خیر که متاسفانه فرمول بیضی خاطرم نبود. البته به صورت پیش فرض نقطه با توجه به چهارگوشی که بیضی را احاطه می‌کند سنجیده می‌شود.

کلاس دایره (Circle) از کلاس بالا (Ellipse) ارث بری دارد که کد آن را در زیر مشاهده می‌نمایید.
using System;
using System.Drawing;

namespace PWS.ObjectOrientedPaint.Models
{
    /// <summary>
    /// Circle
    /// </summary>
    public class Circle : Ellipse
    {
#region Constructors (2) 

        /// <summary>
        /// Initializes a new instance of the <see cref="Circle" /> class.
        /// </summary>
        /// <param name="startPoint">The start point.</param>
        /// <param name="endPoint">The end point.</param>
        /// <param name="zIndex">Index of the z.</param>
        /// <param name="foreColor">Color of the fore.</param>
        /// <param name="thickness">The thickness.</param>
        /// <param name="isFill">if set to <c>true</c> [is fill].</param>
        /// <param name="backgroundColor">Color of the background.</param>
        public Circle(PointF startPoint, PointF endPoint, int zIndex, Color foreColor, byte thickness, bool isFill, Color backgroundColor)
        {
            float x = 0, y = 0;
            float width = Math.Abs(endPoint.X - startPoint.X);
            float height = Math.Abs(endPoint.Y - startPoint.Y);
            if (startPoint.X <= endPoint.X && startPoint.Y <= endPoint.Y)
            {
                x = startPoint.X;
                y = startPoint.Y;
            }
            else if (startPoint.X >= endPoint.X && startPoint.Y >= endPoint.Y)
            {
                x = endPoint.X;
                y = endPoint.Y;
            }
            else if (startPoint.X >= endPoint.X && startPoint.Y <= endPoint.Y)
            {
                x = endPoint.X;
                y = startPoint.Y;
            }
            else if (startPoint.X <= endPoint.X && startPoint.Y >= endPoint.Y)
            {
                x = startPoint.X;
                y = endPoint.Y;
            }
            StartPoint = new PointF(x, y);
            var side = Math.Max(width, height);
            EndPoint = new PointF(x + side, y + side);
            ShapeType = ShapeType.Circle;
            Zindex = zIndex;
            ForeColor = foreColor;
            Thickness = thickness;
            BackgroundColor = backgroundColor;
            IsFill = isFill;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Circle" /> class.
        /// </summary>
        public Circle()
        {
            ShapeType = ShapeType.Circle;
        }

#endregion Constructors 

#region Methods (1) 

// Public Methods (1) 

        /// <summary>
        /// Points the in sahpe.
        /// </summary>
        /// <param name="point">The point.</param>
        /// <param name="tolerance">The tolerance.</param>
        /// <returns>
        ///   <c>true</c> if [has point in sahpe] [the specified point]; otherwise, <c>false</c>.
        /// </returns>
        public override bool HasPointInSahpe(PointF point, byte tolerance = 5)
        {
            float width = Math.Abs(EndPoint.X+tolerance - StartPoint.X-tolerance);
            float height = Math.Abs(EndPoint.Y+tolerance - StartPoint.Y-tolerance);
            float diagonal = Math.Max(height, width);
            float raduis = diagonal / 2;
            float dx = Math.Abs(point.X - (X + Width / 2));
            float dy = Math.Abs(point.Y - (Y + height / 2));
            return (dx + dy <= raduis);
        }

#endregion Methods 
    }
}
این کلاس شامل دو سازنده می‌باشد، که در سازنده اول با توجه به نقاط ایتدا و انتهای ترسیم شکل مقدار طول و عرض مستطیل احاطه کننده دایره محاسبه شده و باتوجه به آنها بزرگترین ضلع به عنوان قطر دایره در نظر گرفته می‌شود و EndPoint شکل مورد نظر تعیین می‌شود.

در متد HasPointInShape  با استفاده از فرمول دایره تعیین می‌شود که آیا نقطه پارامتر ورودی متد در داخل دایره واقع شده است یا خیر (جهت انتخاب شکل برای جابجایی یا تغییر اندازه).
در پست‌های بعد به پیاده سازی اینترفیس نرم افزار خواهیم پرداخت.

موفق و موید باشید

در ادامه مطالب قبل:
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 1# 
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 2# 
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 3#
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 4# 
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 5# 
اشتراک‌ها
بررسی جامع نگارش آزمایشی Azure DocumentDB

○ No sorting option, or a good paging story
○ SQL Injection, without any other alternative
○ Hard to deploy and to keep current with your codebase
○ Poor development story & no testing story
○ Poor client API
○ Lots of table scans
○ Limited queries and few optimization options
○ Single document transactions (from the client)
○ No cross collection transations at all
○ Very small document sizes allowed

بررسی جامع نگارش آزمایشی Azure DocumentDB