مطالب دوره‌ها
مثال‌هایی بیشتر از عملکرد پشته‌ای MSIL
بررسی عملکرد و کدهای IL یک متد

        ldarg.0
        stloc_0
L_0000:
        ldloc_0
        ldc_i4 5
        add
        stloc_0
        ldloc_0
        ldc_i4 15
        blt L_0000
        ldloc_0
        ret
به کدهای IL فوق دقت کنید. در ادامه قصد داریم عملکرد این متد را بررسی کرده و سپس سعی کنیم تا معادل سی شارپ آن‌را حدس بزنیم. (البته سعی کنید طوری مطلب را مطالعه کنید که ادامه بحث را در ابتدا مشاهده نکنید!)
این متد، یک مقدار int را دریافت کرده و با انجام محاسباتی بر روی آن، مقدار int دیگری را بازگشت می‌دهد.
کار با ldarg.0 شروع می‌شود. به این ترتیب آرگومان موجود در ایندکس صفر، بر روی پشته بارگذاری خواهد شد. فرض کنید ورودی 5 را به این متد ارسال کرده‌ایم.
سپس stloc_0 این مقدار را از پشته pop کرده و در یک متغیر محلی ذخیره می‌کند.
در ادامه برچسب L_0000 تعریف شده است. از برچسب‌ها برای انتقال جریان اجرایی برنامه استفاده می‌کنیم.
ldloc_0 به معنای بارگذاری متغیر محلی از ایندکس صفر است. به این ترتیب عدد 5 بر روی پشته ارزیابی قرار می‌گیرد.
توسط ldc_i4 5، یک i4 یا int 32 بیتی یا int ایی با 4 بایت، به عنوان یک عدد ثابت بارگذاری می‌شود. این عدد نیز بر روی پشته ارزیابی قرار می‌گیرد.
در ادامه با فراخوانی Add، دو مقدار قرار گرفته بر روی پشته pop شده و نتیجه 10؛ مجددا بر روی پشته قرار می‌گیرد.
stloc_0 سبب می‌شود تا این عدد 10 در یک متغیر محلی در ایندکس صفر ذخیره شود.
با فراخوانی ldloc_0، این متغیر محلی به پشته ارزیابی منتقل می‌شود.
به کمک ldc_i4 15، یک عدد صحیح 4 بایتی با مقدار ثابت 15 بارگذاری می‌شود.
در ادامه blt بررسی می‌کند که اگر 10 کوچکتر است از 15 ایی که بر روی پشته قرار گرفته، آنگاه جریان عملیات را به برچسب L_0000 منتقل می‌کند (پرش به برچسب صورت خواهد گرفت).
اگر با سایر زبان‌های اسمبلی کار کرده باشید با lt، gt و امثال آن به طور قطع آشنایی دارید. در اینجا blt به معنای branch less than equal است.
بنابراین در ادامه مجددا همین اعمال فوق تکرار خواهند شد تا به ارزیابی blt جهت دو مقدار 15 با 15 برسیم. از آنجائیکه اینبار 15 کوچکتر از 15 نیست، سطر پس از آن یعنی ldloc_0 اجرا می‌شود که معادل است با بارگذاری 15 به پشته ارزیابی و سپس return فراخوانی می‌شود تا این مقدار را بازگشت دهد.



خوب؛ آیا می‌توانید کدهای معادل سی‌شارپ آن‌را حدس بزنید؟!

        public static int Calculate(int x)
        {
            for (; x < 15; x += 5)
            {
            }
            return x;
        }
بله. متد محاسباتی که در ابتدای بحث کدهای IL آن‌را ملاحظه نمودید، یک چنین معادل سی‌شارپی دارد.


فراخوانی متدها در MSIL

برای فراخوانی متدها در کدهای IL از OpCode ایی به نام call استفاده می‌شود:
 ldstr "hello world"
call void [mscorlib]System.Console::WriteLine(string)
در این مثال توسط ldstr، یک رشته بارگذاری شده و سپس توسط call اطلاعات متدی که باید فراخوانی شود، ذکر می‌گردد. همانطور که ملاحظه می‌کنید، امضای کامل متد نیاز است ذکر گردد؛ متدی از نوع void قرار گرفته در mscorlib با ذکر فضای نام و نام متد مورد نظر.


بررسی یک الگوریتم بازگشتی در MSIL

ابتدا متد بازگشتی ذیل را درنظر بگیرید:
        public static int Calculate(int n)
        {
            if (n <= 1) return n;
            return n * Calculate(n - 1);
        }
اگر کد دی‌کامپایل شده‌ی آن را در ILSpy بررسی کنیم، به دستورات ذیل خواهیم رسید:
.method public hidebysig static 
int32 Calculate (
int32 n
) cil managed 
{
// Method begins at RVA 0x3c0d
// Code size 17 (0x11)
.maxstack 8

IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: bgt.s IL_0006

IL_0004: ldarg.0
IL_0005: ret

IL_0006: ldarg.0
IL_0007: ldarg.0
IL_0008: ldc.i4.1
IL_0009: sub
IL_000a: call int32 FastReflectionTests.Test::Calculate(int32)
IL_000f: mul
IL_0010: ret
} // end of method Test::Calculate
در اینجا ابتدا مقدار آرگومان متد، توسط ldarg بارگذاری می‌شود. سپس مقدار ثابت یک بارگذاری می‌شود. توسط bgt بررسی خواهد شد اگر مقدار آرگومان (عدد اول) بزرگتر است از مقدار عدد ثابت یک (عدد دوم)، آنگاه به برچسب IL_0006 پرش صورت گیرد و قسمت ضرب بازگشتی انجام شود. در غیراینصورت آرگومان متد بارگذاری شده و در سطر IL_0005 کار خاتمه می‌یابد.
در سطرهای IL_0006 و IL_0007، دوبار کار بارگذاری آرگومان متد انجام شده است؛ یکبار برای عملیات ضرب و بار دیگر برای عملیات تفریق از یک.
سپس عدد ثابت یک بارگذاری شده و از مقدار آرگومان، توسط sub کسر خواهد شد. در ادامه متد Calculate به صورت بازگشتی فراخونی می‌گردد. در این حالت دوباره به سطر IL_0000 هدایت خواهیم شد و عملیات ادامه می‌یابد.
مطالب
مقدمه ای بر CQRS و Event Sourcing
به صورت عام، functionality اکثر پروژه‌های نرم افزاری تجاری خلاصه میشود به مخفف معروفی به نام CRUD، که object‌ها را میسازیم، آن‌ها را میخوانیم و تغییر میدهیم.
اپلیکیشن‌های طراحی شده بدین صورت، قابلیت خوانایی بالایی خواهند داشت و دیاگرام طراحی آنها چیزی شبیه به تصویر زیر میباشد

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

زمانیکه نیاز‌های پروژه روز به روز افزورده و پیچیده‌تر میشود، مدل CRUD بصورت پیوسته از ارزشش کاسته میشود و از آن سادگی اولیه‌ی در درک و خوانایی آن دور خواهد شد.

ذات CQRS بر آن است که شما مدل‌های مختلفی را برای خواندن و نوشتن دیتا داشته باشید. الگوی آن چیزی شبیه به تصویر زیر است

چیزی که در این روش مشهود است این میباشد که برنامه نویسان باید قسمت‌های Command و Query را به صورت جداگانه طراحی نمایند.
CQRS این قابلیت را به شما میدهد که interface و Datastore و حتی بطور کامل Technology مجزایی در قسمت‌های CQ داشته باشید.

Event Sourcing
قسمت دوم و متمایز، معماری Event Sourcing یا ES میباشد که بصورت کوتاه، ES یک روش متفاوت برای Data storage میباشد.
اکثرا ما از Datastore‌هایی که مدلی از دیتا را انعکاس می‌دهند استفاده میکنیم. به مثال ساده‌ی زیر توجه کنید

ES از برنامه نویسان میخواهد که مدل سنتی CRUD را فراموش کرده و بجای آن تغییراتی را که روی دیتا صورت گرفته، نیز درج نمایند. اینکار به وسیله‌ی یک دیتابیس Append-only انجام میشود که به نام Event Store شناخته میشود.

در این معماری ما همه‌ی تغییرات روی دیتا را به صورت Serialize Event ذخیره میکنیم که میتواند دوباره در هر زمانی اجرا شده و current state هر objectی را در اختیار بگذارد.

این روش به ما کمک بزرگی میکند تا وضعیت یک object را در گذشته به راحتی پیدا کنیم و از آن میتوان به غیر از فوایدی که دارد، به عنوان یک Logger نیز استفاده نمود. به دلیل اینکه جزء به جزء تغییرات بر روی state سیستم، در آن ثبت شده است. از آنجاییکه دیتا بصورت serialize ذخیره میشود، بارگزاری آن نیز با سرعت بالایی انجام خواهد شد.

پس بصورت خلاصه در معماری Command Query Responsibility Segregation ابتدا باید به این موضوع توجه داشت که قسمت‌های Read و Write نرم افزار به صورت مجزایی طراحی میشوند و Event Sourcing شامل تغییراتی که روی data انجام شده است، میباشد و به‌صورت Serialize شده ذخیره میشود. ما تنها به یک دیتابیس و یک جدول برای نمایش event store نیازمندیم (بستگی به نیازتان میتوان تعداد آن را نیز بیشتر نمود و همچنین حتما لزومی ندارد که از دیتابیس‌های رابطه‌ای استفاده شود؛ بصورت مثال پیاده سازی این قسمت را میتوان با استفاده از Redis که دیتابیسی غیر رابطه‌ای و باسرعت میباشد استفاده نمود).
برای شروع کار (نه پیاده سازی کامل) باید با قسمت‌های مختلف طراحی در این معماری آشنا شویم:
Domain Object
نکته: SimpleCqrs فریم ورکی برای پیاده سازی معماری CQRS , ES میباشد که برای ساده‌تر شدن کار، از آن استفاده شده است (شما حتی میتوانید پیاده سازی خود را داشته باشید)
مدل Movie از کلاسی به نام AggregateRoot ارث بری کرده‌است که توسط SimpleCQRS پیاده سازی شده‌است و یک guid key در آن تعبیه شده است (Aggregate root از مباحث Domain Driven برگرفته شده است و آشنایی با آن کمک شایانی به درک عمیق‌تر روی این مباحث مینماید).
public class Movie : AggregateRoot  
{
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public int RunningTimeMinutes { get; set; }

    public Movie() { }

    public Movie(Guid movieId, string title, DateTime releaseDate, int runningTimeMinutes)
    {
        //پیاده سازی خواهد شد
    }
}
توجه: SimpleCQRS فقط پیاده سازی guid برای کلید مربوط به هر مدل را پیاده سازی نموده است؛ بنابراین کلید مدل نمیتواند integer باشد.

Commands
command دستوراتی است که توسط end user فراخوانی میشود که باعث تغییرات خواهد شد. وقتی اپلیکیشن یک command را دریافت مینماید، command handler به پردازش آن برای فهمیدن خواسته کاربر میپردازد و پس از آن event مربوطه را برای اجرای آن وظیفه‌ی خاص صدا میزند.
همه‌ی command‌ها تغییراتی بر روی state جاری خواهند داشت. در نتیجه دیتا‌های ذخیره شده درون دیتابیس تغییرات خواهند کرد. هر commandی که تغییری بر روی State سیستم نداشته باشد، یک دستور غلط محسوب شده و باید در سمت query‌ها آن را پیاده سازی نمود.
در نتیجه Commnad‌ها دستوراتی هستند که از طرف کاربر برای تغییرات بر روی دیتا‌های ذخیره شده، ارسال میشوند.
فرض کنید Domain Objectی برای Movie تعریف کرده‌ایم و میخواهیم دستور اضافه کردن فیلم را پیاده سازی نماییم
public class CreateMovieCommand : ICommand  
{
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public int RunningTimeMinutes { get; set; }
    public CreateMovieCommand(string title, DateTime releaseDate, int runningTime)
    {
        Title = title;
        ReleaseDate = releaseDate;
        RunningTimeMinutes = runningTime;
    }
}
توجه: ICommand از طریق SimpleCQRS اضافه شده‌است.

Command Handler
بعد از اینکه Command مورد نیاز نوشته شد، حال احتیاج به پیاده سازی CommandHandler مربوطه که دستور متناظر را پردازش میکند، داریم.
public class CreateMovieCommandHandler : CommandHandler<CreateMovieCommand>  
{
    protected IDomainRepository _repository;

    public CreateMovieCommandHandler(IDomainRepository repository)
    {
        _repository = repository;
    }

    public override void Handle(CreateMovieCommand command)  
    {
        var movie = new Domain.Movie(Guid.NewGuid(), command.Title, 
    command.ReleaseDate, command.RunningTimeMinutes);

        _repository.Save(movie);
    }
}
Command Handler باید از کلاس جنریک <CommandHandler<T ارث بری نماید و T باید از نوع Command در نظر گرفته شود و همچنین IDomainRepository اینترفیسی است که توسط SimpleCQRS تعریف شده‌است و ما احتیاجی به پیاده سازی آن نداریم (در قسمت‌های بعدی پیکربندی آن را انجام میدهیم).
برای رسیدگی کردن به دستور مربوطه احتیاج به override کردن متد Handle میباشد.
کار اساسی توسط متد Save انجام میشود که همه‌ی event‌های pending شده توسط Domain Object را گرفته و آنها را به Event Store میفرستد.

Events
event‌ها تغییراتی هستند بر روی State جاری سیستم که توسط کاربر به وسیله‌ی Commandها فراخوانی میشوند.
رویداد‌ها serialize میشوند و درون Event Store ذخیره میشوند؛ بنابراین میتوان فراخوانی آنها را در هر لحظه انجام داد.
هر تعداد Event میتواند توسط یک دستور raise شود.
ساخت یک Event:
قبلا دستوری را برای ساخت یک movie نوشتیم و حال احتیاج به event مربوطه را داریم:
public class MovieCreatedEvent : DomainEvent  
{
    public Guid MovieId
    {
        get { return AggregateRootId; }
        set { AggregateRootId = value;}
    }

    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public int RunningTimeMinutes { get; set; }

    public MovieCreatedEvent(Guid movieId, string title, DateTime releaseDate, int runningTime)
    {
        MovieId = movieId;
        Title = title;
        ReleaseDate = releaseDate;
        RunningTimeMinutes = runningTime;
    }
}
فراموش نکنید که این کلاس آبجکتی خواهد بود که Serialize شده و در دیتابیس ذخیره خواهد شد. باید همه‌ی پراپرتی‌های لازم که با استفاده از این Event ممکن است تغییر کنند را شامل شود (بدیهی است که این پراپرتی‌ها از Domain Object گرفته میشود).
public class Movie : AggregateRoot  
{
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public int RunningTimeMinutes { get; set; }

    public Movie(Guid movieId, string title, DateTime releaseDate, int runningTimeMinutes)
    {
        Apply(new MovieCreatedEvent(Guid.NewGuid(), title, releaseDate, runningTimeMinutes));
    }
}
به Aggregate فوق که در اوایل بحث صحبت شده‌است دقت کنید. حال متد Apply باعث میشود که event مربوطه درون بخش لوکال aggregate root ذخیره شود. بنابراین بعدا میتواند به صورت فیزیکی درون Event Store ذخیره شود.

Event Handler
هر Event Handler  میتواند تعداد زیادی از IHandleDomainEvents ‌ها را پیاده سازی نماید. حال متد Handle این اینترفیس را پیاده سازی نمودیم. 
public class MovieEventHandler : IHandleDomainEvents<MovieCreatedEvent>  
{
    public void Handle(MovieCreatedEvent createdEvent)
    {
        using (MoviesContext entities = new MoviesContext())
        {
            entities.Movies.Add(new Movie()
            {
                Id = createdEvent.AggregateRootId,
                Title = createdEvent.Title,
                ReleaseDate = createdEvent.ReleaseDate,
                RunningTimeMinutes = createdEvent.RunningTimeMinutes
            });

            entities.SaveChanges();
        }
    }
}
مثلا در این قسمت با استفاده از ORM، شیء مورد نظر به صورت فیزیکی درون دیتابیس ذخیره میشود.
در قسمت آخر نیازمندیم که تغییرات زیر را به Movie اضافه نماییم.
درون Doamin Objectی که قبلا تعریف کرده بودیم متدی را به صورت زیر پیاده سازی مینماییم
protected void OnMovieCreated(MovieCreatedEvent domainEvent)
        {
            Id = domainEvent.AggregateRootId;
            Title = domainEvent.Title;
            ReleaseDate = domainEvent.ReleaseDate;
            RunningTimeMinutes = domainEvent.RunningTimeMinutes;
        }
باعث میشود پس از فراخوانی شدن Event، تغییرات صورت گرفته‌ی بر state سیستم، بر روی Domain Object اعمال شود و آن را بروزرسانی نماید. این متد دقیقا بصورت اتوماتیک وقتی که event مربوطه raise میشود، فراخوانی میشود.
پس از ترکیب CQRS و ES معماری اولیه‌ی سیستم چیزی شبیه به دیاگرام زیر خواهد بود (بسته به سناریوهای خاص میتواند سفارشی سازی شود)

خلاصه:
کاربر دستوری را از طریق برنامه به سیستم ارسال مینماید.
command مربوطه دریافت میشود و به روی Command Bus قرار داده میشود.
Command Handler وظیفه‌ی تفسیر کردن Command مربوطه را به عهده میگیرد و به وسیله‌ی Domain object آن event مورد نظر فراخوانی خواهد شد و باعث میشود domain object بروزرسانی گردد.
Event همان objectی است که باید به صورت serialize شده درون append only database ذخیره شود.
Event handler رویداد مربوطه را گرفته و بصورت فیزیکی مقادیر مورد نظر را در دیتابیس ذخیره مینماید.

Query
از آنجاییکه قسمت Read، در سیستم به صورت CQRS طراحی میشود، به راحتی میتوان query‌ها را optimize کرده و به صورت مثال به جای استفاده از ORM‌های معمول بطور مستقیم Stored Procedure فراخوانی کرده، تا جای ممکن کیفیت query‌ها بهترین حالت ممکن باشند. در حالیکه در مدل CRUD بهینه کردن بخش read بسیار پیچیده و بعضا غیر ممکن میباشد.

مزایای استفاده از این مدل
Distributed Systems Capabilities
یکی از مهمترین مزیت‌های این مدل تسهیم گسترش پذیری سیستم بر روی ماشین‌های فیزیکی مختلف از طریق messaging pattern میباشد.
High Availability
از آنجایی که سیستم توزیع پذیر طراحی شده‌است، هر قسمت از آن میتواند بدون توجه به fail شدن قسمت‌های دیگر به کار خود ادامه دهد.
Reduce Complexity
در domain‌های پیچیده طراحی و پیاده سازی objectهایی که مسئول دو قسمت read و write هستند، میتواند کار را بیش از حد پیچیده کرده و در این صورت چون business logic و read logic در هم ترکیب میشوند، مدیریت کردن موارد multiple user, shared data, performance, transactions, consistency سخت و سخت‌تر میشود.
Facilitates Building Task-based UI
وقتی شما به پیاده سازی الگوی CQRS میپردازید، اصولا هر عملی که توسط End user از طریق ui ارسال میشود، معادل command مربوط به آن وجود دارد. به همین جهت میتوان عملیات لازم برای اجرای یک پروسه را بصورت واضحی درک کرد.
 Maintenance And Flexibility
هر چند پیاده سازی این مدل سخت خواهد بود، اما در ابعاد وسیع‌تر به دلیل اینکه هر قسمت به صورت مجزایی طراحی شده و اینکه دستورات و رویداد‌ها به صورت تفکیک شده پیاده سازی شده‌اند، همچنین وجود ES، قابلیت زیادی به debug سیستم می‌دهد.
نکته: ES مدل مورد قبولی برای اکثر معماری‌های نوین سیستم‌های نرم افزاری امروزی میباشد و فقط مختص به CQRS نمیباشد. بطور مثال در معماری Microservices به وفور از Event Sourcing استفاده میشود.

مشکلات استفاده از این مدل
  • ذاتا پیاده سازی این مدل سخت و دشوار است و از آنجاییکه سادگی در پیاده سازی سیستم‌های نرم افزاری، یک اصل مهم محسوب میشود، بنابراین استفاده از این مدل محدود میشود به سیستم‌های نرم افزاری که مزیت‌های گفته شده در قسمت فوق برایشان حیاتی محسوب شود.
  • برای پیاده سازی سیستمی با این مدل احتیاج به تیم توسعه‌ای است که با مفاهیم آن کاملا آشنا باشد.
  • هر چند امروزه فضای فیزیکی برای ذخیره سازی دیتا ارزان محسوب میشود، اما به هر حال استفاده از این مدل به همراه ES، حجم زیادی از Disk space را خواهد گرفت.
  • همانطور که دیدید برای پیاده سازی یک Insert ساده، حجم زیادی کد نوشته شده‌است. بنابراین تولید اینگونه نرم افزار‌ها به زمان بیشتری نیاز دارد.
بنابراین باید در انتخاب معماری سیستم بسیار دقت شود؛ هر چند که این مدل برای سیستم‌های بزرگ و پیچیده خیلی کارآمد محسوب میشود و باعث یک Domain object غنی ، History Tracking، شفافیت در مشکلات Concurrency و همچنین Scalability و غیره خواهد شد، اما پیدا کردن برنامه نویسانی با داشتن درک عمیق روی این مباحث کمی سخت به نظر میرسد.
در قسمت بعدی بصورت کامل به پیاده سازی این الگو در یک اپلیکشن دات نتی خواهیم پرداخت.
نظرات اشتراک‌ها
نگارش نهایی SQL Server 2016 منتشر شد
مانند نگارش‌های سال‌های قبل است. بر اساس کلید درج شده‌ی در فایل ISO، نوع نگارش مشخص می‌شود؛ یا می‌توانید این کلید را خودتان در نگارش 180 روزه وارد کنید. در اصل هیچ تفاوتی ندارند.
نظرات مطالب
غیرمعتبر شدن کوکی‌های برنامه‌های ASP.NET Core هاست شده‌ی در IIS پس از ری‌استارت آن
بعد از Expire شدن کلید چه اتفاقی برای اطلاعاتی که قبلا با کلید قبلی Encrypt شدن میافته؟
برای بخشی از اطلاعات از این روش برای رمزنگاری استفاده کردم آیا اون اطلاعات دیگر قابل خواندن نیست؟
نظرات مطالب
توسعه سیستم مدیریت محتوای DNTCms - قسمت ششم
خواهش میکنم.
فرض کنید در ادامه مدلی داشته باشیم که کلید آن ترکیبی است ؛ در آن صورت استفاده از BaseEntity که صراحتا کلید آن یک خصوصیت مشخص است ، قابل استفاده نخواهد بود.
البته شاید در ادامه همچین سناریویی وجود نداشته باشد.
نظرات مطالب
Persist ، Load و Bookmark در Workflow
سلام .ممنون از زحمتی که کشیدید.یک سوال کلید WorkFlowID در جدول User کلید خارجی از کدوم یک از جداول WF است؟ توی هیچ کدوم از جدول‌ها نیست!
نظرات مطالب
کار با کلیدهای اصلی و خارجی در EF Code first
درسته،ولی تو رابطه‌های one-to-one(و one-to-zero) هم این روش کاربرد نداره،چون کلید Dependent همین کلید خارچی میشه دیگه،اینم درسته دیگه؟
مطالب
OpenCVSharp #5
استفاده از پنجره‌ی native خود OpenCV، روش مرسومی است در زبان‌های مختلف برنامه نویسی که از OpenCV استفاده می‌کنند و این پنجره مستقل است از سکوی کاری مورد استفاده. اما شاید در دات نت علاقمند باشید که نتیجه‌ی عملیات را در یک picture box استاندارد نمایش دهید. در ادامه، تبدیل تصاویر OpenCV را به فرمت دات نت، در دو قالب برنامه‌های WinForms و همچنین WPF، بررسی خواهیم کرد.


استفاده از OpenCVSharp در برنامه‌های WinForms به کمک PictureBoxIpl

یکی از اسمبلی‌های کتابخانه‌ی OpenCVSharp را که در پوشه‌ی bin برنامه می‌توان مشاهده کرد، OpenCvSharp.UserInterface.dll نام دارد. این اسمبلی حاوی یک picture box جدید به نام PictureBoxIpl است که می‌تواند تصاویری را با فرمت IplImage، دریافت کند.


می‌توانید این picture box ویژه را از طریق منوی ToolBox -> Choose items و سپس صفحه‌ی دیالوگ فوق، به نوار ابزار WinForms اضافه کرده و از آن استفاده کنید و یا می‌توان با کدنویسی نیز به آن دسترسی یافت:
using (var iplImage = new IplImage(@"..\..\Images\Penguin.png", LoadMode.Color))
{
    Cv.Dilate(iplImage, iplImage);
 
    var pictureBoxIpl = new OpenCvSharp.UserInterface.PictureBoxIpl
    {
        ImageIpl = iplImage,
        AutoSize = true
    };
    flowLayoutPanel1.Controls.Add(pictureBoxIpl); 
}
در اینجا تصویر مورد نظر را توسط کلاس IplImage بارگذاری کرده و سپس برای نمونه فیلتر Dilate را به آن اعمال کرده‌ایم. سپس وهله‌ی جدیدی از کنترل PictureBoxIpl ایجاد و خاصیت ImageIpl آن، به تصویر بارگذاری شده، تنظیم و در آخر این picture box با کدنویسی به صفحه اضافه شده‌است.

یک نکته
هر نوع تغییری به iplImage پس از انتساب آن به خاصیت ImageIpl، نمایش داده نخواهد شد. برای به حداقل رساندن سربار ایجاد اشیاء جدید (خصوصا برای نمایش اطلاعات رسیده‌ی از دوربین یا WebCam)، از متد RefreshIplImage استفاده کنید. این متد بجای ایجاد یک شیء جدید، تنها ناحیه‌ی موجود را مجددا ترسیم خواهد کرد و بسیار سریع است:
 pictureBoxIpl.RefreshIplImage(iplImage);


استفاده از OpenCVSharp در برنامه‌های WinForms به کمک PictureBox

اگر نخواهید از کنترل جدید PictureBoxIpl استفاده کنید، می‌توان از همان Picture box استاندارد WinForms نیز کمک گرفت:
Bitmap bitmap;
using (var iplImage = new IplImage(@"..\..\Images\Penguin.png", LoadMode.Color))
{
    bitmap = iplImage.ToBitmap(); // BitmapConverter.ToBitmap()
}
 
var pictureBox = new PictureBox
{
    Image = bitmap,
    ClientSize = bitmap.Size
}; 
 
flowLayoutPanel1.Controls.Add(pictureBox);
تنها نکته‌ای که در اینجا جدید است، استفاده از متد الحاقی ToBitmap می‌باشد که در کلاس BitmapConverter کتابخانه‌ی OpenCVSharp تعریف شده‌است. به این ترتیب تصویر با فرمت OpenCV، به یک Bitmap دات نتی تبدیل می‌شود. اکنون می‌توان این بیت‌مپ را برای مثال به یک Picture box استاندارد انتساب داد و یا حتی متد Save آن‌را فراخوانی کرد و آن‌را بر روی دیسک سخت، ذخیره نمود.

یک نکته
در اینجا نیز برای به حداقل رسانی به روز رسانی‌های بعدی picture box بهتر است از متد ToBitmap به شکل زیر کمک گرفت:
 iplImage.ToBitmap(dst: (Bitmap)pictureBox.Image);
به این ترتیب سربار وهله سازی یک شیء جدید Bitmap حذف خواهد شد و صرفا ناحیه‌ی نمایشی مجددا ترسیم می‌شود.





استفاده از OpenCVSharp در برنامه‌های WPF

در WPF می‌توان با استفاده از متد الحاقی ToWriteableBitmap کلاس BitmapConverter، فرمت IplImage را به منبع تصویر یک کنترل تصویر استاندارد، تبدیل کرد:
using System.Windows.Media;
using OpenCvSharp;
using OpenCvSharp.Extensions;
 
namespace OpenCVSharpSample05Wpf
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            loadImage();
        }
 
        private void loadImage()
        {
            using (var iplImage = new IplImage(@"..\..\Images\Penguin.png", LoadMode.Color))
            {
                Cv.Dilate(iplImage, iplImage);
 
                Image1.Source = iplImage.ToWriteableBitmap(PixelFormats.Bgr24);
            }
        }
    }
}

کدهای کامل WPF و WinForms این مطلب برای دریافت.
مطالب
MVVM و فراخوانی متدهای اشیاء View از طریق ViewModel

ما در ViewModel دسترسی مستقیمی به هیچ یک از اشیاء موجود در View نداریم (و درستش هم همین است). الان فرض کنید که می‌خواهیم از طریق ViewModel یک View را ببندیم؛ مثلا متد Close آن پنجره را فراخوانی کنیم. به عبارتی در حالت کلی می‌خواهیم یکی از متدهای تعریف شده یکی از عناصر بصری موجود در View را از طریق ViewModel فراخوانی نمائیم.
برای حل این مساله از فایل‌های همان SDK‌ مرتبط با Expression blend استفاده خواهیم کرد.

ابتدا ارجاعاتی را به اسمبلی‌های System.Windows.Interactivity.dll و Microsoft.Expression.Interactions.dll اضافه می‌کنیم.
سپس دو فضای نام مرتبط هم باید اضافه شوند:

  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"  
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

یک مثال عملی:
قصد داریم از طریق ViewModel ، پنجره‌ای را ببندیم. کدهای XAML این مثال را در ادامه مشاهده خواهید کرد:

<Window x:Class="WpfCallMethodActionSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:vm="clr-namespace:WpfCallMethodActionSample.ViewModels"
Name="ThisWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<vm:MainWindowViewModel x:Key="vmMainWindowViewModel" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource vmMainWindowViewModel}}">

<Button Content="Save &amp; Close" VerticalAlignment="Top" Margin="5">
<i:Interaction.Triggers>
<!--فراخوانی متدی در ویوو مدل-->
<i:EventTrigger EventName="Click">
<ei:CallMethodAction
TargetObject="{Binding}"
MethodName="SaveButtonClicked" />
</i:EventTrigger>

<!--فراخوانی متدی در شیء جاری از طریق ویوو مدل-->
<i:EventTrigger SourceObject="{Binding}" EventName="CloseMainWindow">
<ei:CallMethodAction
TargetObject="{Binding ElementName=ThisWindow}"
MethodName="Close"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</Window>

همچنین ViewModel تعریف شده نیز همین چند سطر زیر است:

using System;

namespace WpfCallMethodActionSample.ViewModels
{
public class MainWindowViewModel
{
public void SaveButtonClicked()
{
close();
}

public event EventHandler CloseMainWindow;
private void close()
{
if (CloseMainWindow != null) CloseMainWindow(this, EventArgs.Empty);
}
}
}

توضیحات:
اگر به ViewModel دقت کنید خبری از DelegateCommand در آن نیست. بله، به کمک ترکیبی از EventTrigger و CallMethodAction می‌توان جایگزینی را جهت DelegateCommand معرفی شده در قسمت‌های قبل این سری مباحث MVVM ارائه داد.
EventTrigger در اینجا به این معنا است که اگر EventName ذکر شده رخ داد، آنگاه این اعمال را انجام بده. مثلا در اینجا CallMethodAction را فراخوانی کن.
CallMethodAction در اسمبلی Microsoft.Expression.Interactions.dll تعریف شده است و تنها متدی از نوع void و بدون پارامتر را می‌تواند به صورت خودکار فراخوانی کند (محدودیت مهم آن است).
اینکه این متد کجا قرار دارد، توسط TargetObject آن مشخص می‌شود. اگر TargetObject را مساوی Binding قرار دادیم، یعنی به دنبال متدی که در DataContext گرید وجود دارد بگرد. به عبارتی به صورت خودکار به SaveButtonClicked تعریف شده در ViewModel ما متصل خواهد شد و آن‌را فراخوانی می‌کند.

تا اینجا رخداد Click دکمه تعریف شده را به متد SaveButtonClicked موجود در ViewModel سیم کشی کردیم.

در مرحله بعد می‌خواهیم از طریق ViewModel ، متدی را در View فراخوانی کنیم. نکته آن هم پیشتر ذکر شد؛ TargetObject صحیحی را باید انتخاب کرد. در اینجا برای پنجره جاری نام ThisWindow تعریف شده است و از طریق تعریف:

TargetObject="{Binding ElementName=ThisWindow}"

به CallMethodAction خواهیم گفت که قرار است متد Close را در شیء ThisWindow فراخوانی کنی.
همچنین نحوه تعریف EventTrigger ما هم در اینجا برعکس شده است:

<i:EventTrigger SourceObject="{Binding}"  EventName="CloseMainWindow">

قبلا به دنبال مثلا رخداد Click یک دکمه بودیم، اکنون با توجه به SourceObject تعریف شده، در ViewModel به دنبال این رخداد که برای نمونه در اینجا CloseMainWindow نام گرفته خواهیم گشت.

بنابراین View اینبار به رخداد CloseMainWindow تعریف شده در ViewModel سیم کشی خواهد شد. اکنون اگر این رخداد در ViewModel فراخوانی شود، CallMethodAction متناظر فعال شده و متد Close پنجره را فراخوانی می‌کند.

مطالب
4# آموزش سیستم مدیریت کد Git : نصب و پیکر‌‏بندی
برای نصب Git ابتدا به msysgit رفته و مطابق شکل زیر بر روی گزینه دانلود کلیک کنید. سپس در صفحه باز شده آخرین نسخه Git را دانلود نموده و فایل مربوطه را اجرا کنید:

شروع نصب:

--------------  

در این مرحله بخش Windows Explorer Integration اهمیت دارد. در صورت انتخاب این بخش، بعد از نصب، Git Bash و Git GUI به منوی راست کلیک شما اضافه می‏‌شود. به این ترتیب با سرعت بیشتری می‏توانید به Git در یک  پوشه خاص دسترسی داشته باشید.

--------------
در این مرحله از شما خواسته می‏‌شود تعیین کنید که آیا فقط می‏‌خواهید از طریق Git Bash با Git کار کنید یا با اضافه کردن فایل اجرایی Git به متغیر‏های محلی ویندوز از طریق Command Prompt  ویندوز نیز می‏خواهید به Git دسترسی داشته باشید. گزینه سوم هم Git و هم برخی از ابزار‏های یونیکسی را به متغیر‏های محلی اضافه می‏‌کند که سبب می‏‌شود شما یک خط فرمان قدرتمند‏تر در ویندوز داشته باشید. اما این کار ممکن است در برخی از برنامه‏‌های پیش فرض اختلال ایجاد کند بنابراین در انتخاب این گزینه احتیاط کنید.

--------------
در این مرحله کاراکتری را که نشان دهنده انتهای خط است تعیین می‏‌کنید. این کاراکتر در ویندوز و یونیکس متفاوت است. بنابراین Git از شما می‏‌خواهد که برای حفظ سازگاری در محیط‏ هایی که چند سیستمی هستند، آن‏را تعیین کنید.
گزینه اول به صورت فرمت یونیکس ذخیره و به شکل ویندوز بازیابی می‏‌شود (مناسب برای محیط ویندوز).
گزینه دوم ذخیره به فرمت یونیکسی است و مناسب محیط‌های یونیکس است.
و آخرین گزینه فایل را بدون تغییر ذخیره و بازیابی می‏کند (از این گزینه نیز می‏توان هم برای Unix و هم windows استفاده کرد).
بعد از این مرحله نصب آغاز می‏شود.


نکته: شما می‏‌توانید جهت دسترسی به یک محیط گرافیکی قوی از gitextensions   استفاده کنید. با دانلود این فایل، هم خود Git و هم GUI ‏هایی برای کار‏های مختلف، نظیر مشاهده تفاوت‏های دو فایل یا نمایش گرافیکی شاخه‏‌ها به سیستم شما اضافه می‏‌شود.

پیکربندی Git:
برای پیکربندی Git شما باید یک فایل config ایجاد کنید و با استفاده از دستوراتی که در ادامه می‏‌آید این تنظیمات را انجام دهید. البته پیکربندی Git از طریق ابزار‏های گرافیکی که در محله قبل نصب کردید نیز امکان‏پذیر است.
Git دارای سه نوع دسترسی برای پیکره‌بندی است:
سیستمی: این تنظیمات بر روی کل سیستمی که git برای روی آن نصب شده اعمال می‏‌شود. فایل  gitconfig در مسیر program files/Git/etc/gitconfig قرار دارد و برای تغییر آن باید از سوئیچ system-- استفاده نمود.
در سطح کاربر: فایل  config.در مسیر [users/[username/ برای این منظور است و تغییر این تنظیمات تنها بر روی همین کاربر اعمال می‏شود برای درسترسی به این فایل باید از سوئیچ global-- استفاده کرد.
در سطح Repository: برای هر پوشه repository  این فایل موجود است و اگر از دستور config بدون هیچ سوئیچی استفاده کنیم تغییرات بر روی این فایل اعمال می‏شود.

نکته: معمولا فایل پیکربندی git در سطح سیستم را تغییر نمی‏‌دهند.

دستورات پیکربندی:
همان‏طور که گقته شد هر Commit حاوی اطلاعات فردی است که آن‏را انجام داده است. این اطلاعات را می‏‌توان به صورت زیر تنظیم کرد:
نام کاربر:
git config --global user.name "Hessam"
ایمیل کاربر:
git config --global user.email "hessam@localhost.com"
با استفاده از دستور زیر می‏‌توان تنظیماتی را که تا کنون انجام شده ببینیم:
git config --global --list
همچنین می‏‌توان ویرایشگر متن پیش فرضی برای git تعیین کرد. از این ویرایشگر می‏‌توان به عنوان مثال بعد از فرخوانی دستور commit استفاده نمود تا دلیل commit مشخص شود. در صورت تعیین این ویرایشگر، git  آن‏را خودکار باز می‏کند:
git config --global core.editor notepad
من در اینجا notepad را انتخاب کردم توجه کنید که مسیر ویرایشگر باید در متغیر‌های محلی ویندوز باشد.
و در نهایت جهت نمایش بهتر پیام‏های git می‏توانیم تنظیم کنیم که آن‏ها را با رنگ‏های متفاوتی نمایش دهد:
git config --global color.ui auto
 البته تنظیمات بیشتری را می‏‌توان در اینجا انجام داد، مانند تعیین برنامه پیش فرض برای نمایش اختلاف فایل‏ها و یا برنامه پیش فرض برای حل کردن مشکل conflict و غیره که این تنظیمات در همان بخش‏‌ها گفته خواهد شد.
در قسمت بعد دستورات اولیه کار با git به صورت محلی گفته خواهد شد.