گفتگو هایی در باب سی شارپ

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نمیدونم. لابد یک چیزی از بقایاش در csproj یا sln پروژه تون باقی مونده.


یک مشکل اساسی که با استدلال هاتون دارم اینه که به نظرتون یکی دو روز وقت صرف کردن برای ساختن یک کمپوننت وقت زیاده.
شما از WPF که استفاده کنید دردسر تون چند برابر میشه، چون اولا عادت به طراحی ویژوال فرم های ویندوز دارید، در حالی که بیشتر طراحی در WPF رو باید در قالب XAML تایپ کنید، نه اینکه بصورت ویژوال با Drag کردن بسازید. ثانیا چون کلا WPF براتون محیط جدید و ناآشنایی است زمان میبره تا بهش عادت کنید. اون کسی که بهتون WPF رو پیشنهاد کرده نظر بدی نداده ولی مطلع نیست که شما دو روز براتون زمان زیاده و حوصله ماه ها وقت صرف کردن برای این موارد ناشناخته رو ندارید.


بعضی کار هاتون خیلی عجیبه. محیطی که باهاش آشنا هستید و روال اش رو میدونید ول میکنید چون میگید دو روز طول میکشه که تا انجامش بدم، بعد سر کاری که نمیدونید روالش چیه راحت روز ها وقت صرف می کنید.
شخصی سازی WPF ها وقتی براتون راحت میشه که برای یادگیری کار با XAML وقت صرف کنید و بهش عادت کنید وگرنه به قول شما آسون نیست.

سلامی مجدد
خیلی ممنون
منظورم این نبود که دو روز زمان صرف کردن ، زیاده . منظورم این بود که هر کنترل را اگه بخوام شخصی سازی کنم (مثل کمبوباکس و لیست باکس و چک باکس ، رادیوباتون و بسیاری دیگه) ، هر کدوم شون حداقل یکی دو روز طول میکشه که در مجموع حدود دو هفته تا یک ماه وقت میبره که در اینصورت ، زیاده. وگرنه با یکی دو روز مشکلی ندارم و اگه یکی دو کنترل میبود.
منظورم این بود که کنترل های wpf را توی winform (توسط کنترل ElementHost در winform) استفاده کنم . در این صورت که دیگه لازم نیست با xaml کار کنم. مستقیما با کد سی شارپ کار میکنم.
الان اگه میشه ، جواب این پست آخری (شماره ی 1239) را میدین؟
خیلی ممنون
 

the_king

مدیرکل انجمن
نمیدونم. لابد یک چیزی از بقایاش در csproj یا sln پروژه تون باقی مونده.


یک مشکل اساسی که با استدلال هاتون دارم اینه که به نظرتون یکی دو روز وقت صرف کردن برای ساختن یک کمپوننت وقت زیاده.
شما از WPF که استفاده کنید دردسر تون چند برابر میشه، چون اولا عادت به طراحی ویژوال فرم های ویندوز دارید، در حالی که بیشتر طراحی در WPF رو باید در قالب XAML تایپ کنید، نه اینکه بصورت ویژوال با Drag کردن بسازید. ثانیا چون کلا WPF براتون محیط جدید و ناآشنایی است زمان میبره تا بهش عادت کنید. اون کسی که بهتون WPF رو پیشنهاد کرده نظر بدی نداده ولی مطلع نیست که شما دو روز براتون زمان زیاده و حوصله ماه ها وقت صرف کردن برای این موارد ناشناخته رو ندارید.


بعضی کار هاتون خیلی عجیبه. محیطی که باهاش آشنا هستید و روال اش رو میدونید ول میکنید چون میگید دو روز طول میکشه که تا انجامش بدم، بعد سر کاری که نمیدونید روالش چیه راحت روز ها وقت صرف می کنید.
شخصی سازی WPF ها وقتی براتون راحت میشه که برای یادگیری کار با XAML وقت صرف کنید و بهش عادت کنید وگرنه به قول شما آسون نیست.
سلامی مجدد
خیلی ممنون
منظورم این نبود که دو روز زمان صرف کردن ، زیاده . منظورم این بود که هر کنترل را اگه بخوام شخصی سازی کنم (مثل کمبوباکس و لیست باکس و چک باکس ، رادیوباتون و بسیاری دیگه) ، هر کدوم شون حداقل یکی دو روز طول میکشه که در مجموع حدود دو هفته تا یک ماه وقت میبره که در اینصورت ، زیاده. وگرنه با یکی دو روز مشکلی ندارم و اگه یکی دو کنترل میبود.
منظورم این بود که کنترل های wpf را توی winform (توسط کنترل ElementHost در winform) استفاده کنم . در این صورت که دیگه لازم نیست با xaml کار کنم. مستقیما با کد سی شارپ کار میکنم.
الان اگه میشه ، جواب این پست آخری (شماره ی 1239) را میدین؟
خیلی ممنون
شما برای اینکه کنترلی رو که در محیط WPF طراحی شده در محیط Windows Form نمایش بدید از ElementHost استفاده می کنید، اما این نه باعث میشه که موتور گرافیکی WPF که DirectX ئه تغییر کنه و نه باعث تغییری در ساختار WPF و کنترل ها میشه. کنترل WPF و رسم اش همچنان با XAML و سیستم خودشه. شما همچنان برای کنترل های WPF به XAML وابسته هستید.
مگه جایی خوندید که ElementHost برنامه نویس رو از XAML بی نیاز میکنه؟
شما در WPF برای هر نوع کنترلی مثل CheckBox یک ControlTemplate پیشفرض دارید که اجزاء نام دار خاصی نداره که رویشان مانور بدید.
برای اینکه بتوانید اینجور اجزاء رو تغییر بدید باید برای CheckBox تون ControlTemplate ای تعریف کنید که فرضا BulletDecorator داره و Bullet ای که داخلش اون BulletDecorator هست اسمی داره تا بعدا بتوانید با اون اسم تغییری در ظاهرش بدید. یک چیزی مثل این :
CheckBox Styles and Templates
بیشتر زمان طراحی در WPF در حالت تایپ کردن متن میگذره، نه تغییر مشخصه های Property های ویژوال. WPF یک محیط ایده آل برای طراحی چیزی است که می خواهید، اما شبیه طراحی CSS برای HTML در یک محیط متنی، نه در یک محیط ویژوال مثل فتوشاپ.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
شما برای اینکه کنترلی رو که در محیط WPF طراحی شده در محیط Windows Form نمایش بدید از ElementHost استفاده می کنید، اما این نه باعث میشه که موتور گرافیکی WPF که DirectX ئه تغییر کنه و نه باعث تغییری در ساختار WPF و کنترل ها میشه. کنترل WPF و رسم اش همچنان با XAML و سیستم خودشه. شما همچنان برای کنترل های WPF به XAML وابسته هستید.
مگه جایی خوندید که ElementHost برنامه نویس رو از XAML بی نیاز میکنه؟
شما در WPF برای هر نوع کنترلی مثل CheckBox یک ControlTemplate پیشفرض دارید که اجزاء نام دار خاصی نداره که رویشان مانور بدید.
برای اینکه بتوانید اینجور اجزاء رو تغییر بدید باید برای CheckBox تون ControlTemplate ای تعریف کنید که فرضا BulletDecorator داره و Bullet ای که داخلش اون BulletDecorator هست اسمی داره تا بعدا بتوانید با اون اسم تغییری در ظاهرش بدید. یک چیزی مثل این :
CheckBox Styles and Templates
بیشتر زمان طراحی در WPF در حالت تایپ کردن متن میگذره، نه تغییر مشخصه های Property های ویژوال. WPF یک محیط ایده آل برای طراحی چیزی است که می خواهید، اما شبیه طراحی CSS برای HTML در یک محیط متنی، نه در یک محیط ویژوال مثل فتوشاپ.

خیلی ممنون
نمیدونم چرا متوجه ی صحبت هاتون نمیشم .
الان من در کد زیر ، که در winform نوشتم و یک کنترل چک باکس از wpf را نمایش دادم (توسط ElementHost) ، اصلا کد xaml ای ننوشتم . همش کد سی شارپ هست . نمیدونم چرا میگید نیازمند کدنویسی xaml هستم :


کد:
using WpfControls = System.Windows.Controls;
using WpfMedias = System.Windows.Media;
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            WpfControls.CheckBox wpfCheckBox = new WpfControls.CheckBox();
            wpfCheckBox.Margin = new System.Windows.Thickness(0, 0, 0, 0);
            wpfCheckBox.Width = 100;
            wpfCheckBox.Height = 20;
            wpfCheckBox.Content = "salam";
            wpfCheckBox.Background = new WpfMedias.SolidColorBrush(WpfMedias.Color.FromArgb(255, 70, 70, 70));

            System.Windows.Forms.Integration.ElementHost elementHost = new System.Windows.Forms.Integration.ElementHost();
            elementHost.Bounds = new Rectangle(100, 100, ((int)wpfCheckBox.Width), ((int)wpfCheckBox.Height));
            elementHost.Child = wpfCheckBox;

            this.Controls.Add(elementHost);
        }
    }

فقط نمیدونم چرا متن salam در چک باکس در کد بالا ، یه کم پایین تر از مربعِ چک باکس نوشته بصورت پیش فرض . توی خودِ wpf این مشکل نبود.
--------
بله منم به همین ControlTemplate رسیدم ولی همش ازش مثال که میزنن ، بصورت کد xaml هست . بنابراین من متوجه نشدم . میشه هر وقت وقت کردین ، یه مثال کوچیکی (مثلا همین تغییر پروپرتی Background در کنترل checkbox ، زمان mouse enter روی این کنترل) توسط همین ControlTemplate بزنین تا بهتر متوجه بشم؟
منظورم از پروپرتی Background در کنترل checkbox اینه که رنگ داخل مربعِ چک باکس ، تغییر کنه (مثلا قرمز بشه)
خیلی ممنون
 

the_king

مدیرکل انجمن
خیلی ممنون
نمیدونم چرا متوجه ی صحبت هاتون نمیشم .
الان من در کد زیر ، که در winform نوشتم و یک کنترل چک باکس از wpf را نمایش دادم (توسط ElementHost) ، اصلا کد xaml ای ننوشتم . همش کد سی شارپ هست . نمیدونم چرا میگید نیازمند کدنویسی xaml هستم :


کد:
using WpfControls = System.Windows.Controls;
using WpfMedias = System.Windows.Media;
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            WpfControls.CheckBox wpfCheckBox = new WpfControls.CheckBox();
            wpfCheckBox.Margin = new System.Windows.Thickness(0, 0, 0, 0);
            wpfCheckBox.Width = 100;
            wpfCheckBox.Height = 20;
            wpfCheckBox.Content = "salam";
            wpfCheckBox.Background = new WpfMedias.SolidColorBrush(WpfMedias.Color.FromArgb(255, 70, 70, 70));

            System.Windows.Forms.Integration.ElementHost elementHost = new System.Windows.Forms.Integration.ElementHost();
            elementHost.Bounds = new Rectangle(100, 100, ((int)wpfCheckBox.Width), ((int)wpfCheckBox.Height));
            elementHost.Child = wpfCheckBox;

            this.Controls.Add(elementHost);
        }
    }
شما در این کدتون هیچ کاری با Style اون Checkbox تون ندارید. مشخصه های کنترل های WPF مثل کنترل های ویندوز نیست که هر چی داخل تم اش داره یک مشخصه برای تغییر دادنش قرار بده.
دلیلش هم خیلی واضح ئه، شما در کنترل های ویندوز یک ظاهر مشخص و استاندارد دارید و مولفه ها و کارکرد شون ثابت و از قبل تعریف شده است، اما در WPF درست مثل منوی های داخل وبسایت ها که هر سایتی ظاهر و سبک منوی خودش رو داره همه چی متغیر ئه. هیچ قالب ثابتی در طراحی نیست که مشخصه ها بر اساس اونها تعریف بشن.
با کنترل های WPF دارید طوری کار می کنید که انگار کنترل روی فرم ئه. شما چه اون CheckBox رو توی خود پنجره WPF استفاده کنید و چه داخل فرم ویندوز تون، مشخصه Background اش همینه که می بینید.
Background چه ربطی به رنگ زمینه مربع داخل چک باکس داره.

بله منم به همین ControlTemplate رسیدم ولی همش ازش مثال که میزنن ، بصورت کد xaml هست . بنابراین من متوجه نشدم . میشه هر وقت وقت کردین ، یه مثال کوچیکی (مثلا همین تغییر پروپرتی Background در کنترل checkbox ، زمان mouse enter روی این کنترل) توسط همین ControlTemplate بزنین تا بهتر متوجه بشم؟
منظورم از پروپرتی Background در کنترل checkbox اینه که رنگ داخل مربعِ چک باکس ، تغییر کنه (مثلا قرمز بشه)
خیلی ممنون
از کد Lua که نمیتونستن مثال بزنن، طبعا برای WPF باید کد XAML مینوشتن، جایگزینی نداره. از یاد گرفتن فرار نکنید، اگر XAML رو متوجه نمیشید معنی اش این نیست که باید دورش بزنید، یا باید اصلا سراغ WPF نرید یا اگر سراغش می روید باید درست یاد بگیریدش.
برای طراحی نرم افزاری که واسط کاربری داره چند تا راه که بیشتر نیست، یا باید کاملا به طراحی اینترفیس در یک پلتفرم، حالا Windows Form یا WPF و ... مسلط بشید و خودتون هر چه نیاز دارید داخلش بسازید، یا باید یک مجموعه کامل و بی نقص آماده داشته باشید که مثل کف دست جزئیاتش رو بدونید، یا باید یک همکار داشته باشید که اینجور موارد رو به اون بسپارید. یکمی از این دانستن و یکمی از اون دانستن دردی رو دوا نمی کنه.
می توانید سالها برای دور زدن چیزهایی که نمی دانید و بهتر بود یاد میگرفتید تلاش کنید و نهایتا بخاطر همون عمق کم لنگ بمونید. یا بجاش چند ماه خودتون رو درگیر یادگیری عمیق یک راه حل کنید و برای هر پروژه ای یک راه مشخصی داشته باشید که در اون تبحر دارید. مهم نیست چه روشی رو انتخاب می کنید، مهم اینه که عمیق و کامل یاد بگیرید. هی از این شاخه به اون شاخه پریدن فایده ای نداره.

اینم یک مثال ساده : checkboxsample.zip

من خودم شخصا علاقه ای به WPF ندارم، نه طراحی اینترفیس اش رو می پسندم، نه کندی محیط ویژوال اش رو و نه سبک طراحی اینترفیس اش رو.
اونقدر هم که وقت صرف Windows Form کردم قطعا صرف WPF نکردم. واقعا هم برای طراحی اینترفیس نیازی به WPF پیدا نمی کنم. اما با این وجود تا یک کد XAML ببینم ازش رد نمیشم.
 

پیوست ها

  • CheckBoxSample.zip
    595.5 کیلوبایت · بازدیدها: 3

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
شما در این کدتون هیچ کاری با Style اون Checkbox تون ندارید. مشخصه های کنترل های WPF مثل کنترل های ویندوز نیست که هر چی داخل تم اش داره یک مشخصه برای تغییر دادنش قرار بده.
دلیلش هم خیلی واضح ئه، شما در کنترل های ویندوز یک ظاهر مشخص و استاندارد دارید و مولفه ها و کارکرد شون ثابت و از قبل تعریف شده است، اما در WPF درست مثل منوی های داخل وبسایت ها که هر سایتی ظاهر و سبک منوی خودش رو داره همه چی متغیر ئه. هیچ قالب ثابتی در طراحی نیست که مشخصه ها بر اساس اونها تعریف بشن.
با کنترل های WPF دارید طوری کار می کنید که انگار کنترل روی فرم ئه. شما چه اون CheckBox رو توی خود پنجره WPF استفاده کنید و چه داخل فرم ویندوز تون، مشخصه Background اش همینه که می بینید.
Background چه ربطی به رنگ زمینه مربع داخل چک باکس داره.


از کد Lua که نمیتونستن مثال بزنن، طبعا برای WPF باید کد XAML مینوشتن، جایگزینی نداره. از یاد گرفتن فرار نکنید، اگر XAML رو متوجه نمیشید معنی اش این نیست که باید دورش بزنید، یا باید اصلا سراغ WPF نرید یا اگر سراغش می روید باید درست یاد بگیریدش.
برای طراحی نرم افزاری که واسط کاربری داره چند تا راه که بیشتر نیست، یا باید کاملا به طراحی اینترفیس در یک پلتفرم، حالا Windows Form یا WPF و ... مسلط بشید و خودتون هر چه نیاز دارید داخلش بسازید، یا باید یک مجموعه کامل و بی نقص آماده داشته باشید که مثل کف دست جزئیاتش رو بدونید، یا باید یک همکار داشته باشید که اینجور موارد رو به اون بسپارید. یکمی از این دانستن و یکمی از اون دانستن دردی رو دوا نمی کنه.
می توانید سالها برای دور زدن چیزهایی که نمی دانید و بهتر بود یاد میگرفتید تلاش کنید و نهایتا بخاطر همون عمق کم لنگ بمونید. یا بجاش چند ماه خودتون رو درگیر یادگیری عمیق یک راه حل کنید و برای هر پروژه ای یک راه مشخصی داشته باشید که در اون تبحر دارید. مهم نیست چه روشی رو انتخاب می کنید، مهم اینه که عمیق و کامل یاد بگیرید. هی از این شاخه به اون شاخه پریدن فایده ای نداره.

اینم یک مثال ساده : checkboxsample.zip

من خودم شخصا علاقه ای به WPF ندارم، نه طراحی اینترفیس اش رو می پسندم، نه کندی محیط ویژوال اش رو و نه سبک طراحی اینترفیس اش رو.
اونقدر هم که وقت صرف Windows Form کردم قطعا صرف WPF نکردم. واقعا هم برای طراحی اینترفیس نیازی به WPF پیدا نمی کنم. اما با این وجود تا یک کد XAML ببینم ازش رد نمیشم.

خیلی ممنونم استاد
من منظورم مثال و پیاده سازیِ template توسط کد سی شارپ بود . مثال xaml اش که توی اینترنت هم موجود بود . ولی من xaml بلد نیستم . البته نه اینکه هیچیِ هیچ چی متوجه نشم . شاید 10 درصد کدهای xaml رو متوجه بشم که کفایت نمیکنه برای درک کلی.
چرا template فقط با کد xaml کار میکنه؟
این به این معناست که توی winform اگه بخوام template ای به کنترلِ wpf ای بدم ، نمیشه؟ چون winform که xaml را پشتیبانی نمیکنه . بکنه هم من بلد نیستم.
کلا راه حلی بجز کدِ xaml دادن در wpf (قطعا از راه حلِ template نمیتونم استفاده کنم چون xaml بلد نیستم) ، فقط همون ارث بری و باز نویسی متد OnPaint و کلا این نوع روش های مرسوم ای که در winform استفاده کردیم ، باقی میمونه؟

بعد اینکه به زور یه موضوعی پیدا کردم (انگار تغییر template در کنترل wpf هه) که با کدنویسی سی شارپ این کار را کرد :


Change the background color of a WPF editable ComboBox programmatically

اما من کدش را نوشتم ، متغییر textbox ام null شد و ارور داد .
چرا؟


خیلی ممنون
 

the_king

مدیرکل انجمن
خیلی ممنونم استاد
من منظورم مثال و پیاده سازیِ template توسط کد سی شارپ بود . مثال xaml اش که توی اینترنت هم موجود بود . ولی من xaml بلد نیستم . البته نه اینکه هیچیِ هیچ چی متوجه نشم . شاید 10 درصد کدهای xaml رو متوجه بشم که کفایت نمیکنه برای درک کلی.
چرا template فقط با کد xaml کار میکنه؟
این چیزی که میگید معنی نمیده، Template یک قالب برای تعریف ویژگی های ظاهری ئه، کد برنامه نویسی نیست که در #C نوشته بشه. همانطور که در صفحه HTML قالب ظاهری رو با CSS مشخص می کنند، نه Javascript. اون XAML زبان توصیف اجزاء WPF ئه. همانطور که در صفحه وب توسط HTML توصیف میشه نه چیز دیگری، با php و C# ASP.NET و ... هم که برای وب کد نویسی کنید باید کد های HTML خروجی بدید.

این به این معناست که توی winform اگه بخوام template ای به کنترلِ wpf ای بدم ، نمیشه؟ چون winform که xaml را پشتیبانی نمیکنه . بکنه هم من بلد نیستم.
کلا راه حلی بجز کدِ xaml دادن در wpf (قطعا از راه حلِ template نمیتونم استفاده کنم چون xaml بلد نیستم) ، فقط همون ارث بری و باز نویسی متد OnPaint و کلا این نوع روش های مرسوم ای که در winform استفاده کردیم ، باقی میمونه؟
کاری که میخواهید بکنید کلا کجدار و مریض ئه، CheckBox با تم پیشفرض WPF برای برنامه Win Forms شما مزیتی ایجاد نمی کنه. وقتی اینکار شما منطقی بود که شما یک ویژگی یا ظاهر خاصی در WPF ایجاد کرده بود که امکان پیاده سازیش در Win Forms میسر نبود و ناچار بودید به این طریق ظاهر رو داخل Win Forms نمایش بدید. الان که شما همچین ظاهری رو در WPF هم کد نویسی نکرده بودید چه چیز CheckBox ئه شیفته تون کرده بود که انتقالش بدید به Win Forms. اون کنترل CheckBox خود Windows Forms که در حالت عادی در همین حد خروجی میداد.
کلا برای استفاده از WPF باید XAML بلد باشید، همونقدر که برای کامپیوتر باید استفاده از سیستم عامل رو بلد باشید.

بعد اینکه به زور یه موضوعی پیدا کردم (انگار تغییر template در کنترل wpf هه) که با کدنویسی سی شارپ این کار را کرد :
Change the background color of a WPF editable ComboBox programmatically

اما من کدش را نوشتم ، متغییر textbox ام null شد و ارور داد .
چرا؟
خیلی ممنون
منظور کدش رو درست متوجه نشدید، این کد نمی خواد یک Template جدید ایجاد کنه یا تغییرش بده، خودتون هم که کدش رو می بینید. ComboBox ئه از یکسری بخش های مختلف تشکیل شده که یک بخش اش
PART_EditableTextBox ئه که TextBox ئه و رنگ زمینه اون TextBox رو مشخص میکنه. شما یک TextBox عادی هم داشته باشید می توانید رنگ زمینه اش رو مشخص کنید.
textBox.Background تنظیم یک مشخصه عادی کنترل ئه، چیزی مربوط به اجزاء داخلی ترسیم شده در Template نیست. سعی نکنید اولین کسی باشید که بدون یادگرفتن خلبانی پرواز میکنه، نتیجه خوبی نخواهد داشت.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
این چیزی که میگید معنی نمیده، Template یک قالب برای تعریف ویژگی های ظاهری ئه، کد برنامه نویسی نیست که در #C نوشته بشه. همانطور که در صفحه HTML قالب ظاهری رو با CSS مشخص می کنند، نه Javascript. اون XAML زبان توصیف اجزاء WPF ئه. همانطور که در صفحه وب توسط HTML توصیف میشه نه چیز دیگری، با php و C# ASP.NET و ... هم که برای وب کد نویسی کنید باید کد های HTML خروجی بدید.


کاری که میخواهید بکنید کلا کجدار و مریض ئه، CheckBox با تم پیشفرض WPF برای برنامه Win Forms شما مزیتی ایجاد نمی کنه. وقتی اینکار شما منطقی بود که شما یک ویژگی یا ظاهر خاصی در WPF ایجاد کرده بود که امکان پیاده سازیش در Win Forms میسر نبود و ناچار بودید به این طریق ظاهر رو داخل Win Forms نمایش بدید. الان که شما همچین ظاهری رو در WPF هم کد نویسی نکرده بودید چه چیز CheckBox ئه شیفته تون کرده بود که انتقالش بدید به Win Forms. اون کنترل CheckBox خود Windows Forms که در حالت عادی در همین حد خروجی میداد.
کلا برای استفاده از WPF باید XAML بلد باشید، همونقدر که برای کامپیوتر باید استفاده از سیستم عامل رو بلد باشید.


منظور کدش رو درست متوجه نشدید، این کد نمی خواد یک Template جدید ایجاد کنه یا تغییرش بده، خودتون هم که کدش رو می بینید. ComboBox ئه از یکسری بخش های مختلف تشکیل شده که یک بخش اش
PART_EditableTextBox ئه که TextBox ئه و رنگ زمینه اون TextBox رو مشخص میکنه. شما یک TextBox عادی هم داشته باشید می توانید رنگ زمینه اش رو مشخص کنید.
textBox.Background تنظیم یک مشخصه عادی کنترل ئه، چیزی مربوط به اجزاء داخلی ترسیم شده در Template نیست. سعی نکنید اولین کسی باشید که بدون یادگرفتن خلبانی پرواز میکنه، نتیجه خوبی نخواهد داشت.

خیلی ممنون
پس تغییر ظاهر در wpf به دو روش هست . یکی از طریق template ها که لازمه حتما xaml بلد باشیم . یکی هم از طریق همین روند عادی در winform (یعنی ارث بری و override کردن متد OnPaint و رسم دلخواه خودمون) . پس بنابراین کنترل های wpf هایی که بخوام تغییر شکل شون بدم را بی خیال شم چون در روش اول ، xaml بلد نیستم و روش دوم هم که در winform قابل پیاده سازی هست.
با این حال ، فکر کنم به استفاده ی از کمپوننت ها (مخصوصا کمپوننت تلریک و تم هاش) بسنده کنم . هر چند مشکلات خاص خودش را داره.

میگم استاد علی ، یه سئوال بپرسم ، عصبانی نشین (چون احتمالا قبلا پرسیدم . دقیقا نمیدونم) . میگم در کد زیر :


کد:
        [DllImport("User32.dll", EntryPoint = "SetWindowLongA")]
        private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("User32.dll", EntryPoint = "GetWindowLongA")]
        private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("User32.dll", EntryPoint = "SetLayeredWindowAttributes")]
        private static extern bool SetLayeredWindowAttributes(IntPtr hWnd, uint crKey, byte bAlpha, uint dwFlags);

        private int GWL_EXSTYLE = -20;
        private int WS_EX_LAYERED = 0x00080000;
        private uint LWA_ALPHA = 0x00000002;
        private uint LWA_COLORKEY = 0x00000001;


        private void Button1_Click(object sender, EventArgs e)
        {
            Page4.SetWindowLong(this.mainForm.Handle, this.GWL_EXSTYLE, Page4.GetWindowLong(this.button1.Handle, this.GWL_EXSTYLE) | this.WS_EX_LAYERED);
            Page4.SetLayeredWindowAttributes(this.mainForm.Handle, 0x000000ff, 127, this.LWA_COLORKEY);
        }

اولا شی this.mainForm ، یه شی فرم top level هستش و دوما هر جا از فرم که رنگ قرمز خالص (یعنی r=255 و بقیه ی gb اش 0) باشه را کاملا حذف و شفاف میکنه .
اما همین کد را واسه ی هندل یه کنترل (مثلا دکمه یا هر کنترل دیگه ای که کلا top level نیست) اجرا میکنیم ، عمل نمیکنه .
چرا واسه ی اون کنترل های top level فقط عمل میکنه؟
خیلی ممنون
 

the_king

مدیرکل انجمن
خیلی ممنون
پس تغییر ظاهر در wpf به دو روش هست . یکی از طریق template ها که لازمه حتما xaml بلد باشیم . یکی هم از طریق همین روند عادی در winform (یعنی ارث بری و override کردن متد OnPaint و رسم دلخواه خودمون) . پس بنابراین کنترل های wpf هایی که بخوام تغییر شکل شون بدم را بی خیال شم چون در روش اول ، xaml بلد نیستم و روش دوم هم که در winform قابل پیاده سازی هست.
با این حال ، فکر کنم به استفاده ی از کمپوننت ها (مخصوصا کمپوننت تلریک و تم هاش) بسنده کنم . هر چند مشکلات خاص خودش را داره.

روش دوم نیست/ چیزی که شما روی پنجره فرم تون رسم کنید که تغییر ظاهر WPF محسوب نمیشه، اون موتور رسم اش کاملا مجزا است، شما صرفا روی خروجی اش که در پنجره میبینید رسم جدیدی می کنید. همچین کاری رو به حساب تغییر ظاهر کنترل WPF نذارید.

میگم استاد علی ، یه سئوال بپرسم ، عصبانی نشین (چون احتمالا قبلا پرسیدم . دقیقا نمیدونم) . میگم در کد زیر :
کد:
        [DllImport("User32.dll", EntryPoint = "SetWindowLongA")]
        private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("User32.dll", EntryPoint = "GetWindowLongA")]
        private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("User32.dll", EntryPoint = "SetLayeredWindowAttributes")]
        private static extern bool SetLayeredWindowAttributes(IntPtr hWnd, uint crKey, byte bAlpha, uint dwFlags);

        private int GWL_EXSTYLE = -20;
        private int WS_EX_LAYERED = 0x00080000;
        private uint LWA_ALPHA = 0x00000002;
        private uint LWA_COLORKEY = 0x00000001;


        private void Button1_Click(object sender, EventArgs e)
        {
            Page4.SetWindowLong(this.mainForm.Handle, this.GWL_EXSTYLE, Page4.GetWindowLong(this.button1.Handle, this.GWL_EXSTYLE) | this.WS_EX_LAYERED);
            Page4.SetLayeredWindowAttributes(this.mainForm.Handle, 0x000000ff, 127, this.LWA_COLORKEY);
        }

اولا شی this.mainForm ، یه شی فرم top level هستش و دوما هر جا از فرم که رنگ قرمز خالص (یعنی r=255 و بقیه ی gb اش 0) باشه را کاملا حذف و شفاف میکنه .
اما همین کد را واسه ی هندل یه کنترل (مثلا دکمه یا هر کنترل دیگه ای که کلا top level نیست) اجرا میکنیم ، عمل نمیکنه .
چرا واسه ی اون کنترل های top level فقط عمل میکنه؟
خیلی ممنون
بله قبلا پرسیدید. اولا صرفا از ویندوز 8 به بعد می توانید برای پنجره ای که والد داره WS_EX_LAYERED رو تعریف کنید، در ویندوز های قدیمی تر پنجره فرزندی که WS_EX_LAYERED باشه پشتیبانی نمیشه.
ثانیا باید در Manifest برنامه تون مشخص کنید که این قابلیت ویژوال رو داره. یعنی یک Application Manifest File به پروژه تون اضافه کنید و در بین supportedOS ها موارد Windows 8 به بعد رو از حالت comment شده در بیارید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
روش دوم نیست/ چیزی که شما روی پنجره فرم تون رسم کنید که تغییر ظاهر WPF محسوب نمیشه، اون موتور رسم اش کاملا مجزا است، شما صرفا روی خروجی اش که در پنجره میبینید رسم جدیدی می کنید. همچین کاری رو به حساب تغییر ظاهر کنترل WPF نذارید.

خیلی ممنون . شبیه اینه که شی گرافیک جدیدی ساخته باشیم و روی گرافیک قبلی رسم کنیم؟ یعنی گرافیک قبلی ، رسم اش را انجام میده اما ما گرافیک دیگه ای روی گرافیک قبلی رسم میکنیم که باعث میشه فکر کنیم رسم کلی را تغییر دادیم؟
خوب بالاخره تغییر رسم در wpf ، به همین دو روش انجام میشه دیگه . درسته؟
درباره ی جواب قسمت دوم هم ممنون ، کاری که گفتید را انجام دادم و درست شد.

سئوال دیگه اینکه تفاوت دقیق بین CompositingQuality و SmoothingMode و TextRenderingHint در کلاس Graphic چیه؟ (البته میدونم درباره ی بعضی از این پروپرتی ها قبلا صحبت کردیم اما الان تفاوت بین شون رو میخوام بدونم)
اینایی که در زیر میگم ، درسته؟ :
CompositingQuality ، کیفیت ایمیج و بیت مپ ای که میخواد رسم بشه در اون گرافیک را مشخص میکنه (کاری به کیفیت متن رسم شده نداره)
TextRenderingHint ، کیفیت متن ای که میخواد رسم بشه در گرافیک را مشخص میکنه (کاری به کیفیت بیت مپ رسم شده نداره)
SmoothingMode ، کیفیت هر دو را کنترل میکنه
 
آخرین ویرایش:

the_king

مدیرکل انجمن
خیلی ممنون . شبیه اینه که شی گرافیک جدیدی ساخته باشیم و روی گرافیک قبلی رسم کنیم؟ یعنی گرافیک قبلی ، رسم اش را انجام میده اما ما گرافیک دیگه ای روی گرافیک قبلی رسم میکنیم که باعث میشه فکر کنیم رسم کلی را تغییر دادیم؟
خوب بالاخره تغییر رسم در wpf ، به همین دو روش انجام میشه دیگه . درسته؟

باز که میگید روش دوم. این روشی نیست که دومی باشه.
شما توی یک لیوان آب میوه می ریزید و بعد خالیش کنید و بعد داخلش نوشابه گازداری میریزید، دیگه چیزی از آب میوه هه تو لیوان نمونده که بگید با این روش مزه آب میوه رو به مزه نوشابه تبدیل می کنیم.

سئوال دیگه اینکه تفاوت دقیق بین CompositingQuality و SmoothingMode و TextRenderingHint در کلاس Graphic چیه؟ (البته میدونم درباره ی بعضی از این پروپرتی ها قبلا صحبت کردیم اما الان تفاوت بین شون رو میخوام بدونم)
اینایی که در زیر میگم ، درسته؟ :
CompositingQuality ، کیفیت ایمیج و بیت مپ ای که میخواد رسم بشه در اون گرافیک را مشخص میکنه (کاری به کیفیت متن رسم شده نداره)
TextRenderingHint ، کیفیت متن ای که میخواد رسم بشه در گرافیک را مشخص میکنه (کاری به کیفیت بیت مپ رسم شده نداره)
SmoothingMode ، کیفیت هر دو را کنترل میکنه
CompositingMode شیوه برخورد با رسم روی رسم قبلی رو تعیین می کنه، اگر SourceCopy انتخاب بشه به این معنا است که رسم زیرین باید کلا نادیده گرفته بشه.
CompositingQuality شیوه ترکیب رسم روی رسم قبلی رو تغییر میده، به عبارت دقیق تر الگوریتمی رو مشخص می کنه که وقتی رنگ رسم جدیدی روی رسم قبلی زیرش قرار میگیره محاسبه ترکیب دو رنگ رو انجام میده.
InterpolationMode شیوه منطبق کردن ترسیم از یک ماتریس پیکسلی مبدا در ماتریس مقصد رو مشخص می کنه، چیزی که بهش Interpolation میگن. مثلا وقتی تصویر 3x3 پیکسل ای قراره در فضای کوچکتر 2x2 رسم بشه این الگوریتم مشخص میکنه که هر کدوم از اون 4 پیکسل باید چه رنگی باشه.
PixelOffsetMode شیوه تطبیق رسم اعشاری رو با محدوده پیکسلی مشخص می کنه. فرضا وقتی شما با RectangleF رسم ای از موقعیت 3.1 افقی با طول 2.3 پیکسل دارید، این الگوریتمی است که باید تصمیم بگیره ماتریسی با موقعیت های اعشاری چطور روی ماتریس پیکسلی که موقعیت ها بدون اعشار هستند تطبیق داده بشه.
SmoothingMode شیوه رسم خط و لبه های ناحیه های رنگ شده رو مشخص میکنه.
TextRenderingHint شیوه Hinting فونت رو مشخص می کنه. وقتی منحنی یک فونت میخواد در ماتریس پیکسلی قرار بگیره معمولا یک عملیات Hinting انجام میشه که منحنی Glyph کاراکتر رو که اصولا بین مرز دو پیکسل مجاور سرگردون مونده، عمدا روی یکی از اون دو پیکسل منطبق میکنه تا خطوط فونت بجای محو بودن کاملا Sharp دیده بشه و اینکار روی خوانایی فونت مخصوصا در ابعاد پایین خیلی تاثیر داره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
باز که میگید روش دوم. این روشی نیست که دومی باشه.
شما توی یک لیوان آب میوه می ریزید و بعد خالیش کنید و بعد داخلش نوشابه گازداری میریزید، دیگه چیزی از آب میوه هه تو لیوان نمونده که بگید با این روش مزه آب میوه رو به مزه نوشابه تبدیل می کنیم.


CompositingMode شیوه برخورد با رسم روی رسم قبلی رو تعیین می کنه، اگر SourceCopy انتخاب بشه به این معنا است که رسم زیرین باید کلا نادیده گرفته بشه.
CompositingQuality شیوه ترکیب رسم روی رسم قبلی رو تغییر میده، به عبارت دقیق تر الگوریتمی رو مشخص می کنه که وقتی رنگ رسم جدیدی روی رسم قبلی زیرش قرار میگیره محاسبه ترکیب دو رنگ رو انجام میده.
InterpolationMode شیوه منطبق کردن ترسیم از یک ماتریس پیکسلی مبدا در ماتریس مقصد رو مشخص می کنه، چیزی که بهش Interpolation میگن. مثلا وقتی تصویر 3x3 پیکسل ای قراره در فضای کوچکتر 2x2 رسم بشه این الگوریتم مشخص میکنه که هر کدوم از اون 4 پیکسل باید چه رنگی باشه.
PixelOffsetMode شیوه تطبیق رسم اعشاری رو با محدوده پیکسلی مشخص می کنه. فرضا وقتی شما با RectangleF رسم ای از موقعیت 3.1 افقی با طول 2.3 پیکسل دارید، این الگوریتمی است که باید تصمیم بگیره ماتریسی با موقعیت های اعشاری چطور روی ماتریس پیکسلی که موقعیت ها بدون اعشار هستند تطبیق داده بشه.
SmoothingMode شیوه رسم خط و لبه های ناحیه های رنگ شده رو مشخص میکنه.
TextRenderingHint شیوه Hinting فونت رو مشخص می کنه. وقتی منحنی یک فونت میخواد در ماتریس پیکسلی قرار بگیره معمولا یک عملیات Hinting انجام میشه که منحنی Glyph کاراکتر رو که اصولا بین مرز دو پیکسل مجاور سرگردون مونده، عمدا روی یکی از اون دو پیکسل منطبق میکنه تا خطوط فونت بجای محو بودن کاملا Sharp دیده بشه و اینکار روی خوانایی فونت مخصوصا در ابعاد پایین خیلی تاثیر داره.

خیلی ممنون
پس بجز TextRenderingHint که فقط مربوط به رندر متن میشه ، بقیه ی پروپرتی ها هم میتونن مربوط به رندر متن و هم مربوط به رندر image و هر نوع دیگه ای باشن . درسته؟

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

بعد اینکه استاد علی ، من کلاس TransparentControl را دارم یه کم تغییر میدم . (یه کلاس جداگانه برای کارهای مربوط به قسمت bitmap بنام TransparentControlBitmap و یه کلاس جداگانه برای کارهای مربوط به قسمت متن ، بنام TransparentControlText زدم) . توی کلاس TransparentControlBitmap هم یه بیت مپ بنام ControlDisabledBitmap برای زمانی که کنترل فعال و غیر فعال میشه ، ساختم اما مشکلش اینه که وقتی کنترل TransparentControl مون را غیر فعال میکنیم ، رسم ای انجام نمیگیره. (اگه بیت مپ برای ControlDisabledBitmap را ندیم ، بیت مپی خاکستری را نسبت به بیت مپِ پیش فرض که تعیین کرده بودیم را در نظر میگیره) .
فایل را در زیر میذارم . دقت کنید ، چون در حال تغییر این کلاس هستم ، بعضی از اعضا شاید کار نکنن ولی این کدی که در زیر مینویسم ، باید بدون مشکل کار کنه اما نمیدونم مشکلش کجاست (فقط همین متد سازنده ی کلاس TransparentControl که فعلا در کد زیر نوشتم ، کار میکنه) :


کد:
        private TransparentControl transparentControl;


        public MainForm()
        {
            InitializeComponent();


            Bitmap bitmap = new Bitmap(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\PanelToolBar\Close\Close.png");
            TransparentControlBitmap controlBitmap = new TransparentControlBitmap(bitmap);
            this.transparentControl = new TransparentControl(controlBitmap, new Point(200, 10));

            this.Controls.Add(transparentControl);

            Button button1 = new Button();
            button1.Bounds = new Rectangle(10, 10, 150, 35);
            button1.Text = "Transparent Control Disable";
            button1.Click += new EventHandler(this.Button1_MouseClick);

            this.Controls.Add(button1);
        }


        private void Button1_MouseClick(object sender, EventArgs e)
        {
            this.transparentControl.Enabled = false;
        }

حالا اگه فرم را minimize و بعد ماکسیمایز کنیم ، اون رسم برای بیت مپ ControlDisabledBitmap انجام میشه . یا مثلا اگه کد :


کد:
this.transparentControl.Enabled = false;

را همون اول در متد سازنده بذاریم (بجای اینکه درون Button1_MouseClick بذاریم) ، رسم انجام میشه.
چرا؟ دلیلش چیه؟
 

پیوست ها

  • TransparentControl.rar
    10.6 کیلوبایت · بازدیدها: 1

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد علی ، میدونین مشکل از کجاست؟
الان در کلاس TransparentControl ، اگه توی متد OnEnabledChanged ، یه MessageBox بذارم ، مشکلش حل میشه و همون لحظه رسم میکنه! :


کد:
        protected override void OnEnabledChanged(EventArgs e)
        {
            if (this.Enabled == true)
                this.EventOperation(0);
            else
                this.EventOperation(3);

            MessageBox.Show(this.Enabled.ToString());
            base.OnEnabledChanged(e);
        }

(یا همونطور که گفته بودم ، اگه بعد از disable و enable کردن ، فرم را مینیمایز و ماکسیمایز کنیم ، درست میشه)
علتش را میدونین که مشکل از کجاست؟ من چک میکنم ، از جایی ، مشکلی نمیبینم.
 

the_king

مدیرکل انجمن
خیلی ممنون
پس بجز TextRenderingHint که فقط مربوط به رندر متن میشه ، بقیه ی پروپرتی ها هم میتونن مربوط به رندر متن و هم مربوط به رندر image و هر نوع دیگه ای باشن . درسته؟
نه همه شون.
فکر می کنم واضح توضیح دادم که SmoothingMode مربوط به رسم خط و رنگ کردنه و ربطی به رندر Image نداره. وقتی Image رندر میشه که خط رسم نمی کنه.
همانطور که InterpolationMode برعکس، مربوط به ماتریس پیکسلی است و ربطی به رسم خط و رنگ کردن نداره.

سلامی مجدد
استاد علی ، میدونین مشکل از کجاست؟
الان در کلاس TransparentControl ، اگه توی متد OnEnabledChanged ، یه MessageBox بذارم ، مشکلش حل میشه و همون لحظه رسم میکنه! :


کد:
        protected override void OnEnabledChanged(EventArgs e)
        {
            if (this.Enabled == true)
                this.EventOperation(0);
            else
                this.EventOperation(3);

            MessageBox.Show(this.Enabled.ToString());
            base.OnEnabledChanged(e);
        }

(یا همونطور که گفته بودم ، اگه بعد از disable و enable کردن ، فرم را مینیمایز و ماکسیمایز کنیم ، درست میشه)
علتش را میدونین که مشکل از کجاست؟ من چک میکنم ، از جایی ، مشکلی نمیبینم.
مشکل شما base.OnEnabledChanged(e) ئه، باید بذاریدش کنار. رسم کنترل شما که روال عادی رو طی نمی کنه، نه ترتیبش و نه رسمش.
با MessageBox درست میشه چون بین شون وقفه زمانی ایجاد می کنید.
به محض اینکه Enabled عوض بشه کدتون رو درگیر چند تا رخداد رسم مجزا می کنید که هم مورد اضافی داخلشون هست و هم چون با ترتیب دلخواه شما پیام شون ارسال نمیشه نتیجه رسم رو خراب می کنه.
تا میاد از والد شروع کنه به رسم و برسه به کنترل تون، OnEnabledChanged رسمش که مناسب پنجره کنترل شما نیست رو انجام داده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نه همه شون.
فکر می کنم واضح توضیح دادم که SmoothingMode مربوط به رسم خط و رنگ کردنه و ربطی به رندر Image نداره. وقتی Image رندر میشه که خط رسم نمی کنه.
همانطور که InterpolationMode برعکس، مربوط به ماتریس پیکسلی است و ربطی به رسم خط و رنگ کردن نداره.


مشکل شما base.OnEnabledChanged(e) ئه، باید بذاریدش کنار. رسم کنترل شما که روال عادی رو طی نمی کنه، نه ترتیبش و نه رسمش.
با MessageBox درست میشه چون بین شون وقفه زمانی ایجاد می کنید.

خیلی ممنون استاد علی
من اگه کد base.OnEnabledChanged(e) را از متد OnEnabledChanged بردارم ، اصلا عمل Enable و Disable کردن اتفاق نمیافته (رسم اش منظورم نیست . در این صورت ، رسم اش خوب انجام میشه) . در این صورت ، حتی اگه کنترل مو Disable هم کنم ، باز به رویدادهای موس (مثل MouseEnter و ...) و کیبرد پاسخگوست و غیرفعال نمیشه.
یعنی میگین اون base.OnEnabledChanged را حذف کنم و بجاش خودم کد غیر فعال سازی برای کنترل مو توی متد OnEnabledChanged بنویسم؟


به محض اینکه Enabled عوض بشه کدتون رو درگیر چند تا رخداد رسم مجزا می کنید که هم مورد اضافی داخلشون هست و هم چون با ترتیب دلخواه شما پیام شون ارسال نمیشه نتیجه رسم رو خراب می کنه.
تا میاد از والد شروع کنه به رسم و برسه به کنترل تون، OnEnabledChanged رسمش که مناسب پنجره کنترل شما نیست رو انجام داده.

این دو خط را دقیق متوجه نشدم.
منظورتون از "مورد اضافی داخلشون" چیه؟
منظورتون از "چون با ترتیب دلخواه شما پیام شون ارسال نمیشه نتیجه رسم رو خراب می کنه" را هم متوجه نشدم کدوم قسمت از کد و به چه دلیل میگید؟
خط آخر هم متوجه نشدم . یه کم بیشتر و با مثال از کدم ، توضیح میدین؟ کلا این دو خط تون را متوجه نشدم.
 

the_king

مدیرکل انجمن
خیلی ممنون استاد علی
من اگه کد base.OnEnabledChanged(e) را از متد OnEnabledChanged بردارم ، اصلا عمل Enable و Disable کردن اتفاق نمیافته (رسم اش منظورم نیست . در این صورت ، رسم اش خوب انجام میشه) . در این صورت ، حتی اگه کنترل مو Disable هم کنم ، باز به رویدادهای موس (مثل MouseEnter و ...) و کیبرد پاسخگوست و غیرفعال نمیشه.
یعنی میگین اون base.OnEnabledChanged را حذف کنم و بجاش خودم کد غیر فعال سازی برای کنترل مو توی متد OnEnabledChanged بنویسم؟
وقتی یک متدی مثل base.OnEnabledChanged دارید که ترکیبی از چند کار رو می کنه که بخشی اش رو می پسندید و بخشی اش را نمی پسندید، چاره ای ندارید جز اینکه قید اش را بزنید وآن بخش مناسبش را هم خودتان انجام دهید.
نمی توانید که کدش رو تغییر بدید. چیزی که تغییر ناپذیره کدی است که در Control.OnEnabledChanged انجام میشه و Invalidate و پشت سرش Update می کنه. Update یعنی معطل رسم بعدی نمیشه و همون موقع درخواست رسم فوری می کنه. چون کنترل شما فرزندی نداره روتینی که برای اعمال اون Enabled به فرزندان انجام میشه هم لازمتون نیست، فقط باید پنجره کنترل تون رو از طریق this.Handle اش Enable/Disable کنید :
کد:
  [DllImport("user32.dll")]
  [return: MarshalAs(UnmanagedType.Bool)]
  private static extern bool EnableWindow(IntPtr hwnd, bool fEnable);

این دو خط را دقیق متوجه نشدم.
منظورتون از "مورد اضافی داخلشون" چیه؟
شما کنترل تون رو Disable یا Enable می کنید، برای همچین کاری چند تا Invalidate باید روی کنترل تون انجام بشه؟ یک مورد، نه بیشتر. در کدی که شما فعلا دارید دو تا Invalidate انجام میشه، یکی داخل base.OnEnabledChanged و یکی داخل AllParents_Invalidated. با هم سازگار هم نیستند چون در AllParents_Invalidated شما ابتدا والد رو رسم کرده بودید و بعد تازه کنترل تون رو Invalidate می کنید ولی base.OnEnabledChanged منتظر رسم والد نمیمونه. کاری که base.OnEnabledChanged میکنه اضافیه، نه تنها اضافیه، کار خراب کن هم هست.

منظورتون از "چون با ترتیب دلخواه شما پیام شون ارسال نمیشه نتیجه رسم رو خراب می کنه" را هم متوجه نشدم کدوم قسمت از کد و به چه دلیل میگید؟
شما در OnEnabledChanged اول پنجره والد رو Invalidate می کنید و بعد base.OnEnabledChanged رو اجرا می کنید که اونهم پنجره خود کنترل رو Invalidate می کنه.

شما که به پنجره کنترل نگفتید لطفا Invalidate شدنت رو معطل نگهدار، چون پنجره والد هنوز رسم اش تموم نشده. تا پنجره والد بیاد رسمش رو انجام بده پنجره کنترل تون Invalidate + Update رو دریافت کرده و
رسم اش رو انجام داده. برای کنترل شما هم ترتیب رسم مهمه، باید همیشه اول والد رسم بشه تا بعد نوبت به خود کنترل برسه. چون هر بار که والد مستقل رسم میشه محتویات رسم کنترل تون هم پاک میشه.
خط آخر هم متوجه نشدم . یه کم بیشتر و با مثال از کدم ، توضیح میدین؟ کلا این دو خط تون را متوجه نشدم.
اگر بقیه شون رو متوجه شده باشین که خیلی عالیه. مثال کدتون OnEnabledChanged ئه دیگه. گشتن نمیخواد. شما از یک طرف با EventOperation(3) اون والد رو Invalidate می کنید که آخرش کنترل خودتون رو Invalidate کنه و هم با base.OnEnabledChanged خود کنترل تون رو Invalidate می کنید. کاری هم به این ندارید که base.OnEnabledChanged نه خبر داره و نه اهمیتی میده که شما در EventOperation چه برنامه ای برای رسم دارید.
قبلا بهتون ILSpy رو معرفی کردم. یک نگاهی که به کد Control.OnEnabledChanged بندازید می بینید که چطور Invalidate و Update میکنه :

userpaint.png
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
وقتی یک متدی مثل base.OnEnabledChanged دارید که ترکیبی از چند کار رو می کنه که بخشی اش رو می پسندید و بخشی اش را نمی پسندید، چاره ای ندارید جز اینکه قید اش را بزنید وآن بخش مناسبش را هم خودتان انجام دهید.
نمی توانید که کدش رو تغییر بدید. چیزی که تغییر ناپذیره کدی است که در Control.OnEnabledChanged انجام میشه و Invalidate و پشت سرش Update می کنه. Update یعنی معطل رسم بعدی نمیشه و همون موقع درخواست رسم فوری می کنه. چون کنترل شما فرزندی نداره روتینی که برای اعمال اون Enabled به فرزندان انجام میشه هم لازمتون نیست، فقط باید پنجره کنترل تون رو از طریق this.Handle اش Enable/Disable کنید :
کد:
  [DllImport("user32.dll")]
  [return: MarshalAs(UnmanagedType.Bool)]
  private static extern bool EnableWindow(IntPtr hwnd, bool fEnable);


شما کنترل تون رو Disable یا Enable می کنید، برای همچین کاری چند تا Invalidate باید روی کنترل تون انجام بشه؟ یک مورد، نه بیشتر. در کدی که شما فعلا دارید دو تا Invalidate انجام میشه، یکی داخل base.OnEnabledChanged و یکی داخل AllParents_Invalidated. با هم سازگار هم نیستند چون در AllParents_Invalidated شما ابتدا والد رو رسم کرده بودید و بعد تازه کنترل تون رو Invalidate می کنید ولی base.OnEnabledChanged منتظر رسم والد نمیمونه. کاری که base.OnEnabledChanged میکنه اضافیه، نه تنها اضافیه، کار خراب کن هم هست.


شما در OnEnabledChanged اول پنجره والد رو Invalidate می کنید و بعد base.OnEnabledChanged رو اجرا می کنید که اونهم پنجره خود کنترل رو Invalidate می کنه.

شما که به پنجره کنترل نگفتید لطفا Invalidate شدنت رو معطل نگهدار، چون پنجره والد هنوز رسم اش تموم نشده. تا پنجره والد بیاد رسمش رو انجام بده پنجره کنترل تون Invalidate + Update رو دریافت کرده و
رسم اش رو انجام داده. برای کنترل شما هم ترتیب رسم مهمه، باید همیشه اول والد رسم بشه تا بعد نوبت به خود کنترل برسه. چون هر بار که والد مستقل رسم میشه محتویات رسم کنترل تون هم پاک میشه.

اگر بقیه شون رو متوجه شده باشین که خیلی عالیه. مثال کدتون OnEnabledChanged ئه دیگه. گشتن نمیخواد. شما از یک طرف با EventOperation(3) اون والد رو Invalidate می کنید که آخرش کنترل خودتون رو Invalidate کنه و هم با base.OnEnabledChanged خود کنترل تون رو Invalidate می کنید. کاری هم به این ندارید که base.OnEnabledChanged نه خبر داره و نه اهمیتی میده که شما در EventOperation چه برنامه ای برای رسم دارید.
قبلا بهتون ILSpy رو معرفی کردم. یک نگاهی که به کد Control.OnEnabledChanged بندازید می بینید که چطور Invalidate و Update میکنه :

مشاهده پیوست 112515

آها پس با توصیفی که کردین ، مشکل از اینه که اول من میام در متد OnEnabledChanged ، متد EventOperation را که والد ها را رسم و invalidate میکنه ، فراخونی میکنم و بعد پشتِ سر این متدِ EventOperation ، همین کنترل TransparentControl را رسم و invalidate میکنم . بعدش میره base.OnEnabledChanged(e) را اجرا میکنه که در اونجا دوباره همین کنترل را رسم میکنه اما چون والد این کنترل ، از نوع Control هست ، بنابراین کنترل خاصی را رسم نمیکنه و فقط رنگ پشت زمینه ی کنترلِ والدِ همین کنترل را رسم میکنه که به نظر میرسه که کنترل را پاک میکنه.
بنابراین این کد را بعد از رسم در متد base.OnEnabledChanged(e) ، رسم کنیم ، یعنی اگه این کدهایی که در متد OnEnabledChanged نوشتیم را بجاش در رویداد EnabledChanged بنویسیم ، حل میشه (چون رویداد EnabledChanged زمانی اجرا میشه که قبل اش متد OnEnabledChanged و بنابراین متد base.OnEnabledChanged(e) اجرا شده و رسمِ مربوط در این متد ، انجام شده و بعدش ما در رویداد EnabledChanged ، میایم با همون کد که نوشتم ، کنترل والد و بعد همین کنترل را invalidate میکنیم)
این کار را انجام دادم و درست شد.
خیلی ممنون :rose:
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد علی ، چجوری میشه چک کرد که به یه رویداد ، مقدار داده شده یا نه؟

میخوام در TransparentControl ، به رویداد this.EnabledChanged درون تابع OnEnabledChanged مقدار بدم (برای اینکه چک کنم اگه دفعه ی قبل ، متصل بود و مقدار داشت ، دیگه دوباره الکی متصل نکنه و کد بیخودی اجرا نشه . البته چندان تاثیر و تاخیری در عملکرد برنامه هم نخواهد داشت)
اگه بگین که فقط میخواین یه بار بدی ، چرا توی متد سازنده نمیدی ؛ چون متد سازنده ام 2 نوع مختلف میگیره و اگه توی تابع هم بنویسم ، 2 بار باید تابعی که این کدش را مینویسم ، فراخونی کنم . البته مشکل خاصی نداره ولی اگه بشه درون تابع OnEnabledChanged مقداردهی اش کنم و همینطور چک کنم که قبلا مقدار داشت یا نه ، کد فقط یه جا نوشته میشه.
ممنون

اگر بقیه شون رو متوجه شده باشین که خیلی عالیه. مثال کدتون OnEnabledChanged ئه دیگه. گشتن نمیخواد. شما از یک طرف با EventOperation(3) اون والد رو Invalidate می کنید که آخرش کنترل خودتون رو Invalidate کنه و هم با base.OnEnabledChanged خود کنترل تون رو Invalidate می کنید. کاری هم به این ندارید که base.OnEnabledChanged نه خبر داره و نه اهمیتی میده که شما در EventOperation چه برنامه ای برای رسم دارید.
قبلا بهتون ILSpy رو معرفی کردم. یک نگاهی که به کد Control.OnEnabledChanged بندازید می بینید که چطور Invalidate و Update میکنه :

مشاهده پیوست 112515

الان استاد علی ، این this.Invalidate که از کلاس پدرش اجرا میشه (منظورم در متد base.OnEnabledChanged هست که با خط قرمز نشون دادین) ، سر آخر باعث میشه که متد OnPaint و بعد رویداد Paint اجرا بشه دیگه؟ درسته؟
خوب پس باید متد Override شده ی OnPaint در کلاس من یعنی کلاس TransparentControl را اجرا کنه دیگه؟ درسته؟
پس باید کدی که من در این متد نوشتم را اجرا کنه و رسمی که گفتم (رسم بیت مپ) را انجام بده.
پس چرا انگار رسم خودش را انجام میده؟

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

بعد اینکه در سایت زیر ، سورس کدهای دات نت هم وجود داره :

Reference Source

 
آخرین ویرایش:

the_king

مدیرکل انجمن
سلامی مجدد
استاد علی ، چجوری میشه چک کرد که به یه رویداد ، مقدار داده شده یا نه؟

رویداد عملا یک مجموعه است که با اولین اتصال متد بهش ایجاد میشه و می توانید مکررا یک متد رو هم بهش متصل کنید. اما بررسی این مجموعه بستگی به شیوه تعریف کردنش داره.
برای رویدادی که خودتون در کلاسی ایجاد کنید، کار قدری راحته چون مقدار رویداد اگه null باشه یعنی متدی بهش متصل نیست. برای همین برای Invoke شدن EventHandler ها بجای eventname.Invoke یا از eventname?.invoke استفاده می کنند که اگر eventname مقدارش null بود سر Invoke خطا نده یا قبلش با if اون بررسی null نبودن رو انجام میدن.
اما برای رویدادی مثل Control.Click یکم پیچیده است، چون اولا بصورت Property پیاده سازی شده، نه فیلد، و ثانیا از مواردی استفاده کرده که شما بصورت عادی بخاطر protected / private بودنشون دسترسی بهشون ندارید.

میخوام در TransparentControl ، به رویداد this.EnabledChanged درون تابع OnEnabledChanged مقدار بدم (برای اینکه چک کنم اگه دفعه ی قبل ، متصل بود و مقدار داشت ، دیگه دوباره الکی متصل نکنه و کد بیخودی اجرا نشه . البته چندان تاثیر و تاخیری در عملکرد برنامه هم نخواهد داشت)
اگه بگین که فقط میخواین یه بار بدی ، چرا توی متد سازنده نمیدی ؛ چون متد سازنده ام 2 نوع مختلف میگیره و اگه توی تابع هم بنویسم ، 2 بار باید تابعی که این کدش را مینویسم ، فراخونی کنم . البته مشکل خاصی نداره ولی اگه بشه درون تابع OnEnabledChanged مقداردهی اش کنم و همینطور چک کنم که قبلا مقدار داشت یا نه ، کد فقط یه جا نوشته میشه.
ممنون
کدی که می نویسم یک حالت کلی نداره که برای همه کلاس ها و رخداد ها جواب بده، بر اساس ساختار رخداد ها در Control نوشتمش :
کد:
        public static bool AddToEventHandler(Control eventOwner, string eventName, string methodName, object methodOwner)
        {
            var events = eventOwner.GetType().GetProperty("Events", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var eventKey = typeof(Control).GetField("Event" + eventName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetValue(null);
            var allEventsList = (EventHandlerList)events.GetValue(eventOwner);
            var eventList = allEventsList[eventKey];
            var methodInfo = methodOwner.GetType().GetMethod(methodName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            foreach (var item in eventList.GetInvocationList())
            {
                if (item.Method == methodInfo)
                {
                    return false;
                }
            }
            allEventsList.AddHandler(eventKey, methodInfo.CreateDelegate(typeof(EventHandler), methodOwner));
            return true;
        }
مثلا :
کد:
            AddToEventHandler(button1, "Click", "button1_Click", this);
این متد رخداد Click کنترل button1 رو به متد button1_Click که در شیء this قرار داره متصل می کنه. و فقط در صورتی اینکار رو میکنه که قبلا متصل نشده باشه.
یعنی ده بار هم که اجرا اش کنید صرفا یکبار اول متصل میشه و دفعات بعدی false بر میگردونه.

الان استاد علی ، این this.Invalidate که از کلاس پدرش اجرا میشه (منظورم در متد base.OnEnabledChanged هست که با خط قرمز نشون دادین) ، سر آخر باعث میشه که متد OnPaint و بعد رویداد Paint اجرا بشه دیگه؟ درسته؟
خوب پس باید متد Override شده ی OnPaint در کلاس من یعنی کلاس TransparentControl را اجرا کنه دیگه؟ درسته؟
پس باید کدی که من در این متد نوشتم را اجرا کنه و رسمی که گفتم (رسم بیت مپ) را انجام بده.
پس چرا انگار رسم خودش را انجام میده؟

رسم خودش نیست، رسم شما است، اما این رسم رو زمانی داره انجام میده که هنوز والد رسم اش رو انجام نداده. چون والد پشت سرش رسم خودش رو انجام میده شما چیزی از رسم تون نمی بینید و خیال می کنید فقط پاک کرده.
اونی که رسم رو پاک کرده رسم والد ئه، نه base.OnEnabledChanged
Invalidate یعنی باطل کردن، یعنی شما به کنترل میگید چیزی که اینجا کشیدی رو دیگه قبول ندارم، معتبر نیست، از نو رسم اش کن. اما با Invalidate بهش نمیگید یالا همین الان رسم اش کن. فقط پشت سرش یک پیام WM_PAINT به پنجره فرستاده میشه که در نوبت رسم قرار میگیره. در مورد پنجره والد هم همینطوره، شما بهش دستور رسم دادید، ولی اونم در نوبت قرار گرفته. ولی داخل base.OnEnabledChanged با اون Update میگه عجله دارم، فوری هر چی Invalidate شده رو Update کن، یعنی هر قسمتی که تو صف رسم بود همین الان رسم کن. که شامل اون Invalidate شما در AllParents_Invalidated هم میشه. برای همینه که بعد از رسم والد دیگه چیزی برای رسم در پنجره کنترل شما نمونده، اون Invalidate ای که شما در AllParents_Invalidated انجام دادید با همون Update ای که base.OnEnabledChanged میکنه اعمال میشه، مجددا و جدا یکبار دیگه انجام نمیشه.

اینکه شما چند جا Invalidate کنید معنی اش این نیست که الزاما برای هر کدوم رسم مجزایی صورت بگیره، بستگی به این داره که مهلتی برای رسم در فاصله میان این Invalidate شدن ها پیش بیاد یا نه. اگر مهلتی نباشه شاید اصلا یک رسم اونم صرفا بعد از آخری صورت بگیره :
کد:
    public partial class Form1 : Form
    {
        public class MyControl : Control
        {
            public int Counter = 0;

            protected override void OnPaint(PaintEventArgs pevent)
            {
                Counter++;
                base.OnPaint(pevent);
            }
        }

        private MyControl c;

        public Form1()
        {
            InitializeComponent();
            c = new MyControl() { Bounds = new Rectangle(150, 100, 10, 10), Parent = this };
            var b = new Button() { Bounds = new Rectangle(10, 10, 80, 25), Text = "Invalidate", Parent = this };
            b.Click += b_Click;
        }

        private void b_Click(object sender, EventArgs e)
        {
            c.Counter = 0;
            c.Invalidate();
            c.Invalidate();
            c.Invalidate();
            c.Invalidate();
            c.Invalidate();
            c.Update();
            var counter = c.Counter;
            Text = counter.ToString();
        }

------------------------------------------
بعد اینکه در سایت زیر ، سورس کدهای دات نت هم وجود داره :

Reference Source
بله، البته به عنوان راهنما و خودشون هم میگن ناقصه، ولی طبعا زمانی که به ILSpy یا NET Reflector. دسترسی ندارید میتونه مفید باشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
رویداد عملا یک مجموعه است که با اولین اتصال متد بهش ایجاد میشه و می توانید مکررا یک متد رو هم بهش متصل کنید. اما بررسی این مجموعه بستگی به شیوه تعریف کردنش داره.
برای رویدادی که خودتون در کلاسی ایجاد کنید، کار قدری راحته چون مقدار رویداد اگه null باشه یعنی متدی بهش متصل نیست. برای همین برای Invoke شدن EventHandler ها بجای eventname.Invoke یا از eventname?.invoke استفاده می کنند که اگر eventname مقدارش null بود سر Invoke خطا نده یا قبلش با if اون بررسی null نبودن رو انجام میدن.
اما برای رویدادی مثل Control.Click یکم پیچیده است، چون اولا بصورت Property پیاده سازی شده، نه فیلد، و ثانیا از مواردی استفاده کرده که شما بصورت عادی بخاطر protected / private بودنشون دسترسی بهشون ندارید.


کدی که می نویسم یک حالت کلی نداره که برای همه کلاس ها و رخداد ها جواب بده، بر اساس ساختار رخداد ها در Control نوشتمش :
کد:
        public static bool AddToEventHandler(Control eventOwner, string eventName, string methodName, object methodOwner)
        {
            var events = eventOwner.GetType().GetProperty("Events", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var eventKey = typeof(Control).GetField("Event" + eventName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetValue(null);
            var allEventsList = (EventHandlerList)events.GetValue(eventOwner);
            var eventList = allEventsList[eventKey];
            var methodInfo = methodOwner.GetType().GetMethod(methodName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            foreach (var item in eventList.GetInvocationList())
            {
                if (item.Method == methodInfo)
                {
                    return false;
                }
            }
            allEventsList.AddHandler(eventKey, methodInfo.CreateDelegate(typeof(EventHandler), methodOwner));
            return true;
        }
مثلا :
کد:
            AddToEventHandler(button1, "Click", "button1_Click", this);
این متد رخداد Click کنترل button1 رو به متد button1_Click که در شیء this قرار داره متصل می کنه. و فقط در صورتی اینکار رو میکنه که قبلا متصل نشده باشه.
یعنی ده بار هم که اجرا اش کنید صرفا یکبار اول متصل میشه و دفعات بعدی false بر میگردونه.


خیلی ممنون

رسم خودش نیست، رسم شما است، اما این رسم رو زمانی داره انجام میده که هنوز والد رسم اش رو انجام نداده. چون والد پشت سرش رسم خودش رو انجام میده شما چیزی از رسم تون نمی بینید و خیال می کنید فقط پاک کرده.
اونی که رسم رو پاک کرده رسم والد ئه، نه base.OnEnabledChanged
Invalidate یعنی باطل کردن، یعنی شما به کنترل میگید چیزی که اینجا کشیدی رو دیگه قبول ندارم، معتبر نیست، از نو رسم اش کن. اما با Invalidate بهش نمیگید یالا همین الان رسم اش کن. فقط پشت سرش یک پیام WM_PAINT به پنجره فرستاده میشه که در نوبت رسم قرار میگیره. در مورد پنجره والد هم همینطوره، شما بهش دستور رسم دادید، ولی اونم در نوبت قرار گرفته. ولی داخل base.OnEnabledChanged با اون Update میگه عجله دارم، فوری هر چی Invalidate شده رو Update کن، یعنی هر قسمتی که تو صف رسم بود همین الان رسم کن. که شامل اون Invalidate شما در AllParents_Invalidated هم میشه. برای همینه که بعد از رسم والد دیگه چیزی برای رسم در پنجره کنترل شما نمونده، اون Invalidate ای که شما در AllParents_Invalidated انجام دادید با همون Update ای که base.OnEnabledChanged میکنه اعمال میشه، مجددا و جدا یکبار دیگه انجام نمیشه.

اینکه شما چند جا Invalidate کنید معنی اش این نیست که الزاما برای هر کدوم رسم مجزایی صورت بگیره، بستگی به این داره که مهلتی برای رسم در فاصله میان این Invalidate شدن ها پیش بیاد یا نه. اگر مهلتی نباشه شاید اصلا یک رسم اونم صرفا بعد از آخری صورت بگیره :
کد:
    public partial class Form1 : Form
    {
        public class MyControl : Control
        {
            public int Counter = 0;

            protected override void OnPaint(PaintEventArgs pevent)
            {
                Counter++;
                base.OnPaint(pevent);
            }
        }

        private MyControl c;

        public Form1()
        {
            InitializeComponent();
            c = new MyControl() { Bounds = new Rectangle(150, 100, 10, 10), Parent = this };
            var b = new Button() { Bounds = new Rectangle(10, 10, 80, 25), Text = "Invalidate", Parent = this };
            b.Click += b_Click;
        }

        private void b_Click(object sender, EventArgs e)
        {
            c.Counter = 0;
            c.Invalidate();
            c.Invalidate();
            c.Invalidate();
            c.Invalidate();
            c.Invalidate();
            c.Update();
            var counter = c.Counter;
            Text = counter.ToString();
        }


بله، البته به عنوان راهنما و خودشون هم میگن ناقصه، ولی طبعا زمانی که به ILSpy یا NET Reflector. دسترسی ندارید میتونه مفید باشه.

خیلی ممنون
خوب باز هم شما میگید update رو وقتی فراخونی میکنه ، به ترتیبی که Invalidate ها توی صف بودن ، شروع به رسم کردن میکنه دیگه؟
کدش این بود دیگه :


کد:
        protected override void OnEnabledChanged(EventArgs e)
        {
            if (this.Enabled == true)
                this.EventOperation(0);
            else
                this.EventOperation(3);


            base.OnEnabledChanged(e);
        }

خوب اول متد EventOperation اجرا میشه . یعنی اول ، Invalidate ، برای والد و بعد ، Invalidate ، برای کنترل جاریِ خودمون توی صف میره . بعد هم که کد base.OnEnabledChanged(e) متد Invalidate را فراخونی میکنه .
پس یعنی باز هم به همین روال عادی (در صف که گفتید) باید رسم کنه . یعنی اول والدها را باید رسم کنه . بعد کنترل TransparentControl خودمون و باز هم دوباره کنترل TransparentControl خودمون این بار از متد base.OnEnabledChanged(e) که Invalidate شد رو باید رسم کنه .
پس با این روال ، مگه باز هم نباید روندش طبیعی باشه؟
 

the_king

مدیرکل انجمن
خیلی ممنون
خوب باز هم شما میگید update رو وقتی فراخونی میکنه ، به ترتیبی که Invalidate ها توی صف بودن ، شروع به رسم کردن میکنه دیگه؟
کدش این بود دیگه :


کد:
        protected override void OnEnabledChanged(EventArgs e)
        {
            if (this.Enabled == true)
                this.EventOperation(0);
            else
                this.EventOperation(3);


            base.OnEnabledChanged(e);
        }

خوب اول متد EventOperation اجرا میشه . یعنی اول ، Invalidate ، برای والد و بعد ، Invalidate ، برای کنترل جاریِ خودمون توی صف میره . بعد هم که کد base.OnEnabledChanged(e) متد Invalidate را فراخونی میکنه .
پس یعنی باز هم به همین روال عادی (در صف که گفتید) باید رسم کنه

خوبه که براتون کد مثال به اون واضحی نوشتم که با Counter تعداد Paint ها رو ببینید. در پست قبلی من چند تا Invalidate داریم و چند تا رخداد Paint داریم؟ هر بار Invalidate شد یک Paint اتفاق افتاد؟
چرا روی اون کد ساده قضاوت نمی کنید.
Invalidate با ترتیب ای که شما می خواهید و میگید اتفاق می افته اما Invalidate رسم که نیست، اعلام ابطال ئه با درخواست یک رسم. هیچکدوم از اینجور فرمان ها مثل Invalidate باعث نمیشه کدتون اونجا متوقف بشه تا وقتی که رسمی صورت بگیره. شما Invalidate می کنید و درخواست رسم فرستاده میشه و کدتون ادامه پیدا می کنه. رسم پنجره درخواستی نیست که قبل از اجرای سطر بعدی کدتون اتفاق بیافته. اگر اینطور بود که ماوس موقع جابجایی باید بخاطر هر رسم پنجره ای سکته میکرد و لحظه ای متوقف میشد.

. یعنی اول والدها را باید رسم کنه . بعد کنترل TransparentControl خودمون و باز هم دوباره کنترل TransparentControl خودمون این بار از متد base.OnEnabledChanged(e) که Invalidate شد رو باید رسم کنه .
پس با این روال ، مگه باز هم نباید روندش طبیعی باشه؟
می نویسم ولی چه فایده، باز میگید رسم. پست قبلی ام رو که خوندید. Invalidate یعنی رسم؟ رسم نیست. رسم یک عملیات جدا است و Invalidate یک عملیات جدا. هم روال کار رسم رو توضیح دادم و هم شیوه کار Invalidate رو. دیگه چی بگم.
 

جدیدترین ارسال ها

بالا