<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های آمنوتجیکارا</title>
        <link>https://virgool.io/feed/@mahdi72</link>
        <description>AmenoTejikara</description>
        <language>fa</language>
        <pubDate>2026-04-15 01:35:18</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/17115/avatar/MewxrF.jpeg?height=120&amp;width=120</url>
            <title>آمنوتجیکارا</title>
            <link>https://virgool.io/@mahdi72</link>
        </image>

                    <item>
                <title>ایجاد قالب های جدید مبتنی بر فرم برای Issue های گیتهاب</title>
                <link>https://virgool.io/@mahdi72/%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%D9%82%D8%A7%D9%84%D8%A8-%D9%87%D8%A7%DB%8C-%D8%AC%D8%AF%DB%8C%D8%AF-%D9%85%D8%A8%D8%AA%D9%86%DB%8C-%D8%A8%D8%B1-%D9%81%D8%B1%D9%85-%D8%A8%D8%B1%D8%A7%DB%8C-issue-%D9%87%D8%A7%DB%8C-%DA%AF%DB%8C%D8%AA%D9%87%D8%A7%D8%A8-js61hvv32mfw</link>
                <description>اگر شخصی مشکلی را شناسایی کند یا یک ویژگی را برای یکی از محصولات درخواست کند، یک Issue را در مخزن مربوطه باز می کند. هنگام بررسی باگ ها، دانستن اطلاعات مانند نسخه سیستم عامل، نسخه نرم افزار مفید است. این باعث می شود که توسعه دهنده بتواند مشکل ایجاد شده را دوباره ایجاد کند (جهت شناسایی منبع مشکل) و در نتیجه رفع آن بسیار سریعتر شود. بنابراین با کمک قالب ها می‌توانید انواع ورودی، اعتبارسنجی و برچسب‌های پیش‌فرض را برای فرم‌های خود تعریف کنید.نیاز سنجیابتدا باید خوب فکر کنید که برای گزارش یک مشکل به چه اطلاعاتی نیاز دارید. من برای مخزن WindowsAppSDK مایکروسافت موارد زیر را در نظر گرفتم:نسخه سیستم عاملنسخه ناگت WASDKنوع پروژه (پکیج شده، غیر پکیج)نسخه IDEفرم Issue چگونه کار می کند؟فرم های Issue به زبان YAML نوشته میشوند که به راحتی قابل درک است. فرم ها ساختار خاصی دارند که باید از آن پیروی کنید. هر فرم باید شامل یک نام، توضیحات، عنوان و برچسب باشد و یک عنصر body که ورودی‌های اصلی در آن قرار می‌گیرند.یک فرم گزارش بسازیم!انواع ورودی های مجاز عبارتند از: markdown, dropdown, checkbox, textarea (جعبه متن، لیست کشویی (کمبوباکس)، چک باکس و مارک داون)فرم ها باید در پوشه .github/ISSUE_TEMPLATE در مخزن شما قرار گیرند. این الگو با یک بلوک علامت‌گذاری کوچک شروع می‌شود: ما می‌خواهیم کاربران را تشویق کنیم تا قبل از ایجاد هر گونه مشکل جدید ابتدا آن را در مسائل موجود جستجو کنند تا از مشکلات تکراری جلوگیری کنیم. برای شروع ابتدا تمپلت پیشفرض را برای مخزن موردنظر ایجاد کنید. (اگر قبلا تمپلت ایجاد کرده اید میتوانید این مراحل را رد کنید.)ابتدا به تنظیمات مخزن بروید و روی Set up templates کلیک کنید.2. تمپلت موردنظر را انتخاب کنید ما اینجا گزنیه اول bug report را انتخاب میکنیم.3. حالا روی گزینه Propose changes کلیک کنید. (قبل از ثبت تغییرات میتوانید تمپلت را با زدن گزینه Preview and edit ویرایش کنید. من ترجیح میدهم بعد از ایجاد آن را ویرایش کنم)4. تغییرات را کامیت کنید5.حالا میرویم سراغ فایل تمپلت پیشفرضی که ایجاد شده و آن را ویرایش میکنیم. (به مسیر فایل دقت کنید.)6.نکته ای که باید دقت کنید، شما اول باید پسوند فایل را از md به yaml تغییر بدهید. محتوای فایل را کامل پاک کنید.7. بسیار خوب حالا نوبت به نوشتن قالب دلخواهمان رسیده است. اول از همه باید ویژگی های پیشفرض را مشخص کنیم:name: Bug report
description: File a bug report
title: &amp;quotBug title&amp;quot
labels: []
body:مهم ترین ویژگی قسمت body است که باید فرم دلخواهمان را داخلش ایجاد کنیم.ابتدا از کاربر توضیح اشکال و مراحل بازتولید را می‌خواهیم. اینها را می توان در ورودی متنی نوشت.   - type: markdown
    attributes:
      value: |
        For bugs related to WinUI, please open a bug on the [Microsoft.UI.Xaml repository](https://github.com/microsoft/microsoft-ui-xaml)
  - type: textarea
    validations:
      required: true
    attributes:
      label: Describe the bug
      description: Please enter a short, clear description of the bug.
  - type: textarea
    validations:
      required: true
    attributes:
      label: Steps to reproduce the bug
      description: Please provide any required setup and steps to reproduce the behavior.
      placeholder: |
        1. Go to &#039;...&#039;
        2. Click on &#039;....&#039;
  - type: textarea
    attributes:
      label: Expected behavior
      description: Please provide a description of what you expected to happen
  - type: textarea
    attributes:
      label: Screenshots
      description: If applicable, add screenshots here to help explain your problemبا کلمه type نوع ورودی مشخص میشود،هر ورودی شامل یک attributes است که میتوانیم لیبل، متن PlaceHolder (در صورت خالی بودن ورودی این متن نمایش داده میشود) و توضیحات مربوط به ورودی را اضافه کنیم. در قسمت validations اجباری یا اختیاری بودن ورودی مشخص میشود. در صورت اجباری بودن ورودی، تا زمانی که کاربر ورودی موردنظر را پر نکند امکان ایجاد Issue را نخواهد داشت.در پایان باید اطلاعات نیازسنجی شده را از کاربر دریافت کنیم. با توجه به اطلاعات موردنیاز میتوانید از انواع ورودی، لیست کشویی (تک انتخابی، چند انتخابی) و چک باکس استفاده کنید.  - type: dropdown
    attributes:
      label: IDE
      description: Which IDE do you use?
      multiple: true
      options:
        - &amp;quotVisual Studio 2022-preview&amp;quot
        - &amp;quotVisual Studio 2022&amp;quot
        - &amp;quotVisual Studio 2019&amp;quot
        - &amp;quotVisual Studio 2017&amp;quot
        - &amp;quotOther&amp;quot
  - type: dropdown
    attributes:
      label: NuGet package version
      options:
        - &amp;quotMicrosoft.WindowsAppSDK 1.0.0-preview3&amp;quot
        - &amp;quotMicrosoft.WindowsAppSDK 1.0.0-preview2&amp;quot
        - &amp;quotMicrosoft.WindowsAppSDK 1.0.0-preview1&amp;quot
        - &amp;quotMicrosoft.WindowsAppSDK 1.0.0-experimental1&amp;quot
        - &amp;quotMicrosoft.ProjectReunion 0.8.5&amp;quot
        - &amp;quotMicrosoft.ProjectReunion 0.8.4&amp;quot
        - &amp;quotMicrosoft.ProjectReunion 0.8.3&amp;quot
        - &amp;quotMicrosoft.ProjectReunion 0.8.2&amp;quot
        - &amp;quotMicrosoft.ProjectReunion 0.8.1&amp;quot
        - &amp;quotMicrosoft.ProjectReunion 0.8.0&amp;quot
  - type: checkboxes
    attributes:
      label: Project type
      description: Please specify project type you have encountered the issue.
      options:
        - label: &amp;quotPackaged&amp;quot
        - label: &amp;quotUnpackaged&amp;quot
  - type: dropdown
    attributes:
      label: Windows version
      description: Which Windows versions did you see the issue on?
      multiple: true
      options:
        - &amp;quotInsider Build (xxxxx)&amp;quot
        - &amp;quotWindows 11 (22000)&amp;quot
        - &amp;quotMay 2021 Update (19043)&amp;quot
        - &amp;quotOctober 2020 Update (19042)&amp;quot
        - &amp;quotMay 2020 Update (19041)&amp;quot
        - &amp;quotNovember 2019 Update (18363)&amp;quot
        - &amp;quotMay 2019 Update (18362)&amp;quot
        - &amp;quotOctober 2018 Update (17763)&amp;quot
        - &amp;quotApril 2018 Update (17134)&amp;quot
        - &amp;quotFall Creators Update (16299)&amp;quot
        - &amp;quotCreators Update (15063)&amp;quotدر نهایت روی کامیت کلیک کنید تا تغییرات ثبت شود.حال یک issue جدید ایجاد کنید. تا فرم ثبت گزارش خود را مشاهده کنید.کدهای کامل را میتوانید در این پول ریکوئست مشاهده کنید.</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Wed, 03 Nov 2021 12:56:21 +0330</pubDate>
            </item>
                    <item>
                <title>فعال سازی Mica (متریال جدید فلوئنت دیزاین در ویندوز 11) در برنامه های WPF</title>
                <link>https://virgool.io/@mahdi72/%D9%81%D8%B9%D8%A7%D9%84-%D8%B3%D8%A7%D8%B2%DB%8C-mica-%D9%85%D8%AA%D8%B1%DB%8C%D8%A7%D9%84-%D8%AC%D8%AF%DB%8C%D8%AF-%D9%81%D9%84%D9%88%D8%A6%D9%86%D8%AA-%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D8%AF%D8%B1-%D9%88%DB%8C%D9%86%D8%AF%D9%88%D8%B2-11-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-wpf-yygmbqk8qrxv</link>
                <description>میکا یک ماده مات و پویا است که از تم و تصویر زمینه دسکتاپ، برای نقاشی پس‌زمینه پنجره‌هایی با عمر طولانی، مانند برنامه‌ها و تنظیمات استفاده می‌کند. Mica به طور خاص برای عملکرد برنامه طراحی شده‌است؛ زیرا فقط یکبار از تصویر زمینه دسکتاپ نمونه برداری می‌کند تا تجسم آن را ایجاد کند. میکا بر خلاف متریال آکریلیک، بسیار بهینه است و از منابع کمتری استفاده می‌کند.تصویر زیر، متریال میکا را در حالت تاریک نمایش می‌دهد.چه زمانی از میکا استفاده کنیم؟میکا ماده‌ای است که در پس‌زمینه برنامه شما، پشت همه محتوای دیگر ظاهر می‌شود. این یک ماده‌ی مات است که از تم کاربر و کاغذ دیواری دسکتاپ استفاده می‌کند تا ظاهر بسیار شخصی سازی شده‌ی خود را ایجاد کند. همانطور که کاربر پنجره را در سراسر صفحه حرکت می‌دهد، مواد Mica به صورت پویا برای ایجاد یک تجسم غنی با استفاده از کاغذ دیواری، زیر برنامه سازگار می‌شود. علاوه بر این، این مواد به کاربران کمک می‌کند تا زمانیکه برنامه غیرفعال است، روی کار فعلی تمرکز کنند و به رنگ خنثی برگردند.توصیه می‌کنیم از Mica به‌عنوان لایه پایه برنامه‌تان استفاده کنید.قابلیت استفاده و سازگاریMica به طور خودکار ظاهر خود را برای طیف گسترده‌ای از دستگاه‌ها و زمینه‌ها تطبیق می‌دهد. Mica برای عملکرد، طراحی شده‌است؛ زیرا فقط یکبار تصویر زمینه‌ی پس زمینه را برای ایجاد تجسم آن می‌گیرد. در حالت کنتراست بالا، کاربران همچنان رنگ پس‌زمینه‌ی آشنای انتخابی خود را بجای میکا مشاهده می‌کنند.علاوه بر این، Mica به عنوان یک رنگ بازگشتی ثابت ظاهر می‌شود (SolidBackgroundFillColorBase):وقتی کاربر شفافیت را در تنظیمات شخصی سازی رنگ خاموش می‌کند.وقتی حالت صرفه جویی در باتری فعال می‌شود.هنگامیکه برنامه روی سخت افزار پایین رده اجرا می‌شود.وقتی پنجره برنامه روی دسکتاپ، غیرفعال می‌شود.هنگامیکه برنامه ویندوز روی Xbox یا HoloLens اجرا می‌شود.زمانیکه نسخه ویندوز، زیر 22000 باشد. (میکا فقط روی ویندوز 11 و بالاتر اجرا میشود)نحوه استفاده از میکا در برنامه‌های WPFبرای کاربران WinUI، استفاده از میکا بسیار ساده‌است. آنها به کمک کلاس BackdropMaterial و پراپرتی ApplyToRootOrPageBackground  به‌راحتی میتوانند میکا را برای UIElement خود فعال کنند. اما برای استفاده از میکا در برنامه‌های WPF، ما باید به کمک توابع محلی ویندوز، میکا را فعال کنیم. توجه داشته باشید که توابع مورد استفاده بصورت UnDocument می باشد که به این معنی می‌باشد که بصورت رسمی مستند سازی نشده و هر لحظه امکان حذف و یا تغییر آن می‌باشد. همچنین به این نکته باید دقت نمود که میکا فقط بر روی نسخه ویندوز 11 و بالاتر فعال میشود و در ویندوز 10 و ... هیچ اتفاقی رخ نمی‌دهد.روش کار به این صورت می‌باشد که باید Flag مربوطه را به HWND متصل کنیم. ابتدا یک پروژه‌ی WPF را ایجاد کنید و سپس کلاسی را با نام NativeMethods ایجاد و کدهای زیر را در آن کپی کنید:public static class NativeMethods
  {
     public enum DWMWINDOWATTRIBUTE : int
        {
            USE_IMMERSIVE_DARK_MODE = 20,
            MICA_EFFECT = 1029
        }
[StructLayout(LayoutKind.Sequential)]
        public struct MARGINS
        {
            public MARGINS(int left, int top, int right, int bottom)
            {
                this.Left = left;
                this.Top = top;
                this.Right = right;
                this.Bottom = bottom;
            }

            /// &lt;summary&gt;Width of left border that retains its size.&lt;/summary&gt;
            public int Left;

            /// &lt;summary&gt;Width of right border that retains its size.&lt;/summary&gt;
            public int Right;

            /// &lt;summary&gt;Height of top border that retains its size.&lt;/summary&gt;
            public int Top;

            /// &lt;summary&gt;Height of bottom border that retains its size.&lt;/summary&gt;
            public int Bottom;
        }
[DllImport(&amp;quotdwmapi.dll&amp;quot)]
        public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attr, ref int attrValue, int attrSize);

        [DllImport(&amp;quotdwmapi.dll&amp;quot)]
        public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);

        public static bool SetWindowAttributeValue(IntPtr hWnd, DWMWINDOWATTRIBUTE attribute, int attributeValue)
        {
            return SetWindowAttribute(hWnd, attribute, ref attributeValue);
        }

        public static bool SetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue)
        {
            var result = DwmSetWindowAttribute(hWnd, attribute, ref attributeValue, sizeof(int));
            return result == 0;
        }

        public static bool WindowExtendIntoClientArea(IntPtr hWnd, MARGINS margins)
        {
            // Extend frame on the bottom of client area
            var result = DwmExtendFrameIntoClientArea(hWnd, ref margins);
            return result == 0;
        }
    }حال به MainWindow.xaml.cs مراجعه کنید. برای اینکه براش واقعاً نشان داده شود، باید کروم داخلی WPF را با یک بازنویسی WindowChrome حذف کنیم:(شما همچنین می‌توانید از WindowStyle.None استفاده کنید، اما WindowChrome به شما امکان می‌دهد کنترل‌های سیستمی را حفظ کنید که مفید خواهد بود.)           this.Background = Brushes.Transparent;
            var chrome = new WindowChrome
            {
                CornerRadius = default(CornerRadius),
                GlassFrameThickness = new Thickness(0, 0, 0, 1),
                UseAeroCaptionButtons = true
            };
            WindowChrome.SetWindowChrome(this, chrome);دقت کنید که شما این کدها را در xaml هم میتوانید بنویسید.حالا باید متد فعال سازی میکا را بعد از InitializeComponent بنویسید.UpdateWindowEffect(this, this.IsActive);کد کامل:public MainWindow()
        {
            this.Background = Brushes.Transparent;
            var chrome = new WindowChrome
            {
                CornerRadius = default(CornerRadius),
                GlassFrameThickness = new Thickness(0, 0, 0, 1),
                UseAeroCaptionButtons = true
            };
            WindowChrome.SetWindowChrome(this, chrome);
            InitializeComponent();
            UpdateWindowEffect(this);
}متد فعال سازی:public void UpdateWindowEffect(Window window)
        {
            UpdateWindowEffect(new WindowInteropHelper(window).EnsureHandle());
        }
public void UpdateWindowEffect(IntPtr windowHandle)
        {
            EnableMicaEffect(windowHandle, true);
        }

        private void EnableMicaEffect(IntPtr windowHandle, bool isDarkTheme)
        {
            NativeMethods.WindowExtendIntoClientArea(windowHandle, new NativeMethods.MARGINS(-1, -1, -1, -1));

            var trueValue = 0x01;
            var falseValue = 0x00;

            // Set dark mode before applying the material, otherwise you&#039;ll get an ugly flash when displaying the window.
            if (isDarkTheme)
            {
                NativeMethods.SetWindowAttributeValue(windowHandle, NativeMethods.DWMWINDOWATTRIBUTE.USE_IMMERSIVE_DARK_MODE, trueValue);
            }
            else
            {
                NativeMethods.SetWindowAttributeValue(windowHandle, NativeMethods.DWMWINDOWATTRIBUTE.USE_IMMERSIVE_DARK_MODE, falseValue);
            }

            NativeMethods.SetWindowAttributeValue(windowHandle, NativeMethods.DWMWINDOWATTRIBUTE.MICA_EFFECT, trueValue);
        }در کدهای بالا، بصورت پیشفرض میکا بصورت دارک اجرا میشود. لذا با توجه به تم سیستم عامل ویندوز خود، باید میکا را فعال سازی کنید ( در فراخوانی متد EnableMicaEffect مقدار true به معنای فعال سازی بصورت تم تاریک می‌باشد. اگر ویندوز شما از تم روشن استفاده میکند باید این مقدار را false کنید.)وقتی پرچم USE_IMMERSIVE_DARK_MODE تنظیم می‌شود، براش Mica را مجبور می‌کند تا در حالت تاریک رندر شود.</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Sun, 31 Oct 2021 13:21:12 +0330</pubDate>
            </item>
                    <item>
                <title>SettingsUIایجاد صفحه تنظیمات برنامه به سبک ویندوز 11</title>
                <link>https://virgool.io/@mahdi72/settingsui%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%D8%B5%D9%81%D8%AD%D9%87-%D8%AA%D9%86%D8%B8%DB%8C%D9%85%D8%A7%D8%AA-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A8%D9%87-%D8%B3%D8%A8%DA%A9-%D9%88%DB%8C%D9%86%D8%AF%D9%88%D8%B2-11-gn6hxupi8bzr</link>
                <description>چند وقت پیش مایکروسافت Powertoys رو به نسخه 2.6 winui ارتقا داد که بهش این اجازه رو میداد از سبک طراحی جدید ویندوز 11 استفاده بکنه، چیزی که نظر من رو به خودش جلب کرد پیاده سازی صفحه تنظیمات به سبک ویندوز 11 بود! برای همین تصمیم گرفته بودم تا این صفحه تنظیمات رو به شکل یک کتابخانه برای WinUI 3 پورت کنم. ولی از اونجایی که WinUI 3 هنوز ویژوال رفرش های ویندوز 11 رو دریافت نکرده بود بیشتر از 1 ماه منتظر بودم تا اینکه 2 روز پیش نسخه جدیدی از WinUI 3 منتشر شد که شامل ویژوال رفرش های ویندوز 11 بود. بلاخره دیروز تونستم این صفحه تنظیمات رو برای WinUI 3 پورت کنم و تو ناگت آپلود کنم.صفحه ناگتسورس کد SettingsUI</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Fri, 08 Oct 2021 11:45:10 +0330</pubDate>
            </item>
                    <item>
                <title>قسمت دوم: نحوه توسعه برنامه HandySub با WinUI3</title>
                <link>https://virgool.io/@mahdi72/%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-%D9%86%D8%AD%D9%88%D9%87-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-handysub-%D8%A8%D8%A7-winui3-p79boaj6mgmx</link>
                <description>در ادامه قسمت قبل که نحوه توسعه هندی ساب رو باهم دیدم، این قسمت قرار هست یه Button به ListViewItem اضافه کنیم تا کاربر بدونه اینکه به قسمت تنظیمات مراجعه کنه و تاریخچه جستجو رو حذف کنه، بتونه از طریق همون لیست پیشنهادی ایتم های موردنظرش رو براحتی حذف کنه.حتما نظرتون رو راجع به این ویدئو بنویسید. افزودنButtonحذفکردنبهListViewItemدرنرمافزارHandySub(aparat.com)winui </description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Thu, 30 Sep 2021 14:37:43 +0330</pubDate>
            </item>
                    <item>
                <title>نحوه توسعه برنامه HandySub با Visual Studio</title>
                <link>https://virgool.io/@mahdi72/%D9%86%D8%AD%D9%88%D9%87-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-handysub-%D8%A8%D8%A7-visual-studio-lblrvw2xkhpr</link>
                <description>امروز تصمیم گرفتم وقتی دارم روی پروژه HandySub کار میکنم نحوه توسعه این برنامه رو ضبط کنم و روی آپارات و ویرگول قرار بدم. بنظرم نشون دادن مراحل توسعه یه نرم افزار میتونه جالب و مفید باشه و نکته های آموزشی متفاوتی رو ارائه بکنه.هندی ساب یه برنامه برای دانلود زیرنویس از وب سایت های مختلف مثل سابسین و جهان زیرنویس و... هستش. خارج از هدف اصلی برنامه که جستجو و دانلود زیرنویس هستش نکته های ریز و درشت زیادی هم وجود داره که باعث میشه نرم افزار ما بهتر دیده بشه و عملکرد مناسبی داشته باشه. تو این ویدئو ما به مرتب سازی تاریخچه جستجو می پردازیم و باهم درگیر کد نویسی و افزودن این ویژگی میشیم.حتما نظرتون رو راجع به این ویدئو بنویسید. https://aparat.com/v/mIt7P </description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Thu, 09 Sep 2021 18:17:41 +0430</pubDate>
            </item>
                    <item>
                <title>معرفی و راهنمایی جهت انتخاب پلتفرم های جدید مایکروسافت</title>
                <link>https://virgool.io/@mahdi72/%D9%85%D8%B9%D8%B1%D9%81%DB%8C-%D9%88-%D8%B1%D8%A7%D9%87%D9%86%D9%85%D8%A7%DB%8C%DB%8C-%D8%AC%D9%87%D8%AA-%D8%A7%D9%86%D8%AA%D8%AE%D8%A7%D8%A8-%D9%BE%D9%84%D8%AA%D9%81%D8%B1%D9%85-%D9%87%D8%A7%DB%8C-%D8%AC%D8%AF%DB%8C%D8%AF-%D9%85%D8%A7%DB%8C%DA%A9%D8%B1%D9%88%D8%B3%D8%A7%D9%81%D8%AA-xoidlhwyuj4t</link>
                <description>اگر به تکنولوژی های شرکت مایکروسافت علاقه مند باشید و اخبار اون رو دنبال کرده باشید قطعا در جریان هستید که علاوه بر تکنولوژی های قدیمی (WPF, UWP, Xamarin) تکنولوژی های جدیدی (Project Reunion, Maui, WinUI, Uno, Xaml Island) بصورت همزمان در حال توسعه هستند. اکثر این تکنولوژی ها شبیه و نزدیک به هم هستند و برای کسی که تازه کار باشد ممکن است دچار سردرگمی شود. و چون بصورت همزمان در حال توسعه می باشند ممکن سوالاتی برای شما پیش بیاید.در این پست هر کدام از این تکنولوژی ها را معرفی کرده و در انتخاب صحیح به شما کمک خواهیم کرد.ساخت برنامه با WPFبه کمک تکنولوژی WPF ما میتوانیم نرم افزارهای دسکتاپ را توسعه دهیم. WPF هم چنان پشتیبانی میشود و در سال های اخیر بصورت متن باز منتشر شده است. اگر نیاز دارید که برنامه شما در ویندوز های 7 تا ویندوز 11 اجرا شود میتوانید از WPF استفاده کنید. لازم به ذکر است که برنامه های WPF به عنوان Win32 یا Desktop شناخته میشوند.سورس کدساخت برنامه با UWPUWP بعد از WPF و با انتشار ویندوز 10 معرفی شد. علت انتشار  هماهنگی برنامه ها با سیستم عامل ویندوز 10 و امنیت بیشتر بود.به طور فنی برنامه ای که بصورت UWP ساخته میشود همان WPF است با این تفاوت که داخل SandBox اجرا میشود و با محیط خارج ارتباطی ندارد. بدلیل مسائل امنیتی بسیاری از کارهای ساده و مهم در UWP غیرممکن (البته راه حل هایی وجود دارد) می باشد و نیاز به دسترسی کاربر دارد. به عنوان مثال API های system.Io.File یا Process قابل استفاده نمی باشند.نرم افزارهایی که با UWP ساخته میشوند فقط بر روی ویندوز 10 به بالا قابلیت اجرا دارند و توزیع ان از طریق استور مایکروسافت امکان پذیر است. در صورت نیاز به توزیع دستی (فایل نصبی) توسعه دهنده باید فایل نصبی را بصورت دیجیتالی امضا کند که دردسر های خودش را دارد.ساخت برنامه با Xamarinاگر نیاز دارید که برای سیستم عامل اندروید و مک برنامه بنویسید زامارین میتواند به شما کمک کند.شروع با زامارینساخت برنامه با WinUIبعد از معرفی UWP نیاز به یک فریمورک رابط کاربری قوی جهت جذب کاربران به سمت UWP احساس شد. در نتیجه مایکروسافت فریمورک WinUI را ایجاد کرد. WinUI در 2 نسخه در حال توسعه می باشد.WinUI 2.Xاین نسخه از WinUI فقط قابلیت استفاده در برنامه های مبتنی بر UWP را دارد. اخیرا نسخه 2.6 آن منتشر شده که شامل تغییرات بصری عظیم می باشد. لازم به ذکر است که ویندوز 11 که اخیرا معرفی شد بر پایه WinUI 2.6  ایجاد شده است.WinUI 3.Xاین نسخه از WinUI قابلیت استفاده در پلتفرم های دیگر را محیا می کند. در حال حاظر بصورت پیش نمایش است و بر پایه WinUI 2.5 می باشد. در 3 ماهه آخر سال 2021 تمامی استایل ها بر پایه نسخه 2.6 خواهد بود.سورس کدبرنامه دمو شامل تمامی کنترل ها و استایل ها نسخه 2.6برنامه دمو شامل تمامی کنترل ها و استایل ها نسخه 3پلتفرم Unoپلتفرم اونو توسط مایکروسافت ایجاد نشده، اما توسط آن پشتیبانی میشود. شما به کمک پلتفرم اونو میتوانید به کمک WinUI 3 برنامه های خود را در ویندوز 7 (به کمک موتور رندر Skia ) تا ویندوز 11، لینوکس (به کمک Skia)، مک و حتی موبایل اجرا کنید.سورس کدوب سایتپلتفرم Mauiمائویی در واقع نسل بعدی زامارین می باشد و بصورت تک پروژه ای ایجاد شده است. در زامارین شما برای هر پلتفرم (ویندوز، اندروید، مک و...) یک پروژه جداگانه داشتید اما در مائویی فقط یک پروژه واحد وجود دارد. پس اگر نیاز دارید که برای گوشی های همراه برنامه نویسی کنید میتوانید از مائویی استفاده کنید. لازم به ذکر است که به کمک مائویی شما میتوانید برای لینوکس و مک هم برنامه ایجاد کنید. اما بدلیل وجود WinUI در سایر پلتفرم ها بهتر است از مائویی فقط برای ایجاد برنامه های موبایل استفاده کنید.سورس کدپلتفرم Project Reunionاخیرا نام این پروژه به Windows App SDK تغییر یافته است. به کمک این پروژه میتوانید از WinUI 3 در برنامه های WPF و سایر تکنولوژی های Desktop استفاده کنید. و کل برنامه خود را مدرن کنید.لازم به ذکر است که برنامه های ساخته شده توسط Reunion فقط در ویندوز 10 به بالا اجرا میشوند.در حال حاظر جهت اجرای برنامه نیاز هست که برنامه بصورت MSIX پکیج بشود.در نسخه 1.0 که تا چند ماه اینده منتشر خواهد شد نیازی به پکیج کردن نخواهد بود.سورس کدپلتفرم Xaml Islandاین پلتفرم در واقع پلی است که شما میتوانید از کنترل های UWP یا WinUI در برنامه های دسکتاپ (WPF) استفاده کنید. تفاوت این پلتفرم با Reunion در این است که شما فقط میتوانید بخشی از برنامه خود را مدرن کنید و قسمت های مدرن شده در ویندوز های پایین تر از ویندوز 10 کار نخواهند کرد. اما در Reunion تمام بخش های برنامه شما مدرن خواهد شد.سخن آخر اینکه اگر نیاز به برنامه های موبایل دارید بهتر است از مائویی استفاده کنید بدلیل اینکه:نسل بعدی زامارین استاز دات نت 6 به بالا استفاده می کندروان، سریع و انعطاف پذیر استخطاهای بسیار کمتری داردمخصوص موبایل طراحی شده استتجربه بیشتری نسبت به سایر پلتفرم ها دارداگر نیاز به اجرای برنامه بصورت کراس پلتفرم دارید (ویندوز/لینوکس/مک) بهتر است از Uno استفاده کنید بدلیل اینکه:مخصوص کراس پلتفرم طراحی شدهاز WinUI 3 استفاده می کندبرای ویندوز 10 به بالا از تکنولوژی UWP و برای ویندوز 7 و لینوکس از Skia استفاده می کنداگر نیاز دارید برنامه شما فقط در ویندوز 10 به بالا اجرا شود بهتر است از Project Reunion استفاده کنید بدلیل اینکه:از WinUI 3 استفاده می کندتمام ویژگی های UWP را داردمحدودیت های UWP را نداردبصورت Full Trust اجرا میشودپیچیدگی های UWP را ندارداز پلتفرم WPF برای اجرا استفاده می کنداگر نیاز دارید که برنامه شما در ویندوز 7 به بالا اجرا شود و در ویندوز 10 ظاهر مدرن تری به خود بگیرد بهتر است از Xaml Island استفاده کنید بدلیل اینکه:فقط بخشی از برنامه را مدرن می کندقسمت های مدرن شده در نسخه های قبل ویندوز 10 اجرا نمیشود</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Sun, 04 Jul 2021 14:07:43 +0430</pubDate>
            </item>
                    <item>
                <title>کاربرد Action ها در Github</title>
                <link>https://virgool.io/javacup/%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%AF-action-%D9%87%D8%A7-github-pel5zw49ufzx</link>
                <description>یه چند وقتی میشه که گیتهاب اکشن هارو معرفی کرده که میشه با استفاده از این اکشن ها یسری فعالیت های تکراری رو، خودکار سازی کرد و توی وقت و انرژی صرفه جویی کرد.حالا مثلا ما چجور کارایی میتونیم بکنیم؟ تقریبا میشه گفت هرکاری رو میشه باهاش کرد. کامپایل کردن پروژه، تست کردن، پابلیش کردن و...من معمولا فایل های خروجی که برای پروژه هام میگیرم بدلیل استفاده از ویژگی SelfContained و ایمیج های ReadyToRun برای اجرای سریعتر، معمولا حجمی حدود 140 مگ داره، حالا وقتی فشردش میکنم حجمش حدود 50 مگ میشه که اگر من بخوام هر دفعه که از برنامه خروجی میگیرم بیام فایل خروجی رو فشرده کنم و اون رو در گیتهاب اپلود بکنم هم فرایندی زمانبر هست هم اینکه تکراری و خسته کننده در نتیجه تصمیم گرفتم که از اکشن گیتهاب برای خودکارسازی این فرایند استفاده کنم. توی این نوشته کوتاه میخوایم یه اکشن بنویسیم که بیاد بر اساس سورس کد موجود روی گیتهاب برنامه رو بیلد کنه، فایل اجرایی رو بصورت فایل فشرده Zip ایجاد کنه و در نهایت این فایل فشرده رو در قسمت Release گیتهاب منتشر کنه/برای شروع کار اول باید در مخزن پروژه در سایت گیتهاب، به قسمت Action بریم.حالا روی قسمت New workflow باید کلیک کنیماینجا شما میتونید از قالب های پیشفرض موجود هر کدوم رو خواستید انتخاب کنید، اما من ترجیح میدم کارمو با یه قالب خالی شروع کنم پس روی set up a workflow yourself کلیک میکنیمکدهای پیشفرضی که وجود داره رو پاک کنید تا مثل عکس زیر یه فایل کاملا تمیز و خالی رو داشته باشیمنکته ای که باید دقت کنید، اسم و مسیر فایل هستش، مسیر فایل رو اصلا نباید تغییر بدید، ولی اسم فایل رو میتونید اصلاح کنید ولی توجه کنید که پسوند فایل باید yml باشه.حالا بریم سراغ نوشتن کدهای اکشن:اول از همه کد زیر رو مینویسیمname: &amp;quotPublish&amp;quotاین خط اسم اکشن مارو مشخص میکنه که قراره توی لیست workflow ها نمایش داده بشهکدی بعدی که باید بنویسیم (در خط بعدی) باید مشخص بکنیم که این اکشن چه زمانی اجرا بشه تریگر های زیر استفاده بیشتری دارند:push = هر زمان که کامیتی رو روی گیتهاب پوش کنید اکشن اجرا میشهpull_request = هر زمان که یه پول رکوئست رو مرج کنید اجرا میشهworkflow_dispatch = برنامه نویس خودش میتونه با کلیک روی دکمه مشخصی در قسمت اکشن ها، اکشن موردنظر رو اجرا کنهلیست کامل تریگر هارو میتونید اینجا مطالعه کنید.ما از push استفاده میکنیم البته یکم تغییرش میدیم زمانی که شامل تگ هم باشه اجرا باشهon:
  push:
    tags:
      - &amp;quotv*&amp;quotنکته ای که هست ما در اخر این دستور از v* استفاده کردیم که داره اشاره میکنه اگر تگ بصورت v1.0.0 بود اجرا بشه اون * میتونه هر عددی باشه. حالا در پایان بهتر متوجه میشید.3 تا متغیر ایجاد میکنیم تا محل فایل پروژه، اجرایی و فشرده رو نگه داره تا فایل اکشنمون زیاد شلوغ نشهenv:
  PROJECT_PATH: src/HandySub/HandySub.csproj
  ZIP_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub-x86.zip
  EXE_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub.exeحالا باید دستورات خودکار سازی رو بنویسیم همه دستورات باید در قسمت jobs نوشته بشنjobs:
  deploy:
    runs-on: windows-latestبه قسمت runs-on توجه کنید اینجا داریم میگیم که اکشن ما روی سرور ویندوزی و اخرین نسخه از اون اجرا بشه که اگر نیاز داشتید میتونید از linux استفاده کنید.خط بعدی باید قدم به قدم دستورات رو بنویسیم ما برای هر قدم از دستور name استفاده میکنیم که هنگام اجرای اکشن بصورت مرتب و خوانا بتونیم بفهمیم که در چه مرحله از اجرا هستیم. قدم اول اینه که اکشن رو اماده کنیم اکثر دستورات مهم توی این اکشن موجوده    steps:
      - name: Initialize Actions
        uses: actions/checkout@v2قدم بعدی sdk دات نت رو باید روی سرور داشته باشیم تا عملیات بیلد و خروجی رو انجام بدیم پس میگیم که نسخه موردنظر مارو دانلود و نصب بکنه      - name: Initialize .Net
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 5.0.x      قبل از بیلد کردن پروژه باید کتابخانه ها و بسته های ناگت رو restore کنیم تا بیلد خطا نداشته باشه      - name: Restore Project
        run: dotnet restore ${{ env.PROJECT_PATH }}حالا دستور خروجی گرفتن رو مینویسیم (بدلایلی که نمیدونم چیه حتما باید توی فایل csproj ، runtimeidentifier پروژه مشخص باشه که اینجا ما از win-x86 استفاده کردیم در غیر این صورت خطا میگیرید)      - name: Publish Project
        run: dotnet publish ${{ env.PROJECT_PATH }} -c Release --self-contained -r win-x86 --no-restoreحالا که فایل اجرایی رو ایجاد کردیم باید اون رو بصورت فشرده zip دربیاریم برای این کار از یه اکشن دیگه کمک میگیریم اول به اصطلاح  using میکنیم اون رو بعد ازش استفاده میکنیم. 2 تا ورودی داره files و dest که به ترتیب باید ادرس فایل ها و محل ذخیره زیپ رو بهش بدیم که ما از متغیر هایی که قبلا ایجاد کردیم استفاده میکنیم.      - name: Create Zip File
        uses: papeloto/action-zip@v1
        with:
          files: ${{ env.EXE_PATH }}
          dest: ${{ env.ZIP_PATH }}          در قدم اخر میایم از یه اکشن دیگه برای ساخت Release در قسمت گیتهاب کمک میگیریم، دقت کنید که برای اپلود کردن فایل زیپ داخل این Release، ما باید توکن و id این ریلیز رو ذخیره کنیم که اینجا میریزم داخل متغیر GITHUB_TOKEN و id، حالا این توکن رو از کجا میاریم؟ از قسمت secrets خود گیتهاب که شامل یسری اطلاعات از جمله توکن میشه، همچنین ما اسم تگ رو از طریق github.ref  دریافت میکنیم (همون تگی که پوش کردیم تو گیتهاب)      - name: Initialize Release
        uses: actions/create-release@v1
        id: create_release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}      حالا نوبته اینه که فایل زیپ رو اپلود کنیم، باز از یه اکشن دیگه کمک میگیریم، توکنی که قبلا ذخیره کردیم رو بهش میدیم همراه با فایل زیپ و در پایان به کمک id که قبلا ذخیره کردیم لینک فایل اپلود شده رو ازش دریافت میکنیم.      - name: Create Release    
        uses: csexton/release-asset-action@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          file: ${{ env.ZIP_PATH }}
          release-url: ${{ steps.create_release.outputs.upload_url }}          کد کامل رو اینجا ببینیددر اخر بر روی دکمه سبز رنگ بالا سمت راست start commit کلیک کنید تا تغییرات ثبت بشه.برگردید به پروژه خودتون ترمینال رو باز کنید و یک تگ جدید ایجاد کنید.git tag v1.0.0حالا تگ ایجاد شده رو پوش کنیدgit push origin tag v1.0.0برید به مخزن گیتهاب تا ببینید که اکشن شما بصورت خودکار اجرا میشه و در پایان یک ریلیز برای شما ایجاد میکنه.در قسمت ریلیز میتونید ببینید که ریلیز توسط ربات گیتهاب ایجاد شده</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Wed, 28 Apr 2021 18:44:44 +0430</pubDate>
            </item>
                    <item>
                <title>استفاده از T4 برای تولید کد در زمان برنامه نویسی</title>
                <link>https://virgool.io/@mahdi72/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-t4-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%AA%D9%88%D9%84%DB%8C%D8%AF-%DA%A9%D8%AF-%D8%AF%D8%B1-%D8%B2%D9%85%D8%A7%D9%86-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-svvqeooajbhl</link>
                <description>بطور ساده و مختصر، زمانی که شما یک پروژه ایجاد میکنید و از اون پنجره های Wizard  تنظیمات دلخواهتون رو اعمال میکنید تا پروژه بصورت شخصی سازی شده ایجاد بشه، درواقع دارید از T4 Template ها کمک میگیرید. T4 قالب هایی هستند که باعث میشوند کدهای سی شارپ یا ویژوال بیسیک بصورت اتوماتیک تولید بشن. نکته مثبتی که T4 داره اینه که ما میتونیم در زمان کدنویسی ازش استفاده کنیم و کدهای سی شارپ رو همون لحظه تحویل بگیریم و ازش استفاده کنیم.اگر کنجکاوید که چرا بهش میگن T4 باید بگم که خلاصه شده ی Text Template Transformation Toolkit هست بخوایم فارسیش کنیم میشه جعبه ابزار تبدیل الگوی متن? چهارتا T اول هر کلمه رو برداشتن شده T4 حالا ما چطوری میتونیم ازش استفاده کنیم و به چه دردی میخوره؟خوب بزارید با یه مثال بهتون نشون بدم که واقعا چقدر مفید هست:ما میتونیم از فایل هایی با پسوند resx برای چند زبانگی و کارهایی از این دست استفاده کنیم ینی محتوامون رو داخل این فایل ها ذخیره کنیم و ازشون استفاده کنیم.حالا وقتی میخوایم داخل Designer ویژوال استودیو از این ریسورس ها استفاده کنیم ممکنه دیزاینر نتونه اسم کلیدهارو نشون بده و Intellisence رو از دست بدیم و مجبور بشیم خودمون اسم کلید رو کامل تایپ کنیم. برای حل این مشکل ما میتونیم یه کلاس ایجاد کنیم و برای هر کلید یه پراپرتی بصورت زیر ایجاد کنیم:public static readonly string About = nameof(About);اما ایا منطقی هست ما هر بار که ریسورس جدیدی ایجاد میکنیم یا تغییر میدیم بیایم این کلاس رو ویرایش کنیم و کلیدهارو اصلاح کنیم؟ قطعا نه!اما چی میشه که یچیزی بیاد این کلیدهارو برامون بکشه بیرون و همین پراپرتی هارو براش ایجاد بکنه؟ قطعا خیلی ساده تر و سریعتر خواهد بود و ما هم به نتیجه دلخواه میرسیم. اینجاست که T4 به کمک میاد.فرض میکنیم که ما یه فایل resx با اسم Resource.resx داریم. که داخلش چند تا کلید ایجاد کردیم، در کنار این فایل یه فایل به اسم LocKey.tt ایجاد میکنیم دقت کنید که پسوندش tt هست.حالا کدهای زیر رو کپی میکنیم:&lt;#@ template debug=&amp;quotfalse&amp;quot hostspecific=&amp;quottrue&amp;quot language=&amp;quotC#&amp;quot #&gt;
&lt;#@ assembly name=&amp;quotSystem.Core&amp;quot #&gt;
&lt;#@ assembly name=&amp;quotSystem.Windows.Forms&amp;quot #&gt;
&lt;#@ output extension=&amp;quot.cs&amp;quot #&gt;
namespace WpfApp1 
{
    public class LocKey 
    {
        &lt;#using (var reader = new
System.Resources.ResXResourceReader(this.Host.ResolvePath(&amp;quotResource.resx&amp;quot))) {
            var enumerator = reader.GetEnumerator();
            while (enumerator.MoveNext()) {
                #&gt;public static readonly string &lt;#= enumerator.Key #&gt; = nameof(&lt;#=
enumerator.Key #&gt;);&lt;# 
                Write(&amp;quot\r\n\t\t&amp;quot);
            }
            Write(&amp;quot\r\n&amp;quot);
        }#&gt;
    }
}توی 4 خط اول ما مشخص کردیم که قراره کدها به چه زبونی تولید بشن، پسوندش چی باشه، از چه فضای نامی قراره استفاده بشه. بعدش فضای نام و اسم کلاس پروژه رو مشخص کردیم که ما اینجا اسمش رو LocKey گذاشتیم. نکته ای که باید دقت کرد اینه که هرجا بخوایم مستقیم کد سی شارپی که تو قالب مینویسیم تو خروجی تولید بشه اون رو بدون نشانه مینویسیم اما اگر بخوایم T4  برامون کد تولید کنه باید اون رو بین نشانه &lt;# #&gt; قرار بدیم. الان تو قالب بالا کد زیر توسط T4 اجرا میشه که میاد فایل resx رو باز میکنه و کلیدهارو میکشه بیرون و خودش تو خروجی ما دیده نمیشه:using (var reader = new System.Resources.ResXResourceReader(this.Host.ResolvePath(&amp;quotResource.resx&amp;quot))) {             var enumerator = reader.GetEnumerator();             while (enumerator.MoveNext()) {                 #&gt;public static readonly string &lt;#= enumerator.Key #&gt; = nameof(&lt;#= enumerator.Key #&gt;);&lt;#                  Write(&amp;quot\r\n\t\t&amp;quot);             }             Write(&amp;quot\r\n&amp;quot);         } و اگر دقت بکنید من کد پراپرتی رو مستقیم نوشتم بجز جاهایی که نیاز به اسم کلید هست و اون قسمت رو به کمک T4  کامل کردمpublic static readonly string &lt;#= enumerator.Key #&gt; = nameof(&lt;#= enumerator.Key #&gt;);حالا اگه فایل رو ذخیره کنیم بلافاصله همه کلیدها بصورت پراپرتی ایجاد میشن</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Mon, 29 Mar 2021 17:19:29 +0430</pubDate>
            </item>
                    <item>
                <title>ذخیره مقادیر تو در تو و پیچیده در فایل Json</title>
                <link>https://virgool.io/@mahdi72/%D8%B0%D8%AE%DB%8C%D8%B1%D9%87-%D9%85%D9%82%D8%A7%D8%AF%DB%8C%D8%B1-%D8%AA%D9%88-%D8%AF%D8%B1-%D8%AA%D9%88-%D9%88-%D9%BE%DB%8C%DA%86%DB%8C%D8%AF%D9%87-%D8%AF%D8%B1-%D9%81%D8%A7%DB%8C%D9%84-json-gfwtwsfhiqqo</link>
                <description>چند وقت پیش برای یکی از برنامه هام امکان تغییر رنگ برنامه رو فراهم کردم توی WPF ما انواع مختلفی رو برای رنگ ها داریم 2 تا از مهم ترینشون Color و Brush هستن Color نوع ساده ای هستش و Brush نوع پیچیده تر با قابلیت های بهتر که حالت های بهتری رو برای رنگ ارائه میکنه مثل LinearGradiantBrush که تصویرهای زیر رو ایجاد میکنهمشکل از اینجا شروع شد که من میخواستم رنگ رو داخل فایل تنظیمات (که فایل json هست) ذخیره کنم ولی با خطا مواجه میشدم و برنامه کرش میکرد. علت این بود که چون Brush نوع پیچیده ای هستش در نتیجه ساختار پیچیده و تو در تویی هم داره در نتیجه سریالیزر جیسون نمیتونه این ساختار پیچیده رو تجزیه کنه/اما چطور این مشکل رو باید برطرف کنیم؟ برای حل این مشکل باید خودمون یه جیسون کانورتر شخصی سازی شده ایجاد کنیم تا سریالیزر جیسون به کمک این کانورتر ما عملیات سریالیز رو انجام بده.برای شروع میتونید یه کلاس به اسم BrushJsonConverter ایجاد کنید.از کلاس JsonConverter ارث بری کنید. و نوعش رو Brush انتخاب کنید.public class BrushJsonConverter : JsonConverter&lt;Brush&gt;حالا 2 تا متد write و read رو override کنید.توی متد read باید بگیم چطور دسریالیز و توی متد write باید بگیم چطور سریالیز کنیم.راه های مختلفی برای این کار وجود داره روشی که من استفاده کردم ایجاد کدهای xaml هستشبه کمک کلاس xamlReader و متد Parse میتونیم مقدار xaml رو بخونیم:public override Brush Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return (Brush)XamlReader.Parse(reader.GetString());
}همینطور به کمک کلاس XamlWriter میتونیم مقدار xaml رو بنویسیم:public override void Write(Utf8JsonWriter writer, Brush value, JsonSerializerOptions options)
{
writer.WriteStringValue(XamlWriter.Save(value));
}حالا که کانورتر شخصی خودمون رو نوشتیم باید به سریالیز جیسون بگیم که از این کانورتر استفاده کنه کافیه بالای پراپرتی موردنظر کانورتر رو فراخوانی کنیم:[JsonConverter(typeof(BrushJsonConverter))]
public Brush Accent { get; set; }</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Fri, 19 Feb 2021 18:07:31 +0330</pubDate>
            </item>
                    <item>
                <title>حذف پسورد اکسل با سی شارپ</title>
                <link>https://virgool.io/@mahdi72/%D8%AD%D8%B0%D9%81-%D9%BE%D8%B3%D9%88%D8%B1%D8%AF-%D8%A7%DA%A9%D8%B3%D9%84-%D8%A8%D8%A7-%D8%B3%DB%8C-%D8%B4%D8%A7%D8%B1%D9%BE-l8uizoqhcg3b</link>
                <description>2 نوع پسورد میشه روی فایل های اکسل گذاشت، یکی روی شیت و ورکبوک هستش و دومی روی کل فایل، اگر نوع اول روی فایل باشه امکان مشاهده فایل و استفاده از اون بدون داشتن پسورد ممکنه ولی امکان مشاهده فرمول ها و ویرایش اون موجود نیست، اگر نوع دوم باشه کلا امکان باز کردن فایل بدون داشتن پسورد ممکن نیست.توی این پست میخوایم باهم پسورد نوع اول رو از فایل حذف کنیم. روش های مختلفی برای این کار وجود داره مثل اجرا کردن یه اسکریپت vba یا ادیت فایل های xml که ما میخوایم از روش ادیت کردن فایل های xml پسورد رو حذف کنیم. فایل xlsx در واقع یه فایل zip هستش، اگر پسوند رو به zip تغییر بدید میتونید فایل های xml رو مشاهده کنید. ما باید فایل های workbook.xml و sheetx.xml رو ویرایش کنیم و تگ workbookProtection و sheetProtection رو حذف کنیم و دوباره محتوا رو zip کنیم و به xlsx تغییر بدیم.یه پروژه جدید تو ویژوال استودیو ایجاد کنید.برای اینکه نیاز هست فایل رو زیپ کنیم بعد استخراجش کنیم و دوباره زیپش کنیم ما ابتدا 4 تا متغیر تعریف میکنیم تا محل این فعالیت هارو مشخص کنه و توی کدنویسی دچار اشتباه نشیم.private static readonly string Path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), &amp;quotUnProtectTemp&amp;quot);
private readonly string _archivePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), &amp;quotUnProtectedArchives&amp;quot);
private readonly string _pathWorkBook = System.IO.Path.Combine(Path, @&amp;quotxl\workbook.xml&amp;quot);
private readonly string _pathSheets = System.IO.Path.Combine(Path, @&amp;quotxl\worksheets&amp;quot);کارو با یه Button شروع میکنیم که قراره فایل های اکسل رو انتخاب کنه و عملیات رو شروع کنه.اول چک میکنیم ببینیم پوشه مربوط به فایل های زیپ موجوده یا نه اگر بود که باید پاک بشه بعد به کمک OpenFileDialog فایل های اکسل رو انتخاب میکنیم امکان MultiSelect رو هم فعال میکنیم که بتونیم همزمان چندتا فایل رو انتخاب کنیم:if (Directory.Exists(_archivePath))
{
Directory.Delete(_archivePath, true);
}
OpenFileDialog openFileDialog = new OpenFileDialog
{
Multiselect = true, Filter = &amp;quotExcel Files|*.xlsx&amp;quot
};
if (openFileDialog.ShowDialog() == true)
{
foreach (var file in openFileDialog.FileNames)
{
UnProtectExcel(file);
}
SaveUnProtectedExcel();
}متد UnProtectExcel ادرس فایل اکسل رو میگیره و عملیات حذف پسورد رو انجام میده، بعد از تموم شدن حلقه و حذف پسورد تمام فایل ها، به کمک متد SaveUnProtectedExcel فایل های اصلاح شده رو به محل موردنظر کاربر منتقل میکنیم.private void UnProtectExcel(string fileName)
{
if (Directory.Exists(Path))
{
Directory.Delete(Path, true);
}
ZipFile.ExtractToDirectory(fileName, Path);
UnProtect(_pathWorkBook, &amp;quotworkbookProtection&amp;quot);
UnProtectionSheets();
if (!Directory.Exists(_archivePath))
{
Directory.CreateDirectory(_archivePath);
}
ZipFile.CreateFromDirectory(Path, System.IO.Path.Combine(_archivePath, System.IO.Path.Combine(_archivePath, System.IO.Path.GetFileName(fileName))));
}چون قراره چندتا فایل رو مورد لطف قرار بدیم پس قبل از هرکاری مسیر عملیات رو چک میکنیم اگر فایل های قدیمی موجود بود پاک میکنیم. با ZipFile اکسل رو اکسترکت میکنیم (نیازی نیست پسوند رو تغییر بدیم خودش xlsx رو به عنوان زیپ میشناسه) با کمک متد UnProtect و دادن مسیر فایل و تگ پروتکشن پسورد رو از فایل workbook.xml حذف میکنیم. بعدش باید پسورد رو از فایل های sheetx.xml حذف کنیم که این کارو متد UnProtectionSheets انجام میده در نهایت اگر مسیر فایل های زیپ موجود نبود ایجاد میکنیم و فایل های اصلاح شده رو دوباره به کمک ZipFile بصورت زیپ درمیاریم. (باز هم نیازی نیست پسوند zip بکنیم و تغییر بدیم به xlsx، بصورت مستقیم میتونیم بصورت xlsx زیپ کنیم)private void UnProtect(string path, string tagname)
{
XNamespace xn = &amp;quothttp://schemas.openxmlformats.org/spreadsheetml/2006/main&quot;
XDocument doc = XDocument.Load(path);
var q = from node in doc.Descendants(xn + tagname)
select node;
q.ToList().ForEach(x =&gt; x.Remove());
doc.Save(path);
}با استفاده از LinqToXml تگ موردنظر رو داخل فایل xml جستجو میکنیم و اون رو حذف میکنیم و دوباره روی فایل ذخیره میکنیم.private void UnProtectionSheets()
{
var files = Directory.EnumerateFiles(_pathSheets);
foreach (var file in files)
{
UnProtect(file, &amp;quotsheetProtection&amp;quot);
}
}چون ممکنه فایل اکسل بیشتر از یدونه شیت داشته باشه و هرکدومش با پسورد محافظت بشه برای همین با EnumerateFiles هرچی فایل داخل مسیر شیت ها باشه پیدا میکنیم و داخل حلقه با کمک همون متد قبلی پسوردشون رو حذف میکنیم.و در نهایت متد اخرمون که قراره یه مسیر از کاربر بگیره و فایل های اصلاح شده رو منتقل کنه اونجاprivate void SaveUnProtectedExcel()
{
using var fbd = new FolderBrowserDialog();
fbd.Description = &amp;quotSave UnProtected Excels&quot;
fbd.UseDescriptionForTitle = true;
fbd.ShowNewFolderButton = true;
DialogResult result = fbd.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK &amp;&amp; !string.IsNullOrWhiteSpace(fbd.SelectedPath))
{
var files = Directory.GetFiles(_archivePath);
foreach (var file in files)
{
File.Move(file, System.IO.Path.Combine(fbd.SelectedPath, System.IO.Path.GetFileName(file)), true);
}
}
}با استفاده از FolderBrowsingDialog یه مسیر از کاربر میگیریم و تمام فایل هایی که در مسیر زیپ هستن رو با File.Move به مسیر انتخابی منتقل میکنیم.</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Fri, 22 Jan 2021 10:30:08 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از فایل Json برای ذخیره و بازیابی تنظیمات برنامه</title>
                <link>https://virgool.io/CodeLovers/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D9%81%D8%A7%DB%8C%D9%84-Json-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%B0%D8%AE%DB%8C%D8%B1%D9%87-%D9%88-%D8%A8%D8%A7%D8%B2%DB%8C%D8%A7%D8%A8%DB%8C-%D8%AA%D9%86%D8%B8%DB%8C%D9%85%D8%A7%D8%AA-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-azb0rrjffra9</link>
                <description>قطعا شرایطی پیش خواهد آمد که شما مجبور شوید داده هایی را به عنوان تنظیمات برنامه در محلی ذخیره کنید و مجددا آن‌ها را فراخوانی کنید. روش‌های مختلفی برای این کار وجود دارند که معروف‌ترین و ساده‌ترین راه استفاده از Settings خود پروژه می‌باشد. اما این به منزله بهترین راه نیست! در این مطلب قصد داریم تنظیمات برنامه را در فایل json با همان ساختار استانداردش ذخیره و بازیابی کنیم.برای اینکار نیاز به سریالیز و دسریالیز کردن مدل داریم، اگر از دات نت کور استفاده میکنید کتابخانه توکار جیسون در فضای نام System.Text.Json از عهده این کار بر میاد و اگر از نسخه‌های دات نت فریمورک استفاده میکنید باید پکیج newtonsoft.json را نصب کنید.برای شروع یک کلاس به نام GlobalData (یا هر نام دلخواه دیگری) ایجاد کنید.چون قرار هست این کلاس هر نوع مدلی را برای ما سریالیز و دسریالیز کند پس کلاس را بصورت جنریک تعریف کنید.public abstract class GlobalData&lt;T&gt; where T : GlobalData&lt;T&gt;, new()حالا برای دسترسی به این کلاس یک متغیر جنریک به نام Config ایجاد میکنیمpublic static T Config { get; set; }همینطور برای خواندن فایل جیسون از محل مشخص یک متغیر دیگر به نام filename ایجاد میکنیمprivate static string _filename { get; set; }در این کلاس به 2 متد نیاز داریم، متد اول برای دسریالیز کردن فایل جیسون و متد دوم برای سریالیز کردن اطلاعات:public static void Init(string FileName = &amp;quotAppConfig.json&amp;quot)       
{            
     _filename = FileName;             
    if (File.Exists(FileName))            
    {                 
       string json = File.ReadAllText(FileName);                  
       Config = (string.IsNullOrEmpty(json) ? new T() : JsonSerializer.Deserialize&lt;T&gt;(json)) ?? new T();            
     }             
    else             
     {                
         Config = new T();             
      }         
}بصورت پیشفرض محل خواندن فایل جیسون را در کنار فایل اجرایی exe و با نام AppConfig.json در نظر میگیریم، در صورتی که فایل ما موجود بود به کمک ReadAllText محتوای فایل جیسون رو میخوانیم و در صورتی که خالی نبود اقدام به دسریالیز کردن آن میکنیم.در متد Save نیز:public static void Save()         
{            
    JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true, 
    IgnoreNullValues = true };
   string json = JsonSerializer.Serialize(Config, options); 
    File.WriteAllText(_filename, json);   
}پراپرتی Config که شامل اطلاعات ما میباشد را در محل موردنظر سریالیز میکنیم.حالا به سراغ پروژه دمو میرویم، یک کلاس ایجاد میکنیم و از کلاس GlobalData ارث بری میکنیم:internal class AppConfig : GlobalData&lt;AppConfig&gt;حالا پراپرتی‌های دلخواه خود را ایجاد میکنیم:
public string ServerUrl { get; set; } = &amp;quothttps://sub.deltaleech.com&quot;  
public bool IsShowNotification { get; set; } = true;  
public NavigationViewPaneDisplayMode PaneDisplayMode { get; set; } = NavigationViewPaneDisplayMode.Left;   
public SkinType Skin { get; set; } = SkinType.Default;دقت کنید که قبل از خواندن تنظیمات باید ابتدا فایل تنظیمات را دسریالیز کرده باشید پس هنگام اجرای پروژه متد Init را فراخوانی کنید:protected override void up(StartupEventArgs e) {
GlobalData&lt;AppConfig&gt;.Init();
}برای خواندن تنظیمات به این صورت عمل کنید:var skin = GlobalData&lt;AppConfig&gt;.Config.Skin;و برای ذخیره کردن :GlobalData&lt;AppConfig&gt;.Config.Skin = Skin.Dark;
GlobalData&lt;AppConfig&gt;.Save();دقت داشته باشید که اگر بعد از ذخیره کردن تنظیمات قصد داشته باشید اطلاعات جدید را دریافت کنید باید حتما قبل از دریافت اطلاعات متد Init را یکبار دیگر فراخوانی کنید تا اطلاعات جدید نمایش داده شود.</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Sat, 02 Jan 2021 18:27:20 +0330</pubDate>
            </item>
                    <item>
                <title>گوش دادن به تغییرات تم ویندوز 10 بدون نیاز به WinRT در سی شارپ</title>
                <link>https://virgool.io/@mahdi72/%DA%AF%D9%88%D8%B4-%D8%AF%D8%A7%D8%AF%D9%86-%D8%A8%D9%87-%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1%D8%A7%D8%AA-%D8%AA%D9%85-%D9%88%DB%8C%D9%86%D8%AF%D9%88%D8%B2-10-%D8%A8%D8%AF%D9%88%D9%86-%D9%86%DB%8C%D8%A7%D8%B2-%D8%A8%D9%87-WinRT-%D8%AF%D8%B1-%D8%B3%DB%8C-%D8%B4%D8%A7%D8%B1%D9%BE-mosfzokjpfux</link>
                <description>امروز میخواستم برای یکی از پروژه هام قابلیتی رو پیاده سازی کنم که هماهنگ با تم ویندوز، تم برنامه رو عوض کنه (تیره/روشن). ینی وقتی تم ویندوز Dark میشه تم برنامه من هم Dark بشه و برعکس.ساده ترین کار اینه که ما بیایم از کدهای WinRT که توسط بسته ناگت SDK Contract ارائه میشه استفاده کنیم. در این صورت کافیه فقط از کلاس ThemeManager استفاده کنیم و بدون کوچکترین خونریزی برناممون رو به این ویژگی مجهز کنیم? اما خب هرچیزی هزینه خودش رو داره و من به شخصه خوشم نمیاد 25 مگابایت فقط برای شناسایی وضعیت تم ویندوز خرج کنم! پس خودم دست به کار شدم تا یه Listener توپ بنویسم.در دات نت یسری ایونت هست که مربوط به سیستم عامل میشن و از کلاس SystemEvents قابل دسترسی هست اینجا یه ایونت داریم به اسم UserPreferenceChanged که شامل مواردی میشه که کاربر تنظیمات ویندوز رو تغییر میده! هر تغییری که تو تنظیمات ویندوز اعمال بشه درون یکی از Category ها صدا زده میشه. پس اگر ما این ایونت رو رجیستر کنیم هر موقع تغییری تو تنظیمات ویندوز اعمال بشه برنامه ما متوجه میشه! پس این شدقدم اول:یه کلاس درست میکنیم و توی متد سازنده این ایونت رو رجیستر میکنیم:public ThemeHelper()
{
 SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
}

private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
switch (e.Category)
{
case UserPreferenceCategory.Accessibility:
break;
case UserPreferenceCategory.Color:
break;
case UserPreferenceCategory.Desktop:
break;
case UserPreferenceCategory.General:
break;
case UserPreferenceCategory.Icon:
break;
case UserPreferenceCategory.Keyboard:
break;
case UserPreferenceCategory.Menu:
break;
case UserPreferenceCategory.Mouse:
break;
case UserPreferenceCategory.Policy:
break;
case UserPreferenceCategory.Power:
break;
case UserPreferenceCategory.Screensaver:
break;
case UserPreferenceCategory.Window:
break;
case UserPreferenceCategory.Locale:
break;
case UserPreferenceCategory.VisualStyle:
break;
}
}همینطور که میبینید دسته بندی شامل موارد مختلفی میشه که به بخش های مختلف تنظیمات مربوطه تنظیمات مربوط به تم درون General صدا زده میشه پس کدهای ما قراره وارد این قسمت بشه.متاسفانه این ایونت اطلاعات کاملتری رو به ما نمیده و فقط اطلاع میده که اینجا یه تغییری رخ داده (همینطور که قبلا گفتم هرچیزی یه هزینه ای داره?) پس ما خودمون میایم مشخصات تم فعلی رو دریافت میکنیم اما از کجا؟ معلومه رجیستری! همه چیز توی رجیستری ثبت میشه و براحتی قابل دسترسی هست پس یه متد مینویسم که کلید رجیستری مربوطه رو بخونه و اونو بصورت یه مدل (Light یا Dark) برگردونه:private const string RegistryKeyPathTheme = @&amp;quotSoftware\Microsoft\Windows\CurrentVersion\Themes\Personalize&quot;
private const string RegSysMode = &amp;quotSystemUsesLightTheme&quot;
public static UITheme GetWindowsTheme()
{
return GetThemeFromRegistry(RegSysMode);
}
private static UITheme GetThemeFromRegistry(string registryKey)
{
using var key = Registry.CurrentUser.OpenSubKey(RegistryKeyPathTheme);
var themeValue = key?.GetValue(registryKey) as int?;
return themeValue != 0 ? UITheme.Light : UITheme.Dark;
}
public enum UITheme
{
Light,
Dark
}حالا ما نیاز به یه ایونت داریم که کاربر بتونه اونو توی برنامه خودش رجیستر کنه و نیازی به پیاده سازی این کدها نداشته باشه پس یه EventHandler به اسم WindowsThemeChanged ایجاد میکنیم:public event EventHandler&lt;FunctionEventArgs&lt;UIWindowTheme&gt;&gt; WindowsThemeChanged;
protected virtual void OnWindowsThemeChanged(UIWindowTheme theme)
{
EventHandler&lt;FunctionEventArgs&lt;UIWindowTheme&gt;&gt; handler = WindowsThemeChanged;
handler?.Invoke(this, new FunctionEventArgs&lt;UIWindowTheme&gt;(theme));
}من میخام که کاربر، مقدار تم فعلی و رنگ Accent فعلی رو بتونه از طریق این ایونت دریافت بکنه پس من باید خودم یه EventArgs ایجاد بکنم و پراپرتی های دلخواه من رو داشته باشه برای همین کلاس FunctionEventArgs رو ایجاد میکنم:public class FunctionEventArgs&lt;T&gt; : RoutedEventArgs
{
public FunctionEventArgs(T theme)
{
Theme = theme;
}
public FunctionEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source){}
public T Theme { get; set; }
}این کلاس از RoutedEventArgs ارث بری کرده و بصورت جنریک پیاده سازی شده، به این معنی که ما میتونیم هر نوع دلخواهی که خواستیم به عنوان arg استفاده بکنیم? اگر دقت بکنید من یک مدل دلخواه رو به عنوان arg مشخص کردم:FunctionEventArgs&lt;UIWindowTheme&gt;من میتونستم از همون UITheme هم استفاده بکنم ولی نمیتونستم مقدار Accent رو هم به کاربر برگردونم واسه همین یه مدل به اسم UIWindowTheme ساختم:public class UIWindowTheme
{
public Brush AccentBrush { get; set; }  
public UITheme CurrentTheme { get; set; }  
}کار تمومه حالا باید بیایم داخل متد SystemEvents_UserPreferenceChanged و بگیم که وقتی تنظیمات ویندوز عوض شد چه اتفاقی بیوفته (دقت کنید که کد باید داخل بخش General نوشته بشه): case UserPreferenceCategory.General:
var changedTheme = new UIWindowTheme()
{
AccentBrush = SystemParameters.WindowGlassBrush,
CurrentTheme = GetWindowsTheme()
};
OnWindowsThemeChanged(changedTheme);
break;یه مدل ایجاد میکنیم و مقدار AccentBrush رو برابر با WindowGlassBrush قرار میدیم این پراپرتی هم مثل ایونتی که اول معرفی کردم مربوط میشه به سیستم عامل و رنگ فعلی Accent رو برمیگردونه، برای مقدار CurrentTheme هم متدی که بالاتر برای دریافت تم فعلی از رجیستری نوشتیم رو صدا میزنیم و در پایان این مدل رو به ایونتمون پاس میدیم.حالا اگر بریم سراغ یه برنامه دمو به این صورت میتونیم پیاده سازی کنیم:ThemeHelper tm = new ThemeHelper();
tm.WindowsThemeChanged +=OnWindowsThemeChanged;وprivate void OnWindowsThemeChanged(object? sender, FunctionEventArgs&lt;RegistryThemeHelper.UIWindowTheme&gt; e)
{
rec.Fill = e.Theme.AccentBrush;
if (e.Theme.CurrentTheme == RegistryThemeHelper.UITheme.Light)
{
Background = Brushes.White;
}
else
{
Background = Brushes.Black;
}
}اینم از نتیجه:</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Thu, 31 Dec 2020 16:31:36 +0330</pubDate>
            </item>
                    <item>
                <title>نگاهی به توسعه و بهبود HandyWinget</title>
                <link>https://virgool.io/@mahdi72/%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D9%87-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D9%88-%D8%A8%D9%87%D8%A8%D9%88%D8%AF-handywinget-yxad5awq42ns</link>
                <description>بلاخره بعد از 4 ماه یه فرصت پیدا کردم تا دوباره بتونم اینجا از کارام بنویسم.چند ماه پیش که مایکروسافت Winget رو منتشر کرد من هم بلافاصله یه رابط کاربری براش زدم تا افرادی که با Cli اشنایی ندارن راحت تر بتونن با این پلتفرم ارتباط برقرار کنن. (قبلا اینجا راجبش نوشتم) راستش اون موقع فکر نمیکردم که این برنامه جا بیوفته و طرفدار پیدا بکنه واسه همین اخیرا تصمیم گرفتم تا یه دستی رو سرش بکشم و بهترش کنم.انگلیسی ها و المانی ها کاربران وفادار❤اینجا میخایم نسخه جدید برنامه رو با هم یه بررسی بکنیم و ببینیم که چطور میتونیم رابط کاربری رو بهتر بکنیم و تجربه بهتری رو برای کاربر ایجاد کنیم.اول ببینیم که نسخه اول چطوری کار میکنه!خب خیلی سادست من به کمک Process دستورات مربوط به دانلود پکیج هارو به cmd میفرستم و cmd پاسخ اون دستور رو به من برمیگردونه و من با خوندن خط به خط اون ها به کاربر گزارش میدم که در چه مرحله ای هستش.این تصویر نسخه اول هستشحالا بریم سراغ نسخه دوم?اولین کاری که کردم یه رابط کاربری استاندارد تر و بهینه تری رو برای برنامه ایجاد کردم. خودم که خیلی حال کردم? (البته بماند که همین منوی ناوبری دهنمو سرویس کرد مجبور شدم کتابخونه رو مجددا پورتش کنم و وابستگی WinRT رو حذفش کنم?)دومین کاری که کردم این بود که نسخه اول بدلیل اینکه با winget در ارتباطه امکان استفاده روی نسخه های قبلی ویندوز رو نداره چون winget روی رنج خاصی از ویندوز 10 نصب میشه و امکان نصب روی نسخه های قدیمی تر رو نداره! پس من تصمیم گرفتم که توی نسخه 2 وابستگی به winget رو حذف کنم تا بتونیم از پکیج منیجر روی نسخه های قدیمی تر ویندوز هم استفاده کنیم کافی بود بجای اینکه دستور دانلود رو به winget ارسال کنم، خودم اون فایل رو دانلود کنم. البته همچنان امکان دانلود با winget موجودهکاربر امکان انتخاب حالت دانلود و نصب برنامه ها را دارد (داخلی/وینگت)سومین کار این بود که نحوه دریافت مانیفست هارو تغییر بدم. نسخه 1 از یه کتابخونه به اسم libgit2sharp استفاده میکرد تا بتونه Repo مربوط به مانیفست هارو از گیتهاب دریافت کنه. متاسفانه این کتابخونه به فایل pdb وابسته بود و امکان حذف این فایل نبود به طوری که اگه حذف میکردم برنامه اجرا نمیشد. از طرفی هم حدود 8 مگ حجم داشت و امکان Embed کردن داخل exe رو هم نداشت. پس تصمیم گرفتم این کتابخونه رو حذف کنم و خودم بیام مخزن مانیفست رو دانلود کنم. نتیجه خیلی بهتر شد و حالا میتونم به کاربر درصد پیشرفت دانلود رو نشون بدم. نسخه 2.1 که در حال توسعه هستش امکان نمایش حجم دانلود شده از حجم کلی رو هم نشون میدهچهارمین کار این بود که بیام لیست برنامه های نصب شده رو نشون بدم. نسخه اول این کارو انجام میداد ولی توانایی شناسایی همه برنامه های نصب شده رو نداشت. این کار به کمک کلیدهای رجیستری انجام میشه و برنامه با اسکن کردن رجیستری برنامه های نصب شده رو شناسایی میکنه. تو نسخه 2 این مورد رو بهبود دادم و حالا برنامه میتونه موارد بیشتری رو تشخیص بده اگه بگیم نسخه اول 60 درصد برنامه هارو شناسایی میکنه باید بگم که نسخه دوم 99 درصد برنامه هارو شناسایی میکنه. خود winget هم امکان شناسایی برنامه های نصب شده رو در اخرین نسخه منتشر شده بصورت آزمایشی اضافه کرده ولی خب کمی کنده و همه برنامه هارو شناسایی نمیکنه (واقعا نمیدونم اون برنامه نویس های مایکروسافت دقیقا چه غلطی میکنن?) از طرفی چون برنامه من قراره روی نسخه های قدیمی ویندوز هم اجرا بشه پس نباید به winget وابستگی داشته باشه واسه همین نیاز بود که این مورد رو حتما بهبود بدم گرچه همین ویژگی مایکروسافت رو هم به برنامه اضافه کردم که کاربر میتونه نحوه شناسایی برنامه هارو انتخاب کنه.باقی موارد رو از دید گیف ببینیم ?نمایش مشخصات پکیج امکان نصب نسخه های مختلفامکان نصب چندین برنامه بصورت همزمانامکان خروجی گرفتن اسکریپت نصب پکیج ها با فرمت پاورشلبهبود گزارش فعالیت های برنامه بهبود گزارش فعالیت های برنامهامکان گروه بندی بر اساس ناشردر پایان اینکه نسخه جدید خیلی خیلی از نسخه اول سریعتر،بهتر و ویژگی های بهتری رو داره.بیشتر این ویژگی ها توسط winget هنوز پشتیبانی نمیشه و برنامه ای براش ندارن مثل امکان نصب چندین برنامه پشت سرهم بدون اینکه شما کار اضافه ای بکنید فقط انتخاب کنید و بوم!همینطور که توی گیف دیدید برنامه این امکان رو میده که شما پکیج های موردنظرتون رو انتخاب کنید و اسکریپت پاورشل نصب اون رو بصورت خروجی دریافت کنید شما میتونید این پاورشل رو روی هر سیستمی که خواستید اجرا کنید و پکیج های انتخابیتون رو نصب کنید.واقعا ویژگی خفنی هستش و برای کسایی که برنامه های زیادی رو نصب میکنن کاربردی! الان که این متن رو نوشتم به ذهنم رسید که امکان Execute کردن پکیج های پاورشل رو به برنامه اضافه کنم قطعا چیز خفنی میشه? در پایان اینکه handywinget با اختلاف زیادی از تمامی نمونه های مشابه یه سرو گردن بالاتره و ویژگی های بهتری رو به کاربر ارائه میده.?خوش باشید/HandyOrg/HandyWinGet: GUI for installing apps through WinGet and Creating Yaml file &#40;github.com&#41;</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Mon, 28 Dec 2020 20:19:42 +0330</pubDate>
            </item>
                    <item>
                <title>HandyUI: طراحی رابط کاربری Dribbble در WPF</title>
                <link>https://virgool.io/@mahdi72/handyui-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D8%B1%D8%A7%D8%A8%D8%B7-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%DB%8C-dribbble-%D8%AF%D8%B1-wpf-pdnqda66y7lg</link>
                <description>از سال پیش برنامه داشتم که بیام یسری از طراحی های سایت Dribbble رو داخل WPF ایجاد کنم یعنی تصاویر مربوط به UI که داخل سایت Dribbble هستن رو بصورت کد xaml داخل WPF ایجاد کنم.امروز بلاخره این پروژه رو تحت نام HandyUI عملی کردم?فعلا 3 تا از طرح های قشنگ رو پیاده سازی کردم یکیش بورد کانبان هست
یکی دیگش ارز کشور ها هستو آخری هم اپلود عکس داخل ابرفعلا این 3 تا رو کدنویسی کردم لازم به ذکر هست که تمامی آیکون ها بصورت کدهای xaml از نوع (DrawingImage یا Geometry) ایجاد شدن و از فایل های png , jpg و... استفاده نشده.در پایان اگر طرح قشنگی دارید برام بفرستید تا اگر تونستم (سخت نباشه?) به پروژه HandyUI اضافه کنم.و اینکه سورس برنامه اینجا قابل دسترسی هست?</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Wed, 12 Aug 2020 17:27:10 +0430</pubDate>
            </item>
                    <item>
                <title>صفحه پروفایل Github خودتون رو خوشگل کنید</title>
                <link>https://virgool.io/@mahdi72/%D8%B5%D9%81%D8%AD%D9%87-%D9%BE%D8%B1%D9%88%D9%81%D8%A7%DB%8C%D9%84-github-%D8%AE%D9%88%D8%AF%D8%AA%D9%88%D9%86-%D8%B1%D9%88-%D8%AE%D9%88%D8%B4%DA%AF%D9%84-%DA%A9%D9%86%DB%8C%D8%AF-swc3tibqphuf</link>
                <description>مثل اینکه گیتهاب شامل یسری چیزهای مخفی هستش به این صورت اگر یه کار خاصی رو انجام بدید یه قابلیتی برای شما فعال میشه/برای مثال اگر یه پروژه به اسم اکانت خودتون ایجاد بکنید یه فایل Readme داخل صفحه پروفایلتون نمایش داده میشهبه عنوان مثال اگر اسم اکانتتون ghost1372 باشه یه مخزن به اسم ghost1372 بسازید یه فایل readme داخل پروفایل شما نمایش داده میشه/یه کاربر خوش ذوق هم یه api اماده کرده که باهاش میشه یسری مشخصات راجب اکانت گیتهابتون بصورت کارت دریافت کرد به این صورت که مثلا چندتا کامیت زدید، چندتا ستاره گرفتید و...برای نمایش مشخصات اکانت گیتهابتون از کد زیر داخل فایل md استفاده کنید&lt;a href=&amp;quothttps://github.com/ghost1372&amp;quot&gt;
&lt;img align=&amp;quotcenter&amp;quot src=&amp;quothttps://github-readme-stats.vercel.app/api?username=ghost1372&amp;show_icons=true&amp;count_private=true&amp;include_all_commits=true&amp;quot /&gt;&lt;/a&gt;کد رو ویرایش کنید و اکانت خودتون رو بنویسید.برای نمایش لیست زبان های مورد استفاده هم از این کد استفاده کنید&lt;a href=&amp;quothttps://github.com/ghost1372&amp;quot&gt;
&lt;img align=&amp;quotcenter&amp;quot src=&amp;quothttps://github-readme-stats.vercel.app/api/top-langs/?username=ghost1372&amp;quot /&gt;
&lt;/a&gt;دوباره فراموش نکنید که اکانت خودتون رو بنویسیداگر خواستید میتونید از تم های مختلف هم استفاده کنید کافیه عبارت زیر رو به آخر api اضافه کنید&amp;theme=draculaتم های موجود:dark, radical, merko, gruvbox, tokyonight, onedark, cobalt, synthwave, highcontrast, dracula</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Sun, 09 Aug 2020 21:53:11 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش ساخت پروگرس بار همراه با انیمیشن در WPF</title>
                <link>https://virgool.io/@mahdi72/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D8%B3%D8%A7%D8%AE%D8%AA-%D9%BE%D8%B1%D9%88%DA%AF%D8%B1%D8%B3-%D8%A8%D8%A7%D8%B1-%D9%87%D9%85%D8%B1%D8%A7%D9%87-%D8%A8%D8%A7-%D8%A7%D9%86%DB%8C%D9%85%DB%8C%D8%B4%D9%86-%D8%AF%D8%B1-wpf-qmgfzge7kl2u</link>
                <description>اگر دوست دارید بدونید که پروگرس بار های دایره چطوری ساخته میشن کافیه این پست رو دنبال کنید.قطعا بارها شده پروگرس بارهای مختلفی رو دیدید و دوست داشتید که خودتون هم یکیش رو بسازید و ولی نمیدونستید که چطور همچین انیمیشن های جذابی رو پیاده سازی کنید.چون من در پلتفرم WPF برنامه نویسی میکنم این پست در محیط Visual Studio و پلتفرم WPF پیاده سازی میشه.من قصد دارم این پروگرس بار رو پیاده سازی کنم:اول باید این رو انالیز کنیم ببینیم چه اتفاقی داره میوفته تا بعد بتونیم پیاده سازیش کنیم: 1 شکل دایره ثابت داریم و 1 شکل دایره متحرکدایره ابی رنگ هم اندازش تغییر میکنه هم مکانشبا دونستن همین 2 مورد کارمون رو شروع میکنیم:یه دایره ثابت روی Window قرار میدیم:&lt;Ellipse Width=&amp;quot14&amp;quot Height=&amp;quot14&amp;quot StrokeThickness=&amp;quot2&amp;quot Stroke=&amp;quot#EDEDED&amp;quot/&gt;طول و عرض 14 و ضخامتش 2 رنگش هم خاکستری میشه حالا دایره متحرک رو ایجاد میکنیم:&lt;Ellipse x:Name=&amp;quotSpinner&amp;quot Width=&amp;quot14&amp;quot Height=&amp;quot14&amp;quot StrokeThickness=&amp;quot2&amp;quot local:EllipseHelper.StrokeDashArrayValue=&amp;quot0.01&amp;quot StrokeDashCap=&amp;quotRound&amp;quot Stroke=&amp;quot#0078D4&amp;quot RenderTransformOrigin=&amp;quot0.5,0.5&amp;quot&gt;
&lt;Ellipse.RenderTransform&gt;
&lt;RotateTransform x:Name=&amp;quotRT&amp;quot Angle=&amp;quot-90&amp;quot/&gt;
&lt;/Ellipse.RenderTransform&gt;
&lt;Ellipse.Triggers&gt;
&lt;EventTrigger RoutedEvent=&amp;quotLoaded&amp;quot&gt;
&lt;BeginStoryboard&gt;
&lt;Storyboard Name=&amp;quotspinInfinite&amp;quot Duration=&amp;quot0:0:2&amp;quot RepeatBehavior=&amp;quotForever&amp;quot&gt;
&lt;DoubleAnimationUsingKeyFrames Storyboard.TargetName=&amp;quotRT&amp;quot Storyboard.TargetProperty=&amp;quotAngle&amp;quot&gt;
&lt;LinearDoubleKeyFrame KeyTime=&amp;quot0:0:0&amp;quot Value=&amp;quot0&amp;quot/&gt;
&lt;LinearDoubleKeyFrame KeyTime=&amp;quot0:0:1&amp;quot Value=&amp;quot450&amp;quot/&gt;
&lt;LinearDoubleKeyFrame KeyTime=&amp;quot0:0:2&amp;quot Value=&amp;quot1080&amp;quot/&gt;
&lt;/DoubleAnimationUsingKeyFrames&gt;
&lt;DoubleAnimationUsingKeyFrames Storyboard.TargetName=&amp;quotSpinner&amp;quot Storyboard.TargetProperty=&amp;quot(local:EllipseHelper.StrokeDashArrayValue)&amp;quot&gt;&lt;LinearDoubleKeyFrame KeyTime=&amp;quot0:0:0&amp;quot Value=&amp;quot0.01&amp;quot/&gt;
&lt;LinearDoubleKeyFrame KeyTime=&amp;quot0:0:1&amp;quot Value=&amp;quot9&amp;quot/&gt;
&lt;LinearDoubleKeyFrame KeyTime=&amp;quot0:0:2&amp;quot Value=&amp;quot0.01&amp;quot/&gt;&lt;/DoubleAnimationUsingKeyFrames&gt;
&lt;/Storyboard&gt;
&lt;/BeginStoryboard&gt;
&lt;/EventTrigger&gt;
&lt;/Ellipse.Triggers&gt;
&lt;/Ellipse&gt;یه دایره ابی رنگ تعریف کردیم که ضخامتش مثل قبلیه، گوشه های اون رو بصورت دایره ای گرد کردیم بعد مکان پیشفرضش برای شروع چرخش رو -90 درجه درنظر گرفتیم همینطور بهش گفتیم وقتی که لود شد یه استوری بورد ایجاد کنه که بصورت دائمی درحال اجرا باشه و بیاد 2 تا انیمیشن رو همزمان اجرا کنه، یکیش برای تغییر زاویه که توی 3 تا فریم انجام میشه و زاویه رو بین 0، 450 و 1080 تغییر میده و برای اینکه پروگرس بار جذاب بشه و حالت کش اومدن پیدا کنه وقتی که داره عملیات چرخش انجام میشه طول اون رو هم تغییر میدیم پس یه انیمیشن دیگه ایجاد میکنیم و توی 3 تا فریم مقدارش رو بین 0.01،9،0.01 تغییر میدیم.چون مقدار StrokeDashArray بصورت DoubleCollection هستش امکان مقدار دهی اون در استوری بورد نیستش برای همین یه AttachedProperty به اسم StrokeDashArrayValue میسازیم که بیاد مقدار دریافتی رو تبدیل کنه به doubleCollection:internal class EllipseHelper
{
public static readonly DependencyProperty StrokeDashArrayValueProperty = DependencyProperty.RegisterAttached(
&amp;quotStrokeDashArrayValue&amp;quot, typeof(double), typeof(EllipseHelper), new PropertyMetadata(0.0, OnStrokeDashArrayValueChanged));
public static double GetStrokeDashArrayValue(Ellipse ellipse)
{
return (double)ellipse.GetValue(StrokeDashArrayValueProperty);
}
public static void SetStrokeDashArrayValue(Ellipse ellipse, double value)
{
ellipse.SetValue(StrokeDashArrayValueProperty, value);
}
private static void OnStrokeDashArrayValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Ellipse ellipse)
{
var value = (double)e.NewValue;
ellipse.StrokeDashArray = new DoubleCollection() { value, 100 };
}
}
} نتیجه میشه چیزی که توی عکس میبینید</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Mon, 03 Aug 2020 09:52:14 +0430</pubDate>
            </item>
                    <item>
                <title>راه اندازی Powerline در ترمینال ویندوز</title>
                <link>https://virgool.io/coderlife/%D8%B1%D8%A7%D9%87-%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C-powerline-%D8%AF%D8%B1-%D8%AA%D8%B1%D9%85%DB%8C%D9%86%D8%A7%D9%84-%D9%88%DB%8C%D9%86%D8%AF%D9%88%D8%B2-isgswlh9c5jh</link>
                <description>دوست دارید که یه ترمینال خوشگل داشته باشید؟پاورلاین به ما کمک میکنه که ترمینالمون رو خوشگل کنیم. Powerline یک تجربه سریع فرمان سفارشی را فراهم می کند و وضعیت کدگذاری رنگ و درخواست های وضعیت Git را ارائه می دهد. (ترجمه گوگله ?)تو این مطلب شما 3 تا چیز یاد میگیرین:راه اندازی پاورلاین در پاورشلراه اندازی پاورلاین در WSLحل مشکل گلیف ها (کاراکتر یا ایکون هایی که تو فونت موجود نیست)برای راه اندازی پاورلاین ما از terminal جدید مایکروسافت که از اینجا قابل دریافت هست استفاده میکنیم (اگر ترمینال رو ندارید شما میتونید از خود powershell هم استفاده کنید)راه اندازی پاورلاین در پاورشلpowershell  رو باز کنید و دستورات زیر رو برای نصب ماژول های موردنیاز ارسال کنید Install-Module posh-git -Scope CurrentUser
Install-Module oh-my-posh -Scope CurrentUserماژول اول وضعیت git رو در ترمینال مشخص میکنه و ماژول دوم تم رو در ترمینال فعال میکنهبعد از نصب ماژول ها دستور زیر رو بزنید تا فایل پروفایل برای تنظیمات ایجاد بشهnotepad $PROFILEحالا دستورات زیر رو کپی کنید داخل فایل و ذخیرش کنیدImport-Module posh-git 
Import-Module oh-my-posh 
Set-Theme Paradoxتا اینجا ماژول هارو نصب کردیم و به پاورشل گفتیم که وقتی اجرا میشه 2 تا ماژول رو بارگذاری کنه و تم رو روی paradox قرار بده (در صورت نیاز میتونید تم دیگه ای رو بصورت پیشفرض قرار بدید)لیست تم های موجود اینجا لیست شدهاگر خواستید تم رو عوض کنید میتونید از پاورشل دستور زیر رو ارسال کنیدSet-Theme paradoxحل مشکل گلیف هابرای حل این مشکل باید از فونت هایی استفاده کنید که از گلیف ها پشتیبانی بکنن برای شروع میتونید از فونت Cascadia Code PL استفاده کنید.از اینجا فونت هارو دانلود کنید و با دابل کلیک روی فونت روی ویندوزتون نصبش کنیداگر Cascadia رو دوست ندارید از اینجا میتونید فونت های دیگه ای رو انتخاب کنیدحالا باید به ترمینال بگیم که از فونت جدید استفاده کنه اگر از ترمینال جدید استفاده میکنید از منو Settings رو بزنید و داخل فایل جیسون گزینه زیر رو به قسمت پاورشل (یا هر پروفایل دیگه که لازم دارید) اضافه کنید&amp;quotfontFace&amp;quot: &amp;quotCascadia Code PL&amp;quot,پروفایل پاورشلتون یچیزی باید تو این مایه ها بشه{     
     // Make changes here to the powershell.exe profile.     
     &amp;quotguid&amp;quot: &amp;quot{61c54bbd-c2c6-5271-96e7-009a87ff44bf}&amp;quot,
     &amp;quotname&amp;quot: &amp;quotWindows PowerShell&amp;quot,
     &amp;quotcommandline&amp;quot: &amp;quotpowershell.exe&amp;quot,
     &amp;quotfontFace&amp;quot: &amp;quotCascadia Code PL&amp;quot,
     &amp;quothidden&amp;quot: false
},اگر از خود برنامه پاورشل استفاده میکنید روی Title راست کلیک بزنید و از Properties قسمت Fontfamily فونت جدید رو انتخاب کنید.ترمینال رو ببندید و دوباره باز کنید حالا میتونید از ترمینال قشنگتون بیشتر لذت ببرید.?راه اندازی پاورلاین در WSLاگر میخواید تو ترمینال Bash که از طریق WSL ویندوز اجرا میشه هم این تم رو پیاده سازی کنید مراحل زیر رو انجام بدیداول پکیج go رو نصب کنید و بعد پروژه پاورلاین رو با گو دریافت کنیدsudo apt install golang-go 
go get -u github.com/justjanne/powerline-goفایل .bashrc رو پیدا کنید (تو قسمت home/user موجوده این فایل) و کدهای زیر رو به انتهاش اضافه کنیدمیتونید برید به محل home/user و بعد دستور زیر رو اول بزنید تا ادیتور متن برای شما باز بشه بعد کدهارو کپی کنید:notepad ./bashrcیاcode ./bashrcبعد این کدهارو داخل فایل کپی و ذخیره کنیدGOPATH=$HOME/go
function _update_ps1() {
    PS1=&amp;quot$($GOPATH/bin/powerline-go -error $?)&amp;quot
}
if [ &amp;quot$TERM&amp;quot != &amp;quotlinux&amp;quot ] &amp;&amp; [ -f &amp;quot$GOPATH/bin/powerline-go&amp;quot ]; then
    PROMPT_COMMAND=&amp;quot_update_ps1; $PROMPT_COMMAND&amp;quot
fiاینم نتیجش:</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Sun, 26 Jul 2020 14:28:36 +0430</pubDate>
            </item>
                    <item>
                <title>دسترسی به کدهای سی++ در زبان های مدیریت شده توسط P/Invoke</title>
                <link>https://virgool.io/coderlife/%D8%AF%D8%B3%D8%AA%D8%B1%D8%B3%DB%8C-%D8%A8%D9%87-%DA%A9%D8%AF%D9%87%D8%A7%DB%8C-%D8%B3%DB%8C-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%B4%D8%AF%D9%87-%D8%AA%D9%88%D8%B3%D8%B7-pinvoke-l7juzvp37plw</link>
                <description>مدت ها بود که موضوع مناسبی به ذهنم نمیرسید تا در موردش بنویسم، تا اینکه همین الان بصورت اتفاقی P/Invoke یادم افتاد. برای من که مسئله جالبی هستش، گفتم بنویسم شاید بدرد شما هم خورد?طبق تعریفی که خود مایکروسافت ارائه میکنه، P/Invoke یه تکنولوژی هستش که به ما اجازه میده به تابع ها(functions) ، ساختارها(structs) و کالبک ها(callbacks) تو کدهای مدیریت نشده سی++ دسترسی داشته باشیم!به عبارت ساده تر ما میتونیم از کتابخونه های سی++، یا کتابخونه های خود ویندوز توی زبان های برنامه نویسی مثل سی شارپ C# استفاده کنیم.اگر باز هم متوجه قضیه نشدید بزارید بیشتر توضیح بدم:خود ویندوزی که دارید ازش استفاده میکنید برای انجام دادن فعالیت ها، کدهاش رو داخل کتابخونه هایی با پسوند dll قرار داده و چون این کتابخونه ها اکثرا با سی++ نوشته شدن بصورت کدهای مدیریت نشده هستن (حالا با اینش کار نداریم) ما میتونیم کارهایی که ویندوز انجام میده رو با سی شارپ یا زبون های دیگه انجامش بدیم، مثلا گرفتن اسم پنجره ها، مخفی کردن پنجره ها، تغییرات توی taskbar و هزار جور کار دیگه اینجاس که بحث p/invoke میاد وسط، پی اینووک مثل یه پل ارتباطی میمونه که میاد امکان دسترسی به این کدها رو برای ما فراهم میکنه/ در ادامه میخوام نحوه استفاده از p/invoke رو اموزش بدم ولی قبلش میخوام بهتون آموزش بدم که برنامه نویس های سی++ چطوری این امکان رو فراهم میکنن?برای این کار یه پروژه خالی سی++ ایجاد کنید (خروجی پروژه باید یه dynamic library dll باشه) حالا از هر محیطی خواستید استفاده کنید مهم نیست مهم اینه که خروجی شما فایل dll باشهپوشه ها و فایل های ایجاد شده رو حذف کنید و خودتون یه فایل cpp ایجاد کنید.داخل این فایل یه متد مینویسیم که برای ما متن سلام رو چاپ کنه:#include &lt;iostream&gt;
void WriteHello()
{
std::cout &lt;&lt; &amp;quotHello&amp;quot
}من میخوام کاری کنم که یه برنامه نویس تو زبان سی شارپ بتونه این متد رو فراخوانی کنه و ازش استفاده کنه پس کد زیر رو باید بنویسیم:extern &amp;quotC&amp;quot __declspec(dllexport) void WriteHello();نکته مهم اینکه نوع بازگشتی تابع و اسم تابع باید دقیقا در عبارت بالا نوشته بشه که توی مثال ما نوع بازگشتی تابع void و اسم تابع WriteHello بود.کافیه پروژه رو کامپایل کنیم و فایل dll رو کپی کنیم کنار فایل Exe که قرار هست با سی شارپ بنویسیم?حالا که فایل dll رو اماده کردیم یه پروژه با سی شارپ ایجاد کنید (از نوع کنسول ایجاد کنید تا عملکرد برنامه قابل مشاهده باشه چون قراره یه متنی رو cout کنه تو کنسول چاپ میشه)اول باید فایل dll رو معرفی کنیم:[DllImport(&amp;quotmylibrary.dll&amp;quot)]بعد باید تابعی که میخوایم ازش استفاده کنیم رو اسمش رو بنویسیم (حتما باید زیر عبارت بالا بنویسیم وگرنه خطا میگیریم):public static extern void WriteHello();اینجا هم باید حواسمون باشه که اسم تابع و نوع بازگشتی رو دقیق بنویسیم، حالا اگر تابع WriteHello(); رو هرجا که بخوایم بنویسیم کدهایی که تو سی++ داخل متد نوشته شده اجرا میشه?به این مراحلی که انجام دادیم P/Invoke میگویند?البته باید دقت کرد اگر تابع پارامتر ورودی یا متغیر بازگشتی داشت نوعشون باید به درستی انتخاب بشه چون برخی از نوع های متغیرها توی کدهای مدیریت نشده و مدیریت شده فرق داره مثل string که توی سی شارپ string هست ولی توی سی++ فرق میکنه مایکروسافت لیستی از این نوع هارو داخل جدولی اینجا ارائه کرده که میتونید مطالعه کنید.در اخر شاید این مثال رو که تایتل پنجره فعال تو ویندوز رو میگیره و توی مسیج باکس نشون میده رو بهتر درک کنید:[DllImport(&amp;quotuser32.dll&amp;quot)]
static extern IntPtr GetForegroundWindow();

[DllImport(&amp;quotuser32.dll&amp;quot)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

private string GetActiveWindowTitle()
{
    const int nChars = 256;
    StringBuilder Buff = new StringBuilder(nChars);
    IntPtr handle = GetForegroundWindow();
    if (GetWindowText(handle, Buff, nChars) &gt; 0)
    {
        return Buff.ToString();
    }
    return null;
}

MessageBox.Show(GetActiveWindowTitle());اینجا از 2 تا تابع استفاده شده یکی GetForegroundWindow که میاد پنجره ای که بالاتر از همه پنجره ها هست (اونی که فعاله و فوکوس روشه) رو انتخاب میکنه و GetWindowText تایتل اون پنجره رو دریافت میکنه/در پایان اگر براتون سواله این توابع رو از کجا میشه پیدا کرد، باید بگم که با رفتن به این سایت میتونید به تمام اطلاعات کافی در مورد کتابخونه های ویندوز دسترسی داشته باشید.</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Tue, 21 Jul 2020 17:57:33 +0430</pubDate>
            </item>
                    <item>
                <title>Extract کردن هر نوع فایل فشرده با unrar و سی شارپ</title>
                <link>https://virgool.io/coderlife/extract-%DA%A9%D8%B1%D8%AF%D9%86-%D9%87%D8%B1-%D9%86%D9%88%D8%B9-%D9%81%D8%A7%DB%8C%D9%84-%D9%81%D8%B4%D8%B1%D8%AF%D9%87-%D8%A8%D8%A7-unrar-%D9%88-%D8%B3%DB%8C-%D8%B4%D8%A7%D8%B1%D9%BE-jc15p51gmanp</link>
                <description>ممکنه تا حالا براتون پیش اومده باشه که بخاین یه فایل فشرده مثل Rar رو با برنامه خودتون Extract کنید و دنبال کدها و کتابخونه های مختلفی رفته باشید، همینطور که میدونید Rar یه نوع الگوریتم فشرده سازی اختصاصی هستش که توسط نرم افزار winrar استفاده میشه، بعضی از کتابخونه ها از فرمت rar پشتیبانی میکنن و امکان Extract کردن رو به کاربر میدن، ولی هیچکدوم از نسخه Rar 5 پشتیبانی نمیکنن (تا جایی که من اطلاع دارم) rar 5 الگوریتم جدید rar هستش که درصد فشرده سازیش بیشتره!امروز داشتم یه اپدیتر خودکار برای خودم مینوشتم که بیاد فایل اپدیت رو دانلود و نصب کنه از اونجایی که فایل اپدیت با الگوریتم rar 5 فشرده سازی شده بود امکان اکسترکت کردن با کتابخونه ها نبود و علاقه ای هم به نصب کتابخونه های حجیم نداشتم، حالا راه حل من برای extract کردن چی بود؟شرکت rarlab که نرم افزار winrar رو توسعه داده و همه ما با کرک ازش استفاده میکنیم، یه نسخه خط فرمان به اسم unrar رو هم توسعه داده که کاملا رایگانه و مختص برنامه نویس ها و افرادیه که میخان از خط فرمان استفاده بکنن، من به کمک این برنامه و ارسال دستورات خط فرمان از طریق سی شارپ تونستم براحتی فایل rar 5 رو extract کنم.کدش رو اینجا میزارم تا اگر کسی علاقمند بود ازش استفاده کنه: (قبلش unrar رو از اینجا دانلود و اکسترکت کنید)System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = &amp;quotUnRAR.exe&amp;quot
p.StartInfo.Arguments = string.Format(@&amp;quotx -s &amp;quot&amp;quot{0}&amp;quot&amp;quot *.*&amp;quot, &amp;quotfile.rar&amp;quot);
p.Start();
p.WaitForExit();</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Wed, 10 Jun 2020 23:43:05 +0430</pubDate>
            </item>
                    <item>
                <title>آمار استفاده کنندگان از پکیج منیجر ویندوز</title>
                <link>https://virgool.io/@mahdi72/%D8%A2%D9%85%D8%A7%D8%B1-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%D9%86%D8%AF%DA%AF%D8%A7%D9%86-%D8%A7%D8%B2-%D9%BE%DA%A9%DB%8C%D8%AC-%D9%85%D9%86%DB%8C%D8%AC%D8%B1-%D9%88%DB%8C%D9%86%D8%AF%D9%88%D8%B2-qsy2sxvdliid</link>
                <description>حدود دو هفته پیش ماکروسافت پکیج منیجر جدیدی (Winget) برای ویندوز 10 معرفی کرد از اونجایی که خصلت پکیج منیجر به خط فرمان بودن اون هست (بدون رابط کاربری) خیلی از کاربر ها شاید مشکل داشته باشن و نیاز به یه رابط کاربری داشته باشن. من تصمیم گرفتم که یه رابط کاربری برای این پکیج منیجر ایجاد کنم. این هم شد نتیجش:بعد تصمیم گرفتم برای اونایی که علاقه مند به ایجاد پکیج دلخواهشون هستن یه ویژگی قرار بدم تا بتونن با رابط کاربری پکیج موردنظرشون (فایل yaml) رو تولید کنن اینم شد نتیجش:حالا بعد از گذشت 2 هفته نتایج جالبی بدست اومده، اول اینکه تو سایت های چینی و آلمانی برنامه رو به کاربرا معرفی کردن:https://www.chip.de/downloads/HandyWinget-GUI-fuer-Windows-Package-Manager_182729768.htmlhttp://jdev.tw/blog/6290/handywinget-gui-and-sharpapphttps://winbuzzer.com/2020/05/29/how-to-use-windows-package-manager-winget-with-powershell-and-gui-xcxwbt/دوم اینکه خود برنامه هم آمار بسیار جالبی رو بهمون ارائه میده:هفته ای 54 کاربر فعالماهانه 263 کاربر فعالو روزی 7 کاربر فعالنمودار ها هم پیشرفت برنامه رو به خوبی نشون میدن نکته جالب اینکه 187 نفر از کاربران برنامه از کشور آلمان هستن و سایر کاربران از کشورهای چین، هلند، فرانسه و ایران هستن که تعداد افراد هر کشور رو میتونید در لیست مشاهده کنید. همینطور کاربران فعال در هر نسخه بصورت نمودار نمایش داده شده که اکثر کاربرا از نسخه 1.1.0.0 استفاده میکنن و اروم اروم دارن به نسخه 1.2.0.0 مهاجرت میکنن</description>
                <category>آمنوتجیکارا</category>
                <author>آمنوتجیکارا</author>
                <pubDate>Sun, 07 Jun 2020 20:52:04 +0430</pubDate>
            </item>
            </channel>
</rss>