سئوالات و مباحث WPF

the_king

مدیرکل انجمن
خیلی ممنون استاد .
بله ، میدونم .
منظورم این بود که منطقِ این دو رویداد چیه که من حس میکنم که شانسی اجرا میشن؟
یا مشکل از متد Debug.WriteLine در این قضیه هست؟ یا چیز دیگه ای؟
اینکه شما چرا احساس می کنید شانسی هستند رو نمی دونم اما قاعدتا ربطی به Debug.WriteLine نداره.
هیچ قاعده عجیب و غریبی در این دو رخداد هم نیست.

اصلا سردرگم شدم . پروپرتیِ Window.IsMouseOver رو که در تایمر اجرا میکنم (و هر 200 میلی ثانیه ، این پروپرتی را Debug.WriteLine میکنم) ، این بار ، در پنجره ای که تست میکنم ، مشکلی نداره و دقیق و درست کار میکنه اما در پنجره ی AlarmBox ، باز درست عمل نمیکنه .
کد های برنامه نویسی رو comment کنید تا ببینید چه کاری انجام می دهید که در رخداد ها اختلال ایجاد می کنه، از comment کردن همون Capture و Release شروع کنید.

اگه از طریقِ Hook کردنِ موس پیش برم ، جواب میگیرم (چون از این جهت میپرسم که اگه مشکلاتِ احتمالی ای وجود داره که ازش باخبرید برای این زمینه ، بیخودی روش وقت نذارم) .
من نظرم رو گفتم، ولی شما مختارید برای ایده ای که از نظر من ایده بدی است روش های مختلفی که به ذهنتون میرسه امتحان کنید و برایش وقت صرف کنید. اینکه بیخودی باشه یا با خودی، به تصور خودتون از ایده بستگی داره.

یعنی ، هیچ کجا ، هیچ کس ، یه همچین چیزی (فلش زدن window) را پیاده سازی نکرده که الگو بگیرم؟!
خودِ مایکروسافت پس چی کار کرده؟ در سطح برنامه های کاربردی ، پیاده سازی کرده دیگه؟
هر کسی که طراحیش کرده باید به اینجور سوالات جواب بده. مطمئن باشید که اگر کسی در جایی پیاده سازی اش کنه هم زنگ نمی زنه به من اطلاع بده که چیکار کرده.
 

SajjadKhati

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


کد های برنامه نویسی رو comment کنید تا ببینید چه کاری انجام می دهید که در رخداد ها اختلال ایجاد می کنه، از comment کردن همون Capture و Release شروع کنید.


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


هر کسی که طراحیش کرده باید به اینجور سوالات جواب بده. مطمئن باشید که اگر کسی در جایی پیاده سازی اش کنه هم زنگ نمی زنه به من اطلاع بده که چیکار کرده.

خیلی ممنون استاد .
با تست هایی متوجه شدم که رویداد MouseLeave ئه اون ویندوز (که اون ویندوز ، همون پروپرتیِ Container هست) ، مشکل داره .
این رویداد را توی ویندوزِ دیگه ی wpf (مثل پروژه ی خودم) تست کردم ، مشکلی نداشت (اول که گفته بودم مشکل داشت ، الان انگار مشکلی نداره) .

الان نمیدونم چرا رویداد MouseLeave ئه پروپرتیِ Container ، مشکل داره .
نکته ی بسیار جالبش اینجاست که ، wpf یه آیکونِ کوچیکی برای Debug داره زمانی که از ویژال استودیو برنامه را اجرا میکنیم (وقتی روی اون دکمه کلیک کنیم ، دکمه هایی مثل "Go To Live Visual Tree" و "Hot Reload" و اینها باز میشن) .
خوب ، حالا اگه موس را فقط از روی این آیکون (برای Debug) خارج کنم ، فقط در همین صورت هست که رویدادِ MouseLeave ئه Container اجرا میشه و اگه از هر جایِ دیگه ای موس را خارج کنم ، این رویداد اجرا نمیشه .
و چون زمانی که برنامه را از ویژال استودیو اجرا نکنم ، اون آیکون وجود نداره ، اصلا رویدادِ MouseLeave ئه Container ، اجرا نمیشه .
نمیدونم مشکلش از کجاست .

تشکر استاد
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد .
با تست هایی متوجه شدم که رویداد MouseLeave ئه اون ویندوز (که اون ویندوز ، همون پروپرتیِ Container هست) ، مشکل داره .
این رویداد را توی ویندوزِ دیگه ی wpf (مثل پروژه ی خودم) تست کردم ، مشکلی نداشت (اول که گفته بودم مشکل داشت ، الان انگار مشکلی نداره) .

الان نمیدونم چرا رویداد MouseLeave ئه پروپرتیِ Container ، مشکل داره .
نکته ی بسیار جالبش اینجاست که ، wpf یه آیکونِ کوچیکی برای Debug داره زمانی که از ویژال استودیو برنامه را اجرا میکنیم (وقتی روی اون دکمه کلیک کنیم ، دکمه هایی مثل "Go To Live Visual Tree" و "Hot Reload" و اینها باز میشن) .
خوب ، حالا اگه موس را فقط از روی این آیکون (برای Debug) خارج کنم ، فقط در همین صورت هست که رویدادِ MouseLeave ئه Container اجرا میشه و اگه از هر جایِ دیگه ای موس را خارج کنم ، این رویداد اجرا نمیشه .
و چون زمانی که برنامه را از ویژال استودیو اجرا نکنم ، اون آیکون وجود نداره ، اصلا رویدادِ MouseLeave ئه Container ، اجرا نمیشه .
نمیدونم مشکلش از کجاست .

تشکر استاد

این کلاس رو توی پروژه ی کوچیک تر هم که بردم ، باز همین همین جوری هه (پروژه را در زیر ، پیوست میکنم) .
نمیدونم مشکلِ رویدادِ MouseLeave ئه Container (که در کلاس AlarmBox در متد ShowModelessInstance مقداردهی کردم) ، کجاست؟

اگه در پست قبلی که توضیحی که دادم رو ببینید ، میبینید که وقتی این برنامه ، بصورت مستقلِ از ویژال استودیو اجرا بشه ، اصلا رویدادِ MouseLeave اش کار نمیکنه .
ولی رویدادِ MouseEnter اش مشکلی نداره (اون قدر مشکلی که هست ، بخاطر عمل نکردنِ رویداد MouseLeave هست) .

تشکر استاد .
 

پیوست ها

  • Wpf_GetChild.rar
    3 مگایابت · بازدیدها: 1

the_king

مدیرکل انجمن
این کلاس رو توی پروژه ی کوچیک تر هم که بردم ، باز همین همین جوری هه (پروژه را در زیر ، پیوست میکنم) .
نمیدونم مشکلِ رویدادِ MouseLeave ئه Container (که در کلاس AlarmBox در متد ShowModelessInstance مقداردهی کردم) ، کجاست؟

اگه در پست قبلی که توضیحی که دادم رو ببینید ، میبینید که وقتی این برنامه ، بصورت مستقلِ از ویژال استودیو اجرا بشه ، اصلا رویدادِ MouseLeave اش کار نمیکنه .
ولی رویدادِ MouseEnter اش مشکلی نداره (اون قدر مشکلی که هست ، بخاطر عمل نکردنِ رویداد MouseLeave هست) .

تشکر استاد .
اون Container خودش Transparent ئه و رنگی نداره در نتیجه خودش ذاتا هیچ نقطه HitTest ای نداره و بر اساس Content اش ئه که MouseEnter و MouseLeave رخ میده، اگر اون MessageBox داخلش نبود نه MouseEnter رخ میداد و نه MouseLeave
حالا احتمالا اون MessageBox یک مشکل HitTest داخل خودش داره چون فرضا اگه از روی پنجره زیرین MainWindow جابجاش کنید درست میشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اون Container خودش Transparent ئه و رنگی نداره در نتیجه خودش ذاتا هیچ نقطه HitTest ای نداره و بر اساس Content اش ئه که MouseEnter و MouseLeave رخ میده، اگر اون MessageBox داخلش نبود نه MouseEnter رخ میداد و نه MouseLeave
حالا احتمالا اون MessageBox یک مشکل HitTest داخل خودش داره چون فرضا اگه از روی پنجره زیرین MainWindow جابجاش کنید درست میشه.

خیلی ممنون استاد .
بِراشِ Transparent که باشه ، دیگه مشکل hit testing نباید بوجود بیاد . قبلا این قضیه را بهش اشاره کردید . انگار فقط مقدارِ بِراشِ null هست که برای hit testing مشکل بوجود میاره .

به هر حال ، رنگ اش را هم که قبل از مقداردهیِ رویداد ، عوض کردم ، باز هم این مشکلِ رویدادِ MouseLeave ، حل نشد (درون متد ShowModelessInstance) :

C#:
            this.Container.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 0, 255, 0));
            this.Container.MouseEnter += Container_MouseEnter;
            this.Container.MouseLeave += Container_MouseLeave;
            this.Container.ShowDialog();

اما رویدادِ MouseEnter اصلا مشکلی نداره .
این قدری هم که رویدادِ MouseEnter اش کار نمیکنه ، بخاطر اینه که قبل اش ، رویدادِ MouseLeave ای به ازاش اتفاق نیفتاد .

تشکر استاد .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
بِراشِ Transparent که باشه ، دیگه مشکل hit testing نباید بوجود بیاد . قبلا این قضیه را بهش اشاره کردید . انگار فقط مقدارِ بِراشِ null هست که برای hit testing مشکل بوجود میاره .
نمی دونم در مورد چی دارید صحبت می کنید.
اولا null نیست، window.Background = Brushes.Transparent ئه. ثانیا وقتی در نقطه ای چیزی نیست بصورت عادی HitTest نداره.
AllowsTransparency برای استفاده از همین قابلیت فعال می کنند که پنجره بتونه شکل غیر مستطیلی داشته باشه. اگر در نقطه شفاف HitTest داشت که دیگه نمیشد ناحیه ای رو خالی فرض کرد.

به هر حال ، رنگ اش را هم که قبل از مقداردهیِ رویداد ، عوض کردم ، باز هم این مشکلِ رویدادِ MouseLeave ، حل نشد (درون متد ShowModelessInstance) :

C#:
            this.Container.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 0, 255, 0));
            this.Container.MouseEnter += Container_MouseEnter;
            this.Container.MouseLeave += Container_MouseLeave;
            this.Container.ShowDialog();

اما رویدادِ MouseEnter اصلا مشکلی نداره .
این قدری هم که رویدادِ MouseEnter اش کار نمیکنه ، بخاطر اینه که قبل اش ، رویدادِ MouseLeave ای به ازاش اتفاق نیفتاد .
قاعدتا تغییر رنگ کمکی نمی کنه، AllowsTransparency رو غیر فعال کنید و ببینید مشکل HitTest بر طرف میشه یا نه.
 

SajjadKhati

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


قاعدتا تغییر رنگ کمکی نمی کنه، AllowsTransparency رو غیر فعال کنید و ببینید مشکل HitTest بر طرف میشه یا نه.

خیلی ممنون استاد .
نه ، فرقی نکرد :

C#:
            this.Container.AllowsTransparency = false;
            this.Container.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 0, 255, 0));
            this.Container.MouseEnter += Container_MouseEnter;
            this.Container.MouseLeave += Container_MouseLeave;
            this.Container.ShowDialog();
 

SajjadKhati

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

C#:
            this.Container.AllowsTransparency = false;
            this.Container.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 0, 255, 0));
            this.Container.MouseEnter += Container_MouseEnter;
            this.Container.MouseLeave += Container_MouseLeave;
            this.Container.ShowDialog();

استاد ، تازه متوجه شدم . وقتی از درون ویندوزی (مثلا توی ویندوزِ 1 هستیم) ، ویندوزِ دیگه ای (مثلا ویندوزِ 2) را ShowDialog کنیم ، باعث میشه رخدادِ MouseLeave ئه اون ویندوزِ 2 ، کار نکنه .
اما اگه از متد Show (بجای متد ShowDialog) استفاده کنیم ، این مشکل وجود نداره .

توی WinForm همچین چیزی را تست کردم ، این مشکل وجود نداره .

پس چرا توی wpf این مشکل وجود داره؟
چرا این طوره و آیا روشی برای حل این مشکل وجود داره؟
تشکر استاد .
 

the_king

مدیرکل انجمن
استاد ، تازه متوجه شدم . وقتی از درون ویندوزی (مثلا توی ویندوزِ 1 هستیم) ، ویندوزِ دیگه ای (مثلا ویندوزِ 2) را ShowDialog کنیم ، باعث میشه رخدادِ MouseLeave ئه اون ویندوزِ 2 ، کار نکنه .
اما اگه از متد Show (بجای متد ShowDialog) استفاده کنیم ، این مشکل وجود نداره .

توی WinForm همچین چیزی را تست کردم ، این مشکل وجود نداره .

پس چرا توی wpf این مشکل وجود داره؟
چرا این طوره و آیا روشی برای حل این مشکل وجود داره؟
مشکلی وجود نداره، تفاوتی هم در این مورد بین WPF و Windows Forms نیست. مساله خیلی واضح ئه.
شما یک نخ دارید که به رخداد های پنجره ای رسیدگی می کنه و فرضا سه تا دکمه دارید که موقع کلیک روی یکی اش MessageBox.Show فراخوانی میشه و برای دومی Thread.Sleep(10000) و برای سومی Background = Brushes.Red (یا BackColor = Color.Red)
وقتی روی دکمه اول یا دوم کلیک کنید و متدی فراخوانی بشه، اون نخ رو مشغول اجرای متد میکنه، زمانی نخ میتونه به سایر رخداد ها رسیدگی کنه که اون متد رو خاتمه بدهید.
وقتی به واسطه MessageBox.Show یا Thread.Sleep اون نخ رو در اجرای متد اول یا دوم معطل نگه می دارید و نمیتونه از متد اون رخداد خارج بشه میتونه به رخداد کلیک دکمه سوم بپردازه؟
C#:
        public Form1()
        {
            InitializeComponent();
            MouseEnter += (sender, e) =>
            {               
                BackColor = Color.LightBlue;
                Text = "MouseEnter";
            };
            MouseLeave += (sender, e) =>
            {
                BackColor = Color.LightGray;
                Text = "MouseLeave";
            };
        }

        private void button1_Click(object sender, EventArgs e)
        {
            using (var f = new Form1())
            {
                f.ShowDialog();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            var f = new Form1();
            f.Show();
        }
    }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
مشکلی وجود نداره، تفاوتی هم در این مورد بین WPF و Windows Forms نیست. مساله خیلی واضح ئه.
شما یک نخ دارید که به رخداد های پنجره ای رسیدگی می کنه و فرضا سه تا دکمه دارید که موقع کلیک روی یکی اش MessageBox.Show فراخوانی میشه و برای دومی Thread.Sleep(10000) و برای سومی Background = Brushes.Red (یا BackColor = Color.Red)
وقتی روی دکمه اول یا دوم کلیک کنید و متدی فراخوانی بشه، اون نخ رو مشغول اجرای متد میکنه، زمانی نخ میتونه به سایر رخداد ها رسیدگی کنه که اون متد رو خاتمه بدهید.
وقتی به واسطه MessageBox.Show یا Thread.Sleep اون نخ رو در اجرای متد اول یا دوم معطل نگه می دارید و نمیتونه از متد اون رخداد خارج بشه میتونه به رخداد کلیک دکمه سوم بپردازه؟
C#:
        public Form1()
        {
            InitializeComponent();
            MouseEnter += (sender, e) =>
            {          
                BackColor = Color.LightBlue;
                Text = "MouseEnter";
            };
            MouseLeave += (sender, e) =>
            {
                BackColor = Color.LightGray;
                Text = "MouseLeave";
            };
        }

        private void button1_Click(object sender, EventArgs e)
        {
            using (var f = new Form1())
            {
                f.ShowDialog();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            var f = new Form1();
            f.Show();
        }
    }

خیلی ممنون استاد . :rose:
اینو قضیه ی نخ و اجرا نشدنِ رویداد یا هر کدی در صورتِ توقفِ نخ را میدونم . ممنون که یادآوری کردید .

جواب این رو هم انگار همین الان متوجه شدم . دلیلش اینه که چون پروپرتی WindowStyle ئه اون Window را مقدار None گذاشتم و اما WindowChrome ای برای اون ، تعریف نکردم .

اون Xceed.Wpf.ToolKit.MessageBox هم که این جوری واسش میشد ، احتمال داره که همین قضیه برای ویندوزش بوده باشه .

البته ، مقدارِ پروپرتیِ ResizeBorderThickness ئه WindowChrome را هم که کم بذاریم ، یه کم باعث میشه اگه سرعت خروج موس از ویندوز خیلی بالا باشه ، احتمال رصد و اجرای رخداد ، کمتر بشه .

تشکر استاد :rose:
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
استاد ، راستی به این چیز ، تازه توجه کردم .
اینکه وقتی که یه پنجره ای در wpf (منظورم در بخش کدهای #C هست) میسازید که از کلاس Window ارث بری میکنه . مثلا کلاسی به نام MainWindow که از کلاس Window ارث بری میکنه .
اما در کدهای xaml ، دیگه نوعِ اون پنجره را ، نوعِ MainWindow نمیگیره . بلکه از نوعِ Window میگیره .
با اون حال ، در کدهای xaml ، هر پروپرتی ای (حداقل private نباشه و حداقل اینکه DependencyProperty باشه) که در MainWindow تعریف کنیم را میشناسه .

سئوالی که اینجا مطرح میشه اینه که اصلا چرا مثل کدهای سی شارپ ، در کدهای xaml ، وقتی میخواد از MainWindow استفاده بشه ، نوعش را از همین MainWindow نمیگیره و از نوعِ والدش که Window باشه ، میگیره؟

دوم اینکه بخاطر عضوِ x:Class هست (حالا نمیدونم این عضو ، فیلد هه ، پروپرتی هه ، چیه) که باعث میشه ویندوزِ مورد نظرمون را بشناسه و با اونکه در کد xaml ، نوع مون را از نوعِ Window تعریف کردیم ، پروپرتی های MainWindow را هم بشناسه . درسته؟

تشکر استاد .
 

the_king

مدیرکل انجمن
سلام
استاد ، راستی به این چیز ، تازه توجه کردم .
اینکه وقتی که یه پنجره ای در wpf (منظورم در بخش کدهای #C هست) میسازید که از کلاس Window ارث بری میکنه . مثلا کلاسی به نام MainWindow که از کلاس Window ارث بری میکنه .
اما در کدهای xaml ، دیگه نوعِ اون پنجره را ، نوعِ MainWindow نمیگیره . بلکه از نوعِ Window میگیره .
با اون حال ، در کدهای xaml ، هر پروپرتی ای (حداقل private نباشه و حداقل اینکه DependencyProperty باشه) که در MainWindow تعریف کنیم را میشناسه .

سئوالی که اینجا مطرح میشه اینه که اصلا چرا مثل کدهای سی شارپ ، در کدهای xaml ، وقتی میخواد از MainWindow استفاده بشه ، نوعش را از همین MainWindow نمیگیره و از نوعِ والدش که Window باشه ، میگیره؟
در WPF کلاسی به نام MainWindow وجود نداره، MainWindow یک کلاس سفارشی مشابه Form1 ئه که در پروژه شما ساخته میشه و برای ساختنش از Window به عنوان base اش استفاده میشه. همانطور که وقتی UserControl1 رو می سازید از UserControl به عنوان base اش استفاده می کنید.

دوم اینکه بخاطر عضوِ x:Class هست (حالا نمیدونم این عضو ، فیلد هه ، پروپرتی هه ، چیه) که باعث میشه ویندوزِ مورد نظرمون را بشناسه و با اونکه در کد xaml ، نوع مون را از نوعِ Window تعریف کردیم ، پروپرتی های MainWindow را هم بشناسه . درسته؟
بله. نه فیلد ئه و نه پروپرتی، Directive ئه، با کلاس XamlDirective در ارتباط ئه.
المنتی که توصیف می شه معمولا نوع داده شیء ئه، معمولا، نه الزاما، همه اینها در XAML overview توضیح داده شده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
در WPF کلاسی به نام MainWindow وجود نداره، MainWindow یک کلاس سفارشی مشابه Form1 ئه که در پروژه شما ساخته میشه و برای ساختنش از Window به عنوان base اش استفاده میشه. همانطور که وقتی UserControl1 رو می سازید از UserControl به عنوان base اش استفاده می کنید.

سلامی مجدد
خیلی ممنون استاد .
بله ، میدونم .
منظورم اینه که چرا مثل Form1 در ویندوز فرم ، در wpf (در کدهای xaml) اش ، اون کلاسِ سفارشی سازی شده (که مثلا نامش MainWindow که از کلاس Window ارث بری میکنه) را فراخونی نمیکنه و بجاش کلاس Window را فراخونی میکنه؟


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


استاد ، یه کلاسی بنام AlarmWindow دارم میسازم (که شبیه MessageBox ئه Xceed هست اما از اون ارث بری نمیکنه و کلا خودم دارم میسازم) .
اون MessageBox ئه Xceed ، یه DependencyProperty برای تغییرِ استایلِ بعضی از کنترل هاش مثل کنترل های دکمه های cancel و ok و ... در نظر گرفت (که مثلا برای دکمه ی cancel ، نام اون پروپرتی اش CancelButtonStyle هست) .

من هم میخوام همین کار را کنم . مثلا یه کنترلِ Label دارم که میخوام برای اون ، یه پروپرتی ای از نوعِ استایل در نظر بگیرم (با نامِ AlarmTextStyle) تا کاربر بتونه به اون لیبل ، استایلِ مورد نظرش را بده .
خوب میدونید که وقتی پروپرتی های یه کنترلی را صریحا مقداردهی کنیم ، دیگه همون پروپرتی هایی از اون کنترل را که در استایلِ اون کنترل مقداردهی کنیم ، اِعمال نمیشه و نادیده گرفته میشه .

حالا توی اون Label ام ، یه content از نوعِ textblock داره که میخوام مقدارش را از پارامترِ متدِ استاتیکِ Show بگیرم و در Text ئه TextBlock بریزم اما میخوام در عین حال ، اگه در پروپرتیِ AlarmTextStyle (که از نوعِ Style ای برای Label هست) ، مقدار و نوعِ Content (ئه استایلِ AlarmTextStyle) را از نوعِ دیگه ای تعیین کرد ، الویت با اون نوع باشه .

و از اون جایی که این دو روند و استراتژی با هم مخالفن (چون وقتی پروپرتی ای صریح مقداردهی بشه ، دیگه مقادیری که در Style بهش داده شد ، کار نمیکنه) ، به نظرتون اولا اصلا این کار (و این قابلیتی که میخوام بهشون بدم) لازمه؟
و دوما اگه آره ، برای رفعِ این مشکل ، بجای اینکه content ئه label را صریحا مشخص کنم ، باید بصورتِ style مشخص کنم؟
و بعد هم مقدارِ content اش که از نوعِ textblock ریختم و قراره Text ئه textblock را از کاربر در متد استاتیکِ Show بگیرم ، حالا این مقدار را توی پروپرتیِ Text ئه TextBlock در Content ئه AlarmTextStyle بریزم؟

تشکر استاد :rose:
 

the_king

مدیرکل انجمن
منظورم اینه که چرا مثل Form1 در ویندوز فرم ، در wpf (در کدهای xaml) اش ، اون کلاسِ سفارشی سازی شده (که مثلا نامش MainWindow که از کلاس Window ارث بری میکنه) را فراخونی نمیکنه و بجاش کلاس Window را فراخونی میکنه؟
قیاس مع الفارق می کنید، متناظر xaml در Form1 هست که میگید مثل Form1؟
چیزی شبیه به xaml در Windows Forms نیست که با اون مقایسه کنید.
در xaml کلاسی فراخوانی نمی شه، در xaml چیزی اجرا نمیشه که فراخوانی شدنی وجود داشته باشه. xaml داره چیزی رو توصیف می کنه، مثلا MainWindow رو. و برای توصیف هم چیزی رو مبنا و پایه قرار میده، مثلا یک Window. میگه این توصیف بر پایه یک Window ئه. برای توصیف اون چیز هم نمیشه مبنا خودش باشه، چون خودش که هنوز توصیف نشده که مبنای توصیف خودش باشه.

استاد ، یه کلاسی بنام AlarmWindow دارم میسازم (که شبیه MessageBox ئه Xceed هست اما از اون ارث بری نمیکنه و کلا خودم دارم میسازم) .
اون MessageBox ئه Xceed ، یه DependencyProperty برای تغییرِ استایلِ بعضی از کنترل هاش مثل کنترل های دکمه های cancel و ok و ... در نظر گرفت (که مثلا برای دکمه ی cancel ، نام اون پروپرتی اش CancelButtonStyle هست) .

من هم میخوام همین کار را کنم . مثلا یه کنترلِ Label دارم که میخوام برای اون ، یه پروپرتی ای از نوعِ استایل در نظر بگیرم (با نامِ AlarmTextStyle) تا کاربر بتونه به اون لیبل ، استایلِ مورد نظرش را بده .
خوب میدونید که وقتی پروپرتی های یه کنترلی را صریحا مقداردهی کنیم ، دیگه همون پروپرتی هایی از اون کنترل را که در استایلِ اون کنترل مقداردهی کنیم ، اِعمال نمیشه و نادیده گرفته میشه .

حالا توی اون Label ام ، یه content از نوعِ textblock داره که میخوام مقدارش را از پارامترِ متدِ استاتیکِ Show بگیرم و در Text ئه TextBlock بریزم اما میخوام در عین حال ، اگه در پروپرتیِ AlarmTextStyle (که از نوعِ Style ای برای Label هست) ، مقدار و نوعِ Content (ئه استایلِ AlarmTextStyle) را از نوعِ دیگه ای تعیین کرد ، الویت با اون نوع باشه .

و از اون جایی که این دو روند و استراتژی با هم مخالفن (چون وقتی پروپرتی ای صریح مقداردهی بشه ، دیگه مقادیری که در Style بهش داده شد ، کار نمیکنه) ، به نظرتون اولا اصلا این کار (و این قابلیتی که میخوام بهشون بدم) لازمه؟

و دوما اگه آره ، برای رفعِ این مشکل ، بجای اینکه content ئه label را صریحا مشخص کنم ، باید بصورتِ style مشخص کنم؟
و بعد هم مقدارِ content اش که از نوعِ textblock ریختم و قراره Text ئه textblock را از کاربر در متد استاتیکِ Show بگیرم ، حالا این مقدار را توی پروپرتیِ Text ئه TextBlock در Content ئه AlarmTextStyle بریزم؟
لزومش رو خودتون تشخیص می دهید. هم می توانید متد Show ای ایجاد کنید که مقداری برای Text اون Label در نظر نگیره تا کاربری که سفارشی سازی بیشتری میخواد از متدی که Text تعیین می کنه استفاده نکنه و هم می توانید موقع مقدار دهی Text برای Label اول وضعیت AlarmTextStyle رو بررسی کنید و مقدار دهی رو شرطی کنید، نه حتمی.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد .
استاد ، این کلاس AlarmWindow ای که تا اینجا نوشتم را براتون توی این پست پیوست میکنم (همین حالا پیوست کنم تا یادم نرفت :green: ) .

حالا وقتی از یه جای دیگه ، همچین کدی را از این AlarmWindow استفاده میکنم :

C#:
            Style alarmWindowStyle = new Style(typeof(AlarmWindow));
            Style mainContentLabelStyle = new Style(typeof(Label));
            Setter setterL1 = new Setter(Label.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 0, 255, 0)));
            mainContentLabelStyle.Setters.Add(setterL1);
            Setter setterAW1 = new Setter(AlarmWindow.AlarmMainContentStyleProperty, mainContentLabelStyle);
            alarmWindowStyle.Setters.Add(setterAW1);

            string messageText = "سلام . خوبی؟";
            string captionText = "هشدار";
            CustomMessageBoxButton messageBoxButton = CustomMessageBoxButton.None;
            
            AlarmWindow.Show(this, messageText, captionText, messageBoxButton, MessageBoxResult.None, null, null, alarmWindowStyle);

وقتی زمانی که استایل های خط بالا یعنی alarmWindowStyle و خطوطِ پایین تر اش اجرا میشه ، بریک پوینت که میذارم ، اصلا بدنه ی set در پروپرتیِ AlarmMainContentStyle اجرا نمیشه . (پروپرتیِ AlarmMainContentStyle ، درون همین فایل AlarmWindow.xaml.cs که در این پست پیوست کردم وجود داره) .

چرا بدنه ی این پروپرتی اجرا نمیشه؟

شبیه همین کار را Xceed.MessageBox کرد و با دریافتِ استایل برای MessageBox اش ، میشد استایلی که برای دکمه ها به عنوان پروپرتی هایی درون همون کلاس تعبیه کرد را مقداردهی کرد .
تشکر استاد .
 

پیوست ها

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد .
استاد ، این کلاس AlarmWindow ای که تا اینجا نوشتم را براتون توی این پست پیوست میکنم (همین حالا پیوست کنم تا یادم نرفت :green: ) .

حالا وقتی از یه جای دیگه ، همچین کدی را از این AlarmWindow استفاده میکنم :

C#:
            Style alarmWindowStyle = new Style(typeof(AlarmWindow));
            Style mainContentLabelStyle = new Style(typeof(Label));
            Setter setterL1 = new Setter(Label.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 0, 255, 0)));
            mainContentLabelStyle.Setters.Add(setterL1);
            Setter setterAW1 = new Setter(AlarmWindow.AlarmMainContentStyleProperty, mainContentLabelStyle);
            alarmWindowStyle.Setters.Add(setterAW1);

            string messageText = "سلام . خوبی؟";
            string captionText = "هشدار";
            CustomMessageBoxButton messageBoxButton = CustomMessageBoxButton.None;
          
            AlarmWindow.Show(this, messageText, captionText, messageBoxButton, MessageBoxResult.None, null, null, alarmWindowStyle);

وقتی زمانی که استایل های خط بالا یعنی alarmWindowStyle و خطوطِ پایین تر اش اجرا میشه ، بریک پوینت که میذارم ، اصلا بدنه ی set در پروپرتیِ AlarmMainContentStyle اجرا نمیشه . (پروپرتیِ AlarmMainContentStyle ، درون همین فایل AlarmWindow.xaml.cs که در این پست پیوست کردم وجود داره) .

چرا بدنه ی این پروپرتی اجرا نمیشه؟

شبیه همین کار را Xceed.MessageBox کرد و با دریافتِ استایل برای MessageBox اش ، میشد استایلی که برای دکمه ها به عنوان پروپرتی هایی درون همون کلاس تعبیه کرد را مقداردهی کرد .
تشکر استاد .

سلامی مجدد
استاد ، اگه با تعریف Style ئه جدید (مثل همون پروپرتیِ AlarmMainContentStyle در کلاس AlarmWindow) ، وقتی که این پروپرتی را در قالبِ Style ئه AlarmWindow مقداردهی میکنیم (یعنی پروپرتیِ AlarmMainContentStyle را توسطِ پروپرتیِ AlarmWindow.Style مقداردهی میکنیم مثل شیش خط اول در کد پست قبلی) ، با این روشِ مقداردهی ، قرار نباشه که بدنه ی پروپرتیِ AlarmMainContentStyle اجرا بشه ، پس چجوری باید کدهای درون پروپرتی را اجرا کنیم؟

یعنی من وقتی میخوام پروپرتیِ AlarmMainContentStyle مقداری گرفت ، به پروپرتیِ this.AlarmMainContentLabel.Style در اون صورت همون مقدار را بده ، باید چی کار کنم؟

خودِ Xceed.MessageBox چه کاری کرد؟ من گشتم ولی دقیق متوجه نشدم چی کار کرد . درون بخشِ set ئه پروپرتی های استایل اش ، کدی جز سِت کردن در DependencyProperty ننوشت . پس کدهای مورد نظرش برای سِت شدن استایل برای کنترل مورد نظرش ، کجان؟
مثلا کدهای مربوط به پروپرتیِ YesButtonStyle (در Xceed.MessageBox) ، کجاست تا وقتی برنامه نویس ، استایلی که به این پروپرتی میده را روی دکمه ی OK اِعمال کنه؟


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


یه چیز دیگه اینکه وقتی در AlarmWindow (فایل در پست قبلی که پیوست کردم) ، پروپرتیِ Background ای که در AlarmWindow را مشخص کردم ، برمیدارم و در استایل ، این پروپرتی را مقداردهی میکنم ، درست کار میکنه (بجای شیش خطِ اول در پست قبلی ، اینها را میذارم) :

C#:
            Style alarmWindowStyle = new Style(typeof(AlarmWindow));
            Style mainContentLabelStyle = new Style(typeof(Label));
            Setter setterL1 = new Setter(Label.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 0, 255, 0)));
            mainContentLabelStyle.Setters.Add(setterL1);
            Setter setterAW1 = new Setter(AlarmWindow.AlarmMainContentStyleProperty, mainContentLabelStyle);
            Setter setterAW_2 = new Setter(AlarmWindow.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 0, 255, 0)));
            alarmWindowStyle.Setters.Add(setterAW1);
            alarmWindowStyle.Setters.Add(setterAW_2);

که تا اینجا مشکلی نیست .
اما وقتی پروپرتیِ Width را در استایل مشخص میکنم ، کار نمیکنه و Width ئه AlarmWindow تغییری نمیکنه . با اونکه در AlarmWindow ، پروپرتیِ Width مقداردهی نشد :

C#:
            Style alarmWindowStyle = new Style(typeof(AlarmWindow));
            Style mainContentLabelStyle = new Style(typeof(Label));
            Setter setterL1 = new Setter(Label.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 0, 255, 0)));
            mainContentLabelStyle.Setters.Add(setterL1);
            Setter setterAW1 = new Setter(AlarmWindow.AlarmMainContentStyleProperty, mainContentLabelStyle);
            Setter setterAW_2 = new Setter(AlarmWindow.WidthProperty, 500d);
            alarmWindowStyle.Setters.Add(setterAW1);
            alarmWindowStyle.Setters.Add(setterAW_2);

چرا پروپرتیِ Width کار نمیکنه؟

تشکر استاد
 
آخرین ویرایش:

SajjadKhati

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

اینکه من الان بخوام در window ای که سفارشی کردم (مثل همین AlarmWindow) و شامل چند تا کنترل هست ، اگه بخوام یه پروپرتی ای از نوع Style در نظر بگیرم که وقتی کاربر بهش مقدار میده ، این مقدارِ از نوعِ Style اش ، به عنوانِ Style ئه یه کنترلِ خاصی در اون AlarmWindow سِت بشه (مثلا مقدارِ این Style را برای Style ئه کنترلِ Button در AlarmWindow تنظیم کنم) ، در این صورت باید چی کار کنم؟

(با توجه به مشکلی که در پست های قبلی بیان کردم که وقتی Style ئه اون AlarmWindow را مقدار میدیم و در این استایلِ AlarmWindow ، به این پروپرتی ای از نوعِ Style که در خط بالا اشاره کردم مقدار میدیم ، اکسسور و بخشِ set در اون پروپرتی ، اجرا نمیشه) .

یا یه لینکی در این باره میدین؟
من چیز خاصی پیدا نکردم در این باره .

تشکر استاد .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
استاد ، این کلاس AlarmWindow ای که تا اینجا نوشتم را براتون توی این پست پیوست میکنم (همین حالا پیوست کنم تا یادم نرفت :green: ) .

حالا وقتی از یه جای دیگه ، همچین کدی را از این AlarmWindow استفاده میکنم :

C#:
            Style alarmWindowStyle = new Style(typeof(AlarmWindow));
            Style mainContentLabelStyle = new Style(typeof(Label));
            Setter setterL1 = new Setter(Label.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 0, 255, 0)));
            mainContentLabelStyle.Setters.Add(setterL1);
            Setter setterAW1 = new Setter(AlarmWindow.AlarmMainContentStyleProperty, mainContentLabelStyle);
            alarmWindowStyle.Setters.Add(setterAW1);

            string messageText = "سلام . خوبی؟";
            string captionText = "هشدار";
            CustomMessageBoxButton messageBoxButton = CustomMessageBoxButton.None;
           
            AlarmWindow.Show(this, messageText, captionText, messageBoxButton, MessageBoxResult.None, null, null, alarmWindowStyle);

وقتی زمانی که استایل های خط بالا یعنی alarmWindowStyle و خطوطِ پایین تر اش اجرا میشه ، بریک پوینت که میذارم ، اصلا بدنه ی set در پروپرتیِ AlarmMainContentStyle اجرا نمیشه . (پروپرتیِ AlarmMainContentStyle ، درون همین فایل AlarmWindow.xaml.cs که در این پست پیوست کردم وجود داره) .

چرا بدنه ی این پروپرتی اجرا نمیشه؟

شبیه همین کار را Xceed.MessageBox کرد و با دریافتِ استایل برای MessageBox اش ، میشد استایلی که برای دکمه ها به عنوان پروپرتی هایی درون همون کلاس تعبیه کرد را مقداردهی کرد .
تشکر استاد .
همیشه به یاد داشته باشید که هر وقت به مشکلی برخوردید اول صورت مساله رو ساده کنید، وقتی صورت مساله رو ساده کنید پیدا کردن راه حلش ساده تر میشه. پیدا کردن اشکال در یک کد کوچیک و خلاصه شده خیلی ساده تر از کدی است که یه عالمه بخش نامرتبط به مشکل داره.
اول مثال خود Custom Dependency Property رو در سایت مایکروسافت ببینید.
مشخصه ها رو نوشته اید تا مقدار DependencyProperty ئه رو تغییر بده یا مقدارش رو بخونه، نه اینکه وقتی DependencyProperty تغییر کرد بره set مشخصه رو اجرا کنه. Setter برای تغییر مقدار DependencyProperty طراحی شده، کاری به مشخصه نداره.
و ایراد کار اینجا است که DependencyProperty تون callback نداره، وقتی مقدار DependencyProperty تغییر کرد اتفاقی نمی افته.
ببینید این مثال ساده چقدر راحت مشکل رو نشون میده :
C#:
    public class MyWindow : Window
    {
        public static readonly DependencyProperty MyBackgroundProperty
            = DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyWindow));

        public Brush MyBackground
        {
            get => (Brush)GetValue(MyBackgroundProperty);
            set
            {
                SetValue(MyBackgroundProperty, value);
                Background = value;
            }
        }
    }
C#:
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var style = new Style(typeof(MyWindow));
            var setter = new Setter(MyWindow.MyBackgroundProperty, Brushes.Red);
            style.Setters.Add(setter);
            var w = new MyWindow() { Width = 300, Height = 200 };
            w.Style = style;
            w.ShowDialog();
        }
این مشکل با callback حل میشه :
C#:
    public class MyWindow : Window
    {
        public static readonly DependencyProperty MyBackgroundProperty
            = DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyWindow), new PropertyMetadata(OnMyBackgroundChanged));

        private static void OnMyBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((MyWindow)d).Background = (Brush)e.NewValue;
        }

        public Brush MyBackground
        {
            get => (Brush)GetValue(MyBackgroundProperty);
            set => SetValue(MyBackgroundProperty, value);
        }
    }
دقت کنید که تغییر دادن ;w.MyBackground = Brushes.Yellow هم منجر به اجرای متد OnMyBackgroundChanged میشه، برای همین در set فقط SetValue لازمه و کد دیگری نداره، تغییر دادن مقدار Background فقط در OnMyBackgroundChanged انجام میشه.
 

the_king

مدیرکل انجمن
اما وقتی پروپرتیِ Width را در استایل مشخص میکنم ، کار نمیکنه و Width ئه AlarmWindow تغییری نمیکنه . با اونکه در AlarmWindow ، پروپرتیِ Width مقداردهی نشد :

C#:
            Style alarmWindowStyle = new Style(typeof(AlarmWindow));
            Style mainContentLabelStyle = new Style(typeof(Label));
            Setter setterL1 = new Setter(Label.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 0, 255, 0)));
            mainContentLabelStyle.Setters.Add(setterL1);
            Setter setterAW1 = new Setter(AlarmWindow.AlarmMainContentStyleProperty, mainContentLabelStyle);
            Setter setterAW_2 = new Setter(AlarmWindow.WidthProperty, 500d);
            alarmWindowStyle.Setters.Add(setterAW1);
            alarmWindowStyle.Setters.Add(setterAW_2);

چرا پروپرتیِ Width کار نمیکنه؟
باید کدتون رو بررسی کنید و ببینید با چی تداخل داره چون مشکلی در WidthProperty نیست. من نمیتونم کد ناقص شما رو اجرا کنم، خودتون باید در پروژه بررسی اش کنید. اما میتونم در مثال ساده خودم ببینم که WidthProperty مشکلی نداره :
C#:
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var style = new Style(typeof(MyWindow));
            var setter = new Setter(MyWindow.MyBackgroundProperty, Brushes.Red);
            style.Setters.Add(setter);
            var w = new MyWindow() { Height = 200 };
            var setter2 = new Setter(MyWindow.WidthProperty, 200d);
            style.Setters.Add(setter2);
            w.Style = style;
            w.MyBackground = Brushes.Yellow;
            w.ShowDialog();
        }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خوندن تون با نخوندن تون چندان فرقی نداشت، چون صریحا در نتیجه گیری اش هم گفته نمایشگر 96ppi پنجره WPF رو در همون same size نمایشگر 192ppi نمایش داد.

سلامی مجدد استاد .
استاد ، میگم اینجا که گفتید که گفت :

In conclusion, we’ve seen that WPF really is resolution independent as long as Windows display properties scale factor settings are properly taken into account. What WPF Resolution Independence really means that two monitors set to their native resolution and which are accurately reporting their DPI settings to WPF will display the same WPF window at the exact same size. Under those conditions a monitor with 96 physical pixels per inch will display any WPF window at the same size as a monitor which has 192 physical pixels per inch.

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

پنجره های wpf ، فقط زمانی در مانیتورهای مختلف ، اندازه ی برابری دارند (یعنی نسبت به اینچ با هم برابرند نه در مقیاسِ پیکسل) که در هر مانیتور ، هم اینکه روی ریزولیشنِ پیش فرضِ اون مانیتور تنظیم شده باشه (یعنی اون ریزولیشن ای که مثلا در ویندوز 10 مینویسه Recomended یا در واقع ، اون مانیتور ، به همون تعداد ، پیکسل های فیزیکی داره) و هم اینکه dpi ئه هر مانیتور هم روی حالتِ پیش فرضش تنظیم شده باشه (البته نمیدونم در ویندوز 10 ، تنظیمِ بخشِ scale & layout ، همون تنظیمِ dpi ای هست ک در نسخه های قبلی ویندوز مثل xp و اینها بود یا نه . و اگه همین هه ، پس یعنی مثلا در هر مانیتور ، در بخشِ scale & layout در ویندوز 10 ، مقدارش روی 100 که Recomended هست باشه) .

در این صورت ، یعنی در صورت تنظیم ریزولیشن و dpi ده هر مانیتور به پیش فرض شون ، پنجره های wpf در اون مانیتورها ، یک اندازه نمایش داده میشن (یعنی همه شون نسبت به اینچ ، در یک اینچِ واحد و یکسانی نشون داده میشن) (یعنی دیگه نسبی نیست . یعنی درصدی نیست که در مانیتورِ 1 که 2 برابرِ مانیتورِ 2 بود (و هر دو مانیتور یک ریزولیشن را داشتن) ، پس در مانیتور مانیتور 2 که میخواد نمایش بده ، نصفِ مانیتور 1 نمایش بده که همون) .

این درکی که از مطلب بالا دارم ، درسته؟
مفهومش همینه؟

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

و البته هم همون اول در ابتدای این مقاله گفت که مستقل از ریزولیشن بودنِ wpf به این معنا نیست که مثلا ما ریزولیشن مانیتورمون یا dpi ئه مانیتورمون را که تغییر بدیم ، اندازه ی پنجره ی wpf مون تغییر نکنه (بلکه تغییر میکنه) و همچنین ردِ بقیه ی موارد هم گفت .

تشکر استاد :rose:
 

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

بالا