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

the_king

مدیرکل انجمن
البته من هنوز این قضیه را پیاده سازی نکردم (که استفاده از پروپرتی را برای ImageSource پیاده سازی کرده باشم یا نه) . فعلا میخوام روش استفاده را برم .
الان توی روش Converter برای Binding ، اگه بتونم شناسه ای را در متد Convert دریافت کنم ، روش Converter انگار خیلی به صرفه تر میشه .
آیا میشه توی متد Convert ، شناسه ای از اون شیِ Binding یا خود شیِ Binding را بدست آورد؟
به صرفه معنی نمیده چون این روش ها هیچکدوم هزینه نداره، ده کلاس بشه صد کلاس هم یک ریال هزینه بیشتر نداره. فقط خودتون دارید برای متد و کلاس سازی هزینه فرضی در نظر می گیرید، واقعی نیست. یک چیزی مثل ساختن کلاس رو در ذهن تون هزینه بر در نظر گرفته اید که میخواهید تعدادش کمتر بشه، وگرنه هر کلاس 0 ریال هزینه داره.
پارامتر های متد IValueConverter.Convert رو ببینید، کاری با Binding ئه نداره، چیزی در مورد شیء Binding نمیدونه، اما یک پارامتر parameter داره که مقدارش رو Binding میده. یعنی اگر در Binding.ConverterParameter مقدار تعیین کننده ای قرار بگیره اون رو پارامتر parameter دریافت می کنه تا بتونه بر اساسش کار متفاوتی بکنه. پس اگر می خواهید Converter مورد تعیین کننده ای در مورد Binding بدونه باید در ConverterParameter اون Binding مشخص اش کنید.
استاد اگه ناراحت نمیشین ، یه نقد کوچیک کنم . قبل تر ، یه کم صبرتون بیشتر از حالا بود . :green:
مثلا چند باری بود که قبلا روش خودم را رفته بودم ، باز نهایتا برگشتم به حرف شما . هر چند ضرر کرده بودم اما اون باعث شد تجربه ی شخصی ام بیشتر بشه . که اونها کسب تجربه ای برام شد .
شما باید هر روشی رو تجربه کنید، چه موفق باشه و چه نباشه. چون هر کاری بکنید ازش یک چیزی رو بهتر یاد می گیرید، هیچوقت ضرر نمی کنید.
برای همین هم هیچوقت نخواستم جلوی تجربه کردن شما رو بگیرم، کلمه تجربه رو در انجمن برنامه نویسی بیش از چهل بار نوشتم چون خیلی مهم ئه، می توانید جستجو کنید و ببینید. اما چیزی که میگم ربطی به صبر من نداره، اگر بخواهید از کسی مشورت بگیرید باید اجازه بدهید که از کار تون انتقاد کنه، انتقاد از شما نیست که بخواهید دفاع کنید، انتقاد از کار شما است. کسی که ازش راهنمایی می خواهید که نمیخواد از شما امتیاز کم کنه یا تلاش تون رو زیر سوال ببره که بخواهید از کار تون دفاع کنید، خودش شخصا هم همچین تصمیمی نگرفته بوده که تمایلی برای شنیدن انتقاد نداشته باشید، خودتون درخواست راهنمایی کرده اید. من هیچوقت نمیگم فلانی کد ات رو بیار بررسی کنم و بهت امتیاز بدم. وقتی شما برای روش مناسب از من سوال می کنید باید آمادگی انتقاد از روش قبلی تون رو داشته باشید، اگر بخواهید از کاری که کردید دفاع کنید که دیگه نظر مخالف اش بی فایده است.

همیشه می توانید تصور کنید که کاری که می کنید ایرادی نداره، اما اگر بخواهید واکنش تون به مشورت کسی همچین پاسخی باشه دیگه کسی بهتون پیشنهادی نمی کنه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد .
شناسه ی Binding در ConverterParameter را نام ای اختصاصی (با رعایت قانون خاص برای هر نام برای Binding) در نظر گرفتم .
اگه نیاز به پارامترهای دیگه ای جز نام برای Convert بود ، آرایه ای از object ها را براش میفرستم که عضو اولش ، همین رشته ای که نام اختصاصی داره باشه و عضوهای بعدیِ آرایه ، بقیه ی پارامترهای مورد نیاز .

استاد ، بهترین مکان برای قرارگیریِ این کلاس Convert ، لایه ی ViewModel هست؟
چون اولا برای کل پروژه و هر Binding ای که در View انجام میشه ، فقط میخوام از یک کلاس و یک شیِ واحد از همین کلاسِ Convert استفاده کنم .

و دوما ، یکطرفِ Binding که لایه ی View هست (همون Binding Target Property) و یک طرف دیگه که ممکنه هر لایه ای اعم از View و Model و حتی ViewModel به عنوان Binding Source Property باشه .
فرضا اگه Binding Source Property مون در لایه ی Model باشه و لازم بشه که مقدارش را به نوعِ مورد نظر در View تبدیل کنیم ، بهترین مکانی که به هر دو اطلاعات از لایه ها بشه دسترسی داشت و MVVM را نقض نکنه ، لایه ی ViewModel هست .
درست میگم؟

تشکر .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
شناسه ی Binding در ConverterParameter را نام ای اختصاصی (با رعایت قانون خاص برای هر نام برای Binding) در نظر گرفتم .
اگه نیاز به پارامترهای دیگه ای جز نام برای Convert بود ، آرایه ای از object ها را براش میفرستم که عضو اولش ، همین رشته ای که نام اختصاصی داره باشه و عضوهای بعدیِ آرایه ، بقیه ی پارامترهای مورد نیاز .

استاد ، بهترین مکان برای قرارگیریِ این کلاس Convert ، لایه ی ViewModel هست؟
چون اولا برای کل پروژه و هر Binding ای که در View انجام میشه ، فقط میخوام از یک کلاس و یک شیِ واحد از همین کلاسِ Convert استفاده کنم .

و دوما ، یکطرفِ Binding که لایه ی View هست (همون Binding Target Property) و یک طرف دیگه که ممکنه هر لایه ای اعم از View و Model و حتی ViewModel به عنوان Binding Source Property باشه .
فرضا اگه Binding Source Property مون در لایه ی Model باشه و لازم بشه که مقدارش را به نوعِ مورد نظر در View تبدیل کنیم ، بهترین مکانی که به هر دو اطلاعات از لایه ها بشه دسترسی داشت و MVVM را نقض نکنه ، لایه ی ViewModel هست .
درست میگم؟

تشکر .
بله.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد .
در کنترل Hardcodet.Wpf.TaskbarNotification.TaskbarIcon ، وقتی پروپرتی ToolTipText اش را بصورت زیر مینویسم :

C#:
this.TaskbarIcon.ToolTipText = "پشتیبان 1.2 (بکاپ ها)";

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

مقدار پروپرتیِ Language و FlowDirection اش را هم تغییر دادم اما تفاوتی نکرد :

C#:
this.TaskbarIcon.FlowDirection = FlowDirection.RightToLeft;
this.TaskbarIcon.Language = System.Windows.Markup.XmlLanguage.GetLanguage("ar-SA");

راهی برای درست شدنش هست (که پرانتزها را مثلِ همینی که در این انجمن میبینیم ، موقع اجرای برنامه هم همینطور نشون بده) ؟

===============

ویرایش :

بجای پروپرتیِ ToolTipText ، از پروپرتیِ TrayToolTip اش استفاده کردم و UIElement ای که برای این پروپرتی در نظر گرفتم ، پروپرتیِ FlowDirection را تنظیم کردم و درست شد .

تشکر .
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد ، هر وقت ، هر بار ، یا هر دو بار یا سه بار درمیون ، پروژه ی wpf ام را از ویژال استودیو اجرا میکنم و میبندم ، 50 تا 100 مگابایت ، نشتی حافظه داره .
اول فکر کردم مشکل نشتی از پروژه ی من هست . اما وقتی پروژه ام را بدون ویژال استودیو (یعنی مستقلا) ، چند ده بار اجرا کردم ، دیدم مشکل نشتی حافظه نداره .

اما وقتی از ویژال استودیو اجرا میکنم و بعد میبندم ، نشتی داره . جوری که فرضا بعد از 10 بار اجرای نرم افزار از ویژال استودیو ، شاید چیزی حدود 800 مگ نشتی حافظه داره و به میزان استفاده از حافظه ، اضافه میشه (منظورم حافظه ی مجازی هست که در قسمت Commited در Task Managerمشخص هست . به حافظه ی فیزیکی هم اضافه میشه) .
بعد از 20 تا 30 بار اجرا از طریق ویژال استودیو ، حدودا 1.5 گیگ نشتی حافظه داره .

نسخه ی ویژال استودیو ام ، 16.9.2 هست .
این ، باگِ ویژال استودیو هست؟
قضیه چیه؟

مخصوصا برای من که محدودیت نسبی حافظه دارم و دو شی از ویژال استودیو باز باشه و چندین سربرگ در مرورگر هم باز باشه ، رم خیلی پر میشه و page file بیشتر درگیر میشه .
تشکر
 

the_king

مدیرکل انجمن
سلامی مجدد
استاد ، هر وقت ، هر بار ، یا هر دو بار یا سه بار درمیون ، پروژه ی wpf ام را از ویژال استودیو اجرا میکنم و میبندم ، 50 تا 100 مگابایت ، نشتی حافظه داره .
اول فکر کردم مشکل نشتی از پروژه ی من هست . اما وقتی پروژه ام را بدون ویژال استودیو (یعنی مستقلا) ، چند ده بار اجرا کردم ، دیدم مشکل نشتی حافظه نداره .

اما وقتی از ویژال استودیو اجرا میکنم و بعد میبندم ، نشتی داره . جوری که فرضا بعد از 10 بار اجرای نرم افزار از ویژال استودیو ، شاید چیزی حدود 800 مگ نشتی حافظه داره و به میزان استفاده از حافظه ، اضافه میشه (منظورم حافظه ی مجازی هست که در قسمت Commited در Task Managerمشخص هست . به حافظه ی فیزیکی هم اضافه میشه) .
بعد از 20 تا 30 بار اجرا از طریق ویژال استودیو ، حدودا 1.5 گیگ نشتی حافظه داره .

نسخه ی ویژال استودیو ام ، 16.9.2 هست .
این ، باگِ ویژال استودیو هست؟
قضیه چیه؟

مخصوصا برای من که محدودیت نسبی حافظه دارم و دو شی از ویژال استودیو باز باشه و چندین سربرگ در مرورگر هم باز باشه ، رم خیلی پر میشه و page file بیشتر درگیر میشه .
تشکر
سیستم عامل به پروسه حافظه میده و وقتی پروسه بسته شد هر چی داده بود پس میگیره، چه پروسه خوب اون حافظه رو مدیریت کرده باشه و چه نکرده باشه. یعنی نشتی حافظه در داخل برنامه رخ میده و هی حافظه اضافی دریافت می کنه، اما سیستم عامل نهایتا با بسته شدن پروسه همون حافظه نشتی رو هم پس می گیره.
نشتی حافظه در پروسه در حال اجرا رخ میده، نه پروسه ای که دیگه بسته شده. بنابر این اگه واقعا نشتی ای هم باشه مربوط به روالی است که بعد از بسته شدن ویژوال استدیو همچنان در حال اجرا است، پروسه خاتمه یافته دیگه حافظه نداره.
و یا میتونه نشتی ای در کار نباشه ولی یک پروسه برای منظوری همچنان از اون حجم حافظه استفاده می کنه.
 

SajjadKhati

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

در کد زیر :


که گفتش برای تشخیص راحت ترِ :
TopLevelHeader
TopLevelItem
SubmenuItem
SubmenuHeader
بهتره که اون کد را بنویسیم ، من اون را (بصورت ContextMenu) نوشتم :

XML:
        <Button MouseEnter="Button_MouseEnter"  HorizontalAlignment="Left" Height="44" Margin="433,316,0,0" VerticalAlignment="Top" Width="116" Content="Right-click me!">
            <Button.ContextMenu>
                <ContextMenu>
                    <MenuItem >
                        <MenuItem />
                        <MenuItem/>
                        <MenuItem />
                    </MenuItem>
                    <MenuItem >
                        <System:String>Second item</System:String>
                    </MenuItem>
                    <Separator/>
                    <MenuItem />
                </ContextMenu>
            </Button.ContextMenu>
        </Button>

حالا نتیجه ای که میگیرم ببینین درسته؟ :

- SubmenuItem : به شیِ MenuItem (یا هر شیِ دیگه به عنوان آیتم) ای گفته میشه که اولا فرزند نداره و دوما جزء زیر منو محسوب بشه (زیر منو را در خط آخر تعریف میکنم 1) .
- SubmenuHeader : به شیِ MenuItem ای گفته میشه که اولا فرزند داره و دوما جزء زیر منو محسوب بشه .
- TopLevelItem و TopLevelItem را دقیق تفاوت شون را نمیدونم . این دو مورد را یه کم توضیح میدین که به کدوم ها دقیقا TopLevelItem و به کدوم ها TopLevelItem گفته میشه (بی زحمت با مثال باشه ، یا فرضا اگه منوهای یک نرم افزار مثلا منوهای visual studio 2019 را مثال بزنید ، بهتر درک میکنم) .

هر چند TopLevel انگار به منوهایی گفته میشه که فقط در قسمت بالا (اول) در menu bar هستن . مثلا در عکس زیر :

MBGCQ.png


به اون آیتم هایی که فقط در بالا هستن (Top One و Top Two و ...) میگن Top Level . همچنین Context Menu ها ، Top Level ندارن .

1) زیر منوها هم اون هایی هستن که Top Level نیستن . یعنی Context Menu ها ، همه شون جزء زیر منوها هستن .
اینهایی که گفتم ، درستن؟
تشکر استاد :rose:
 
آخرین ویرایش:

the_king

مدیرکل انجمن
سلام استاد .
خیلی ممنون استاد از جواب تون .

در کد زیر :


که گفتش برای تشخیص راحت ترِ :
TopLevelHeader
TopLevelItem
SubmenuItem
SubmenuHeader
بهتره که اون کد را بنویسیم ، من اون را (بصورت ContextMenu) نوشتم :

XML:
        <Button MouseEnter="Button_MouseEnter"  HorizontalAlignment="Left" Height="44" Margin="433,316,0,0" VerticalAlignment="Top" Width="116" Content="Right-click me!">
            <Button.ContextMenu>
                <ContextMenu>
                    <MenuItem >
                        <MenuItem />
                        <MenuItem/>
                        <MenuItem />
                    </MenuItem>
                    <MenuItem >
                        <System:String>Second item</System:String>
                    </MenuItem>
                    <Separator/>
                    <MenuItem />
                </ContextMenu>
            </Button.ContextMenu>
        </Button>

حالا نتیجه ای که میگیرم ببینین درسته؟ :

- SubmenuItem : به شیِ MenuItem (یا هر شیِ دیگه به عنوان آیتم) ای گفته میشه که اولا فرزند نداره و دوما جزء زیر منو محسوب بشه (زیر منو را در خط آخر تعریف میکنم 1) .
- SubmenuHeader : به شیِ MenuItem ای گفته میشه که اولا فرزند داره و دوما جزء زیر منو محسوب بشه .
- TopLevelItem و TopLevelItem را دقیق تفاوت شون را نمیدونم . این دو مورد را یه کم توضیح میدین که به کدوم ها دقیقا TopLevelItem و به کدوم ها TopLevelItem گفته میشه (بی زحمت با مثال باشه ، یا فرضا اگه منوهای یک نرم افزار مثلا منوهای visual studio 2019 را مثال بزنید ، بهتر درک میکنم) .

هر چند TopLevel انگار به منوهایی گفته میشه که فقط در قسمت بالا (اول) در menu bar هستن . مثلا در عکس زیر :

MBGCQ.png


به اون آیتم هایی که فقط در بالا هستن (Top One و Top Two و ...) میگن Top Level . همچنین Context Menu ها ، Top Level ندارن .

1) زیر منوها هم اون هایی هستن که Top Level نیستن . یعنی Context Menu ها ، همه شون جزء زیر منوها هستن .
اینهایی که گفتم ، درستن؟
تشکر استاد :rose:
یک مورد ناشناخته و کشف نشده نیست که بخواهید با نوشتن چیزی نتیجه گیری کنید. نتیجه گیری نمیخواد، قواعدش رو خودش نوشته.
توضیحاتش که در MenuItemRole هست :

قواعدش هم که در ()System.Windows.Controls.MenuItem.UpdateRole هست :
C#:
// System.Windows.Controls.MenuItem
private void UpdateRole()
{
    SetValue(value: (!IsCheckable && base.HasItems) ? ((LogicalParent is Menu) ? MenuItemRole.TopLevelHeader : MenuItemRole.SubmenuHeader) : ((!(LogicalParent is Menu)) ? MenuItemRole.SubmenuItem : MenuItemRole.TopLevelItem), key: RolePropertyKey);
}
اگر درک اش کد به واسطه اون :? های پشت سر هم دشوار شده، این معادل اونه که خیلی خوانا است :
C#:
            if (!IsCheckable && base.HasItems)
            {
                if (LogicalParent is Menu)
                {
                    value = MenuItemRole.TopLevelHeader;
                }
                else
                {
                    value = MenuItemRole.SubmenuHeader;
                }
            }
            else
            {
                if (!(LogicalParent is Menu))
                {
                    value = MenuItemRole.SubmenuItem;
                }
                else
                {
                    value = MenuItemRole.TopLevelItem;
                }
            }
 

SajjadKhati

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

استاد ، من یه ToolTip در کد سی شارپ ام (نه کد xaml) دارم که به عنوان مقدارِ پروپرتیِ TrayToolTip در کنترل Hardcodet.Wpf.TaskbarNotification.TaskbarIcon استفاده میشه .

TaskbarIcon هم از لحاظ پدر و فرزندی ، مستقل از MainWindow ام هست . یعنی TaskbarIcon ، فرزندِ MainWindow محسوب نمیشه . پس این ToolTip ام هم فرزند MainWindow محسوب نمیشه .
از طرفی در Resource ئه MainWindow ، اون DarkStyle را اضافه کردم که شامل Style از نوعِ ToolTip هم میشه .

حالا در کد سی شارپ ، اگه بخوام استایل را برای ToolTip ام تنظیم کنم و کد را بصورت زیر بنویسم ، درست عمل میکنه :

C#:
trayIconToolTip.Style = this.Resources[typeof(ToolTip)] as Style;

اما کد بالا بصورت StaticResource استفاده میشه . و با تغییر Resource ئه MainWindow ، همون مقدار قبلی اش میمونه .

اما اگه بخوام بصورت DynamicResource متصل کنم ، در کد زیر با توجه به اینکه ToolTip ، فرزندِ MainWindow نیست ، باید کد را چجوری تغییر بدم تا درست بشه؟ :

C#:
trayIconToolTip.SetResourceReference(System.Windows.Controls.ToolTip.StyleProperty, ) ;

پارامتر دوم را باید چی بنویسم؟

مقدار Resource ئه MainWindow ام در xaml بصورت زیر نوشتم :

XML:
    <local:PoshtibangirToloWindowBase.Resources>
        <ResourceDictionary>
            
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>

        </ResourceDictionary>
    </local:PoshtibangirToloWindowBase.Resources>

یا اگه DynamicResource نشه ، در کد سی شارپ ، چجوری بهش Binding کنم؟
تشکر استاد .
 

SajjadKhati

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

استاد ، من یه ToolTip در کد سی شارپ ام (نه کد xaml) دارم که به عنوان مقدارِ پروپرتیِ TrayToolTip در کنترل Hardcodet.Wpf.TaskbarNotification.TaskbarIcon استفاده میشه .

TaskbarIcon هم از لحاظ پدر و فرزندی ، مستقل از MainWindow ام هست . یعنی TaskbarIcon ، فرزندِ MainWindow محسوب نمیشه . پس این ToolTip ام هم فرزند MainWindow محسوب نمیشه .
از طرفی در Resource ئه MainWindow ، اون DarkStyle را اضافه کردم که شامل Style از نوعِ ToolTip هم میشه .

حالا در کد سی شارپ ، اگه بخوام استایل را برای ToolTip ام تنظیم کنم و کد را بصورت زیر بنویسم ، درست عمل میکنه :

C#:
trayIconToolTip.Style = this.Resources[typeof(ToolTip)] as Style;

اما کد بالا بصورت StaticResource استفاده میشه . و با تغییر Resource ئه MainWindow ، همون مقدار قبلی اش میمونه .

اما اگه بخوام بصورت DynamicResource متصل کنم ، در کد زیر با توجه به اینکه ToolTip ، فرزندِ MainWindow نیست ، باید کد را چجوری تغییر بدم تا درست بشه؟ :

C#:
trayIconToolTip.SetResourceReference(System.Windows.Controls.ToolTip.StyleProperty, ) ;

پارامتر دوم را باید چی بنویسم؟

مقدار Resource ئه MainWindow ام در xaml بصورت زیر نوشتم :

XML:
    <local:PoshtibangirToloWindowBase.Resources>
        <ResourceDictionary>
         
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>

        </ResourceDictionary>
    </local:PoshtibangirToloWindowBase.Resources>

یا اگه DynamicResource نشه ، در کد سی شارپ ، چجوری بهش Binding کنم؟
تشکر استاد .

به این استایل ای که در Resource تعریف کردم ، Binding انجام دادم :

C#:
            Binding trayToolTipStyleBindingTarget = new Binding();
            trayToolTipStyleBindingTarget.Source = this.Resources[typeof(ToolTip)];
            trayIconToolTip.SetBinding(System.Windows.Controls.ToolTip.StyleProperty, trayToolTipStyleBindingTarget);

اما با تغییر مقدار به LightStyleResource.xaml ، کد بالا ، باعث تغییرِ استایلِ ToolTip نشد و همون استایلِ قبلی اش (که Dark بود) ، باقی موند .
در واقع چون من نیومدم فقط مقدارِ استایل با نوعِ ToolTip (که کلیدش هم چه بذاریم یا نه ، همون ToolTip هست) را تغییر بدم (که اگه این کار را میکردم ، احتمالا کد بالا جواب میداد) .
بلکه کل Source ئه ResourceDictionary را تغییر دادم که ربطی به تغییرِ نوعِ ToolTip نداره .

پس استاد راهکاری برای حل این مشکل به نظرتون چیه؟
تشکر
 

SajjadKhati

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

خودمون باید استایل اون کنترل را جداگانه تغییر بدیم؟
مثل قضیه ی بالا؟
تشکر
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .

استاد ، من یه ToolTip در کد سی شارپ ام (نه کد xaml) دارم که به عنوان مقدارِ پروپرتیِ TrayToolTip در کنترل Hardcodet.Wpf.TaskbarNotification.TaskbarIcon استفاده میشه .

TaskbarIcon هم از لحاظ پدر و فرزندی ، مستقل از MainWindow ام هست . یعنی TaskbarIcon ، فرزندِ MainWindow محسوب نمیشه . پس این ToolTip ام هم فرزند MainWindow محسوب نمیشه .
از طرفی در Resource ئه MainWindow ، اون DarkStyle را اضافه کردم که شامل Style از نوعِ ToolTip هم میشه .

حالا در کد سی شارپ ، اگه بخوام استایل را برای ToolTip ام تنظیم کنم و کد را بصورت زیر بنویسم ، درست عمل میکنه :

C#:
trayIconToolTip.Style = this.Resources[typeof(ToolTip)] as Style;

اما کد بالا بصورت StaticResource استفاده میشه . و با تغییر Resource ئه MainWindow ، همون مقدار قبلی اش میمونه .

اما اگه بخوام بصورت DynamicResource متصل کنم ، در کد زیر با توجه به اینکه ToolTip ، فرزندِ MainWindow نیست ، باید کد را چجوری تغییر بدم تا درست بشه؟ :

C#:
trayIconToolTip.SetResourceReference(System.Windows.Controls.ToolTip.StyleProperty, ) ;

پارامتر دوم را باید چی بنویسم؟
نباید اون ResourceReference پیشفرض رو تغییر بدهید. دقت کنید که یک ToolTip هر جا که باشه، اون ResourceReference رو داره، ربطی به اینکه والدش چیه و کجاست نداره.
مقدار Resource ئه MainWindow ام در xaml بصورت زیر نوشتم :

XML:
    <local:PoshtibangirToloWindowBase.Resources>
        <ResourceDictionary>
         
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>

        </ResourceDictionary>
    </local:PoshtibangirToloWindowBase.Resources>

یا اگه DynamicResource نشه ، در کد سی شارپ ، چجوری بهش Binding کنم؟
تشکر استاد .
نباید Binding کنید، چون شما نمیدونید که عامل تغییر Style ها در اون Window چیه. Binding رو بر اساس تغییر کدوم مشخصه بنویسید که مطمئن باشید تغییر می کنه؟ معلوم نیست. فرضا ممکنه Resources اش کلا با یک ResourceDictionary جدید جایگزین بشه، یا ممکنه ResourceDictionary اش همون قبلی بمونه ولی در زیر مجموعه اش MergedDictionaries جدیدی اضافه یا کم بشه. یا اصلا در ResourceDictionary های زیر مجموعه اش تغییری رخ بده. یا حتی در یک Style داخلش تغییری رخ بده. شما که نمیدونید چی قراره تغییر کنه. فقط میدونید که قراره در Style پیشفرض برای ToolTip های مرتبط با این Window تغییری رخ بده.

به این استایل ای که در Resource تعریف کردم ، Binding انجام دادم :

C#:
            Binding trayToolTipStyleBindingTarget = new Binding();
            trayToolTipStyleBindingTarget.Source = this.Resources[typeof(ToolTip)];
            trayIconToolTip.SetBinding(System.Windows.Controls.ToolTip.StyleProperty, trayToolTipStyleBindingTarget);

اما با تغییر مقدار به LightStyleResource.xaml ، کد بالا ، باعث تغییرِ استایلِ ToolTip نشد و همون استایلِ قبلی اش (که Dark بود) ، باقی موند .
در واقع چون من نیومدم فقط مقدارِ استایل با نوعِ ToolTip (که کلیدش هم چه بذاریم یا نه ، همون ToolTip هست) را تغییر بدم (که اگه این کار را میکردم ، احتمالا کد بالا جواب میداد) .
بلکه کل Source ئه ResourceDictionary را تغییر دادم که ربطی به تغییرِ نوعِ ToolTip نداره .

پس استاد راهکاری برای حل این مشکل به نظرتون چیه؟
تشکر
من پیشنهاد می کنم که از مکانیسم خود WPF استفاده کنید، یعنی اجازه بدهید که یک المنتی که فرزند خود پنجره است متوجه تغییر در Style برای ToolTip بشه و بعد اون المنت به trayIconToolTip اون تغییر و Style جدید رو منتقل کنه.
مثلا این MyButton وقتی Style اش تغییر کرد، با رخداد StyleChanged میتونه اطلاع بده :
C#:
        private class MyButton : Button
        {
            private static readonly RoutedEvent StyleChangedEvent;

            public delegate void StyleChangedEventHandler(object sender, RoutedEventArgs e);

            public event StyleChangedEventHandler StyleChanged
            {
                add => AddHandler(StyleChangedEvent, value, false);
                remove => RemoveHandler(StyleChangedEvent, value);
            }

            static MyButton()
            {
                StyleChangedEvent = EventManager.RegisterRoutedEvent("StyleChanged", RoutingStrategy.Direct, typeof(StyleChangedEventHandler), typeof(MyButton));
            }

            public MyButton()
            {
                SetResourceReference(StyleProperty, typeof(Button));
            }

            protected override void OnStyleChanged(Style oldStyle, Style newStyle)
            {
                base.OnStyleChanged(oldStyle, newStyle);
                RaiseEvent(new RoutedEventArgs(StyleChangedEvent, this));
            }
        }
حالا اگر در اون Window یک Button رو با کد نویسی حتی با Visibility.Hidden اضافه کنید، به محض اینکه تغییری در Style پیشفرض برای Button رخ بده میتونه اطلاع بده تا فرضا با Button1.Style = ((Button)sender).Style اون Style رو روی المنت دیگری که هیچ ربطی به اون Window نداره اعمال کنید. Style پیشفرض اون پنجره برای Button ها رو هم می توانید همیشه در Style خود اون Button پیدا کنید.

سلامی مجدد
اگه یه کنترلی ، فرزندِ کنترلِ MainWindow که توی Resource اش استایل تعریف شد ، نباشه ، راهی نداره که با تغییر ریسورس ، استایلِ اون کنترلی که فرزندش نیست هم اتوماتیک تغییر کنه؟

خودمون باید استایل اون کنترل را جداگانه تغییر بدیم؟
مثل قضیه ی بالا؟
تشکر
مساله اصلی تغییر Resource نیست، تغییر Resource یکی از عامل های تغییر Style ئه، مساله اصلی رخداد تغییر Style ئه.
شما می خواهید از روالی استفاده کنید که بصورت داخلی در المنت های WPF پیاده سازی شده و کاری با المنت های خارج از اون Scope مشخص نداره و میخواهید به طریقی به موردی ربطش بدهید که بیرون از اون Scope ئه. اون روال داخلی رو نمی توانید تغییر بدهید چون در کد های WPF ئه، اما می توانید از تغییر مطلع بشوید و بعد به اون المنت منتقلش کنید.
 

SajjadKhati

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

حالا یه مورد دارم که دقیق برعکس مورد قبلی هست . یعنی ، مورد قبلی ، کنترلِ ToolTip ای بود که فرزند یا نوادگانِ MainWindows نبود و میخواستیم با تغییرِ استایل ای که این تغییرِ استایل را توسط Source ئه ResourceDictionary (ای که به عنوان Resource ئه MainWindow تعریف شده) اِعمال میکنیم ، استایلِ مورد نظر ، برای ToolTip مون هم اعمال بشه .


اما در این مورد ، یه کنترل user control ای داریم که داخلش چند تا کنترلِ دیگه هست . و طبعا اگه بخوایم به این کنترل هایی که داخل شون هستن هم استایل بدیم ، باید فایل xaml ای که حاوی استایل مون هستن را برای user control مون هم استفاده کنیم .
کد هم برای اِعمالِ استایل در user control هم مثل کد MainWindow هست :

XML:
    <local:PoshtibangirToloWindowBase.Resources>
        <ResourceDictionary>
            
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>

        </ResourceDictionary>
    </local:PoshtibangirToloWindowBase.Resources>

یعنی در اینجا ، user control مون ، فرزند و یا جزء نوادگانِ MainWindow محسوب میشه .
در این صورت ، وقتی که استایلِ MainWindow را عوض کردم ، مجبورم همه ی اشیای user control ای که در همه ی Window ها بکاربردم را هم جداگانه تغییر استایل بدم .
چون پروپرتیِ Source ئه ResourceDictionary از نوع DependencyProperty نیست که بتونم این پروپرتیِ user control را به همین پروپرتی ای که در MainWindow استفاده کرده بودم ، Binding و یا DynamicResource کنم .


حالا به نظرتون راهی هست که (در کد xaml یا در کد سی شارپ ، فرقی نداره) بشه پروپرتیِ Source ئه ResourceDictionary ای که در user control بکار بردیم را به همین پروپرتی ای که در MainWindow بکار بردیم ، ارتباط داد جوری که با تغییرِ این پروپرتی در MainWindow ، همین پروپرتی در user control ، اتوماتیک تغییر کنه و یا هر راهکار دیگه ای که بصورت دستی مجبور نباشیم که خودمون کدش را تغییر بدیم؟
بهترین راهکار این هم مثل قبلی ، استفاده از رویداد و اطلاع رسانی از طریق رویداد هست؟

همین مشکل را برای ویندوزهای دیگه هم دارم . یعنی یه ویندوزِ SettingWindow ای دارم که با پروپرتیِ Owner اش ، با MainWindow در ارتباط هست و از طریقِ کدِ xaml ئه بالا ، روش ، استایل اِعمال میشه که این را هم مجبورم باز هم بصورت دستی و جداگانه ، استایلش را تغییر بدم .
جوری میشه که اینها را به هم وابسته که و با تغییر یک استایل برای MainWindow ، استایل بقیه ی SettingWindow و user control ها هم اتوماتیک تغییر کنه؟

تشکر استاد .
 

the_king

مدیرکل انجمن
پس بهترین راه اینه که رویداد براش ایجاد کنم .
چرا فکر می کنید بهترین راه شده؟ من نمیدونم همه راه ها چیه.
در این صورت ، وقتی که استایلِ MainWindow را عوض کردم ، مجبورم همه ی اشیای user control ای که در همه ی Window ها بکاربردم را هم جداگانه تغییر استایل بدم .
چرا مجبور هستید؟ وقتی برای User Control یا هر المنت دیگری یک Style مشخص رو فرضا از طریق Key بکار ببرید دیگه ارتباطی با تغییرات Style های پیشفرض نداره. وقتی شما در Application.Resources یک Style با کلید برای این User Control تعریف کنید می توانید به اون User Control ها اون Style رو تخصیص بدهید که از Window شون مستقل باشند. و هر تغییری در اون Resource یا Style به همه User Control ها منعکس بشه.
حالا به نظرتون راهی هست که (در کد xaml یا در کد سی شارپ ، فرقی نداره) بشه پروپرتیِ Source ئه ResourceDictionary ای که در user control بکار بردیم را به همین پروپرتی ای که در MainWindow بکار بردیم ، ارتباط داد جوری که با تغییرِ این پروپرتی در MainWindow ، همین پروپرتی در user control ، اتوماتیک تغییر کنه و یا هر راهکار دیگه ای که بصورت دستی مجبور نباشیم که خودمون کدش را تغییر بدیم؟
بهترین راهکار این هم مثل قبلی ، استفاده از رویداد و اطلاع رسانی از طریق رویداد هست؟
متوجه نمی شوم که چرا میخواهید واسطه تغییرات در یک پنجره باشه. اگر قراره منبع تغییرات محدوده ای فراتر از یک پنجره خاص رو پوشش بده، میتونه خارج از پنجره ها باشه، چرا از درون یک پنجره کنترل بشه؟
همین مشکل را برای ویندوزهای دیگه هم دارم . یعنی یه ویندوزِ SettingWindow ای دارم که با پروپرتیِ Owner اش ، با MainWindow در ارتباط هست و از طریقِ کدِ xaml ئه بالا ، روش ، استایل اِعمال میشه که این را هم مجبورم باز هم بصورت دستی و جداگانه ، استایلش را تغییر بدم .
جوری میشه که اینها را به هم وابسته که و با تغییر یک استایل برای MainWindow ، استایل بقیه ی SettingWindow و user control ها هم اتوماتیک تغییر کنه؟
چرا مجبور هستید؟ هیچ المنتی مجبور نیست از Style پیشفرض استفاده کنه.
 

SajjadKhati

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

چرا مجبور هستید؟ وقتی برای User Control یا هر المنت دیگری یک Style مشخص رو فرضا از طریق Key بکار ببرید دیگه ارتباطی با تغییرات Style های پیشفرض نداره. وقتی شما در Application.Resources یک Style با کلید برای این User Control تعریف کنید می توانید به اون User Control ها اون Style رو تخصیص بدهید که از Window شون مستقل باشند. و هر تغییری در اون Resource یا Style به همه User Control ها منعکس بشه.

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

سلامی مجدد
خیلی ممنون استاد .
این رو تقریبا متوجه شدم .

چرا مجبور هستید؟ هیچ المنتی مجبور نیست از Style پیشفرض استفاده کنه.

میخوام در SettingWindow هم از استایل های Dark و Light که ساخته بودم استفاده کنم .
برای بکار بردن این استایل ها در این پنجره ها ، مثل قضیه ی MainWindow ، مجبورم که پروپرتیِ Source ئه ResourceDictionary را تنظیم کنم دیگه .

اگه مقدارِ Source ئه ResourceDictionary در MainWindow را تغییر بدم ، باز مجبورم که دوباره ، مقدارِ Source ئه ResourceDictionary در SettingWindow را هم تغییر بدم (و هر تعداد از ویندوزهایی که میسازم و میخوام این استایل ها را روشون اِعمال کنم را هم باید Source ئه ResourceDictionary ئه اون ویندوزها را هم تغییر بدم) .

حالا راهی هست که فرضا همه شون را به یه جا متصل کنم (با اونکه میدونم پروپرتیِ Source ئه ResourceDictionary چون DependencyProperty نمیشه ، پس نمیشه به عنوان Binding Target قرار بگیره) تا با تغییرِ مقدارِ یک چیز (اون چیز ، حالا متغییر ، پروپرتی و ... باشه) ، مقدار بقیه هم اتوماتیک تغییر کنن؟


فرضا همه ی اینها (همه ی پروپرتیِ Source ئه ResourceDictionary برای ویندوزهای مختلف) را به یک اشاره گری از رشته (string) متصل کنیم (منظورم از متصل کردن ، Binding نیست . صرفا مقداردهیِ عادی هست) .
بعد هم یه جوری فرضا بشه مقدارِ آدرسِ اشاره گر (نه اینکه مقدارِ خودِ اشاره گر برای اون متغییر) را تغییر بدیم .
چطوره؟
این جوری دیگه لازم نیست برای هر ویندوزی که میسازیم و میخوایم استایلش را تغییر بدیم ، کدِ تغییرِ مقدارِ استایلش را هم بنویسیم .

تشکر استاد .
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .
این رو تقریبا متوجه شدم .



میخوام در SettingWindow هم از استایل های Dark و Light که ساخته بودم استفاده کنم .
برای بکار بردن این استایل ها در این پنجره ها ، مثل قضیه ی MainWindow ، مجبورم که پروپرتیِ Source ئه ResourceDictionary را تنظیم کنم دیگه .

اگه مقدارِ Source ئه ResourceDictionary در MainWindow را تغییر بدم ، باز مجبورم که دوباره ، مقدارِ Source ئه ResourceDictionary در SettingWindow را هم تغییر بدم (و هر تعداد از ویندوزهایی که میسازم و میخوام این استایل ها را روشون اِعمال کنم را هم باید Source ئه ResourceDictionary ئه اون ویندوزها را هم تغییر بدم) .
باز که میگید مجبور هستید، ازتون سوال کردم چرا مجبور هستید؟ چه کسی یا چه چیزی شما رو مجبور میکنه که در MainWindow یا هر پنجره دیگری Source ئه ResourceDictionary تنظیم کنید؟ چه مساله ای مانع میشه که در App.xaml یک MergedDictionaries برای اون Dark یا Light اضافه کنید و هر زمان هم لازم شد قبلی رو حذف کنید و اون دیگری رو جایگزین کنید؟
حالا راهی هست که فرضا همه شون را به یه جا متصل کنم (با اونکه میدونم پروپرتیِ Source ئه ResourceDictionary چون DependencyProperty نمیشه ، پس نمیشه به عنوان Binding Target قرار بگیره) تا با تغییرِ مقدارِ یک چیز (اون چیز ، حالا متغییر ، پروپرتی و ... باشه) ، مقدار بقیه هم اتوماتیک تغییر کنن؟
لازم نیست به مورد خاصی متصل شون کنید. همه المنت هایی که با Style پیشفرض کار می کنند نسبت به تغییرش واکنش نشون می دهند.
در ضمن در نظر بگیرید که برای تغییر یک منبع Style ها لازم نیست Source رو تغییر بدهید، می توانید کلا یک ResourceDictionary رو با Source جدید جایگزین قبلی کنید.
فرضا همه ی اینها (همه ی پروپرتیِ Source ئه ResourceDictionary برای ویندوزهای مختلف) را به یک اشاره گری از رشته (string) متصل کنیم (منظورم از متصل کردن ، Binding نیست . صرفا مقداردهیِ عادی هست) .
بعد هم یه جوری فرضا بشه مقدارِ آدرسِ اشاره گر (نه اینکه مقدارِ خودِ اشاره گر برای اون متغییر) را تغییر بدیم .
چطوره؟
این جوری دیگه لازم نیست برای هر ویندوزی که میسازیم و میخوایم استایلش را تغییر بدیم ، کدِ تغییرِ مقدارِ استایلش را هم بنویسیم .
App.xml و Application.Current.Resources محلی است که شما برای منابع مشترک بین اون پنجره ها بکار می برید.
وقتی یک ResourceDictionary رو از داخلش حذف می کنید و دیگری رو جایگزین می کنید المنت ها در پنجره های مختلف تاثیر می گیرند.
C#:
            Application.Current.Resources.MergedDictionaries.Clear();
            Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("Dictionary2.xaml", UriKind.Relative) });
مگر اینکه باز بگید مجبور هستم.
 

SajjadKhati

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

آره ، میدونستم این قضیه را .
مدت ها پیش هم استایل ها را توی App.Xaml لود کرده بودم . یه مشکلی پیش اومده بود که نمیدونم چی بود و فکر کردم واسه ی این قضیه هست . الان که دوباره منتقل کردم ، درست شد . تشکر استاد.

-----------

بعد استاد یه مسئله ای برای ShapeTextButton ام هست .
ساختار استایل هام را میدونید که ، یه DarkStyle و یه LightStyle دارم که شامل استایل های نوع ShapeTextButton هم هستن .
بعد در TitleBarUserControl (که از نوع UserControl هست) ، از ShapeTextButton استفاده کردم منتها در Resource ئه TitleBarUserControl ، یک استایلِ دیگه از ShapeTextButton ساختم که بر اساسِ استایلِ قبلی هست :

XML:
            <UserControl:TitleBarUserControl.Resources>
                <Style TargetType="{x:Type CustomControls:ShapeTextButton}" BasedOn="{StaticResource {x:Type CustomControls:ShapeTextButton}}">
                    <Setter Property="DockPanel.Dock" Value="Right"/>
                    <Setter Property="Margin" Value="0,8,10,8"/>
                    <Setter Property="Width" Value="24"/>
                    <Setter Property="Height" Value="24"/>
                    <Setter Property="GetContentBrush_ForWhichButtonShapeProperty" Value="Stroke"/>
                </Style>
            </UserControl:TitleBarUserControl.Resources>

منظورم از استایل قبلی ، استایلِ ShapeTextButton ای هست که در DarkStyle یا LightStyle تعریف شده و کلید نداره (که اگه کلیدی نداشته باشه ، میدونید که اتوماتیک ، کلیدِ نوعِ همون المنت و همون نوع را در نظر میگیره) .


حالا مشکل اینه که هر کنترل ShapeTextButton ای که درون این TitleBarUserControl ایجاد میکنم (یعنی هر کنترل ShapeTextButton ای که استایل در کد بالا روش اِعمال میشه) ، استایلِ پیش فرض اش که هر چی باشه که این استایل پیش فرض را در Resource ئه App.Xaml اون استایل را لود کردم ، همون اِعمال میشه اما وقتی استایل در Resource ئه App.Xaml را تغییر میدم ، ShapeTextButton هایی که در TitleBarUserControl هستن ، استایلِ جدید ، روشون اِعمال نمیشه و همون استایل قدیم شون باقی میمونن .
اما ShapeTextButton هایی که استایل در کد بالا براشون اِعمال نمیشه (یعنی درون TitleBarUserControl نیستن) ، مشکلی ندارن و به درستی کار میکنن .


این مشکل ، بخاطر پروپرتیِ BasedOn در کد بالا که بصورت StaticResource استفاده میشه هست؟
چون این پروپرتی که DependencyProperty نیست و پس نمیشه بصورت DynamicResource ازش استفاده کرد .
جالب اینجاست که در یه پنجره ی دیگه ، استایل دومِ ShapeTextButton را بر اساسِ استایلِ اولش (یعنی دقیقا شبیه کد بالا) را منتها برای کنترل های ShapeTextButton ای که درون یک Grid بودن ، یعنی برای Resource ئه Grid ساختمش و بدون مشکل کار میکنه . پروپرتیِ BasedOn اش را StaticResource کردم . و با تغییر LightStyle به DarkStyle و برعکس ، این ها هم تغییر میکنن و درست کار میکنن .

یا اینکه بخاطر اینه که کلیدِ قبلیِ استایلی که در DarkStyle و یا LightStyle برای ShapeTextButton نوشته شدن ، صریحا کلیدی ندارن و پس کلیدشون از نوع شیِ Type ای از نوعِ ShapeTextButton در نظر گرفته میشه و پس استایلِ بعدی ای که بر اساسش مینویسیم ، باید کلید مجزای دیگه ای داشته باشه؟ (استایل در کد بالا را کلید مجزا براش در نظر گرفتم اما باز هم همین مشکل وجود داره) .

یا اینکه مشکل از یه جای دیگه هست؟
کلا میدونین علت این مشکل چیه؟

================

مشکل دیگه اینکه وقتی این کد استایلِ ShapeTextButton را درونِ خودِ فایل xaml در کلاس TitleBarUserControl مینویسم (دقت کنید که این بار ، منظورم شی ای از کلاس TitleBarUserControl که فرضا در MainWindow و ... ازش میسازیم ، نیست . بلکه درون یکی از المنت Panel ای که در فایل xaml ئه کلاس TitleBarUserControl استفاده میکنیم ، هست) ، اولا اینکه مشکلی که در بالا گفته بودم ، همچنان پابرجاست و علاوه بر اون ، هر چند زمان اجرا ، درست اجرا میشه اما زمان طراحی ، ارور میده که نمیتونه resource ای با نام ShapeTextButton را پیدا کنه . در صورتی که نام فضای نام و کلا چیزهایی که مربوط به ShapeTextButton هست را درست میدم و برنامه به درستی اجرا میشه .

بعدش هم TitleBarUserControl ام هم به طَبَعِ این ارور ، زمان طراحی ، خطا میده و نشون داده نمیشه (اما زمان اجرای برنامه مشکلی نداره) .
اما اگه قبل از اجرای این استایلِ ShapeTextButton ای که در المنت Panel ئه TitleBarUserControl نوشته بودم ، استایل DarkStyle یا LightStyle را درون TitleBarUserControl الحاق کنم ، این مشکل حل میشه (با وجود اینکه DarkStyle را در فایل App.xaml الحاق کردم) :

XML:
<local:PoshtibangirToloUserControlBase.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </local:PoshtibangirToloUserControlBase.Resources>

میدونین چرا استایل ShapeTextButton که در کد اول در این پست دادم را در المنت Panel ئه TitleBarUserControl به تنهایی مینویسم ، همچین مشکلی ایجاد میشه؟

تشکر استاد .
 

SajjadKhati

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

آره ، میدونستم این قضیه را .
مدت ها پیش هم استایل ها را توی App.Xaml لود کرده بودم . یه مشکلی پیش اومده بود که نمیدونم چی بود و فکر کردم واسه ی این قضیه هست . الان که دوباره منتقل کردم ، درست شد . تشکر استاد.

-----------

بعد استاد یه مسئله ای برای ShapeTextButton ام هست .
ساختار استایل هام را میدونید که ، یه DarkStyle و یه LightStyle دارم که شامل استایل های نوع ShapeTextButton هم هستن .
بعد در TitleBarUserControl (که از نوع UserControl هست) ، از ShapeTextButton استفاده کردم منتها در Resource ئه TitleBarUserControl ، یک استایلِ دیگه از ShapeTextButton ساختم که بر اساسِ استایلِ قبلی هست :

XML:
            <UserControl:TitleBarUserControl.Resources>
                <Style TargetType="{x:Type CustomControls:ShapeTextButton}" BasedOn="{StaticResource {x:Type CustomControls:ShapeTextButton}}">
                    <Setter Property="DockPanel.Dock" Value="Right"/>
                    <Setter Property="Margin" Value="0,8,10,8"/>
                    <Setter Property="Width" Value="24"/>
                    <Setter Property="Height" Value="24"/>
                    <Setter Property="GetContentBrush_ForWhichButtonShapeProperty" Value="Stroke"/>
                </Style>
            </UserControl:TitleBarUserControl.Resources>

منظورم از استایل قبلی ، استایلِ ShapeTextButton ای هست که در DarkStyle یا LightStyle تعریف شده و کلید نداره (که اگه کلیدی نداشته باشه ، میدونید که اتوماتیک ، کلیدِ نوعِ همون المنت و همون نوع را در نظر میگیره) .


حالا مشکل اینه که هر کنترل ShapeTextButton ای که درون این TitleBarUserControl ایجاد میکنم (یعنی هر کنترل ShapeTextButton ای که استایل در کد بالا روش اِعمال میشه) ، استایلِ پیش فرض اش که هر چی باشه که این استایل پیش فرض را در Resource ئه App.Xaml اون استایل را لود کردم ، همون اِعمال میشه اما وقتی استایل در Resource ئه App.Xaml را تغییر میدم ، ShapeTextButton هایی که در TitleBarUserControl هستن ، استایلِ جدید ، روشون اِعمال نمیشه و همون استایل قدیم شون باقی میمونن .
اما ShapeTextButton هایی که استایل در کد بالا براشون اِعمال نمیشه (یعنی درون TitleBarUserControl نیستن) ، مشکلی ندارن و به درستی کار میکنن .


این مشکل ، بخاطر پروپرتیِ BasedOn در کد بالا که بصورت StaticResource استفاده میشه هست؟
چون این پروپرتی که DependencyProperty نیست و پس نمیشه بصورت DynamicResource ازش استفاده کرد .
جالب اینجاست که در یه پنجره ی دیگه ، استایل دومِ ShapeTextButton را بر اساسِ استایلِ اولش (یعنی دقیقا شبیه کد بالا) را منتها برای کنترل های ShapeTextButton ای که درون یک Grid بودن ، یعنی برای Resource ئه Grid ساختمش و بدون مشکل کار میکنه . پروپرتیِ BasedOn اش را StaticResource کردم . و با تغییر LightStyle به DarkStyle و برعکس ، این ها هم تغییر میکنن و درست کار میکنن .

یا اینکه بخاطر اینه که کلیدِ قبلیِ استایلی که در DarkStyle و یا LightStyle برای ShapeTextButton نوشته شدن ، صریحا کلیدی ندارن و پس کلیدشون از نوع شیِ Type ای از نوعِ ShapeTextButton در نظر گرفته میشه و پس استایلِ بعدی ای که بر اساسش مینویسیم ، باید کلید مجزای دیگه ای داشته باشه؟ (استایل در کد بالا را کلید مجزا براش در نظر گرفتم اما باز هم همین مشکل وجود داره) .

یا اینکه مشکل از یه جای دیگه هست؟
کلا میدونین علت این مشکل چیه؟

================

مشکل دیگه اینکه وقتی این کد استایلِ ShapeTextButton را درونِ خودِ فایل xaml در کلاس TitleBarUserControl مینویسم (دقت کنید که این بار ، منظورم شی ای از کلاس TitleBarUserControl که فرضا در MainWindow و ... ازش میسازیم ، نیست . بلکه درون یکی از المنت Panel ای که در فایل xaml ئه کلاس TitleBarUserControl استفاده میکنیم ، هست) ، اولا اینکه مشکلی که در بالا گفته بودم ، همچنان پابرجاست و علاوه بر اون ، هر چند زمان اجرا ، درست اجرا میشه اما زمان طراحی ، ارور میده که نمیتونه resource ای با نام ShapeTextButton را پیدا کنه . در صورتی که نام فضای نام و کلا چیزهایی که مربوط به ShapeTextButton هست را درست میدم و برنامه به درستی اجرا میشه .

بعدش هم TitleBarUserControl ام هم به طَبَعِ این ارور ، زمان طراحی ، خطا میده و نشون داده نمیشه (اما زمان اجرای برنامه مشکلی نداره) .
اما اگه قبل از اجرای این استایلِ ShapeTextButton ای که در المنت Panel ئه TitleBarUserControl نوشته بودم ، استایل DarkStyle یا LightStyle را درون TitleBarUserControl الحاق کنم ، این مشکل حل میشه (با وجود اینکه DarkStyle را در فایل App.xaml الحاق کردم) :

XML:
<local:PoshtibangirToloUserControlBase.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PoshtibangirTolo;component/Resource/Style_Template/DarkStyleResource.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </local:PoshtibangirToloUserControlBase.Resources>

میدونین چرا استایل ShapeTextButton که در کد اول در این پست دادم را در المنت Panel ئه TitleBarUserControl به تنهایی مینویسم ، همچین مشکلی ایجاد میشه؟

تشکر استاد .

سلامی مجدد
استاد ، زمان اجرای برنامه ، وقتی استایل را تغییر میدم ، بعدش میام شیِ Resource و Style ئه جدیدی برای شیِ TitleBarUserControl (که کد xaml ئه Rersource اش را در پست قبلی دادم) در نظر میگیرم اما با همون مقادیر قبلی برای استایلی که در کد xaml بود ، درست کار میکنه .
یعنی کد سی شارپ زیر را وقتی اجرا میکنم ، درست کار میکنه :

C#:
            App.Current.Resources.MergedDictionaries[2].Source = new Uri("/PoshtibangirTolo;component/Resource/Style_Template/LightStyleResource.xaml", UriKind.RelativeOrAbsolute);


            this.TitleBarUserControl.Resources = new ResourceDictionary();
            Style shapeTextButtonBaseStyle = App.Current.Resources[typeof(ShapeTextButton)] as Style;
            Style shapeTextButtonSecondStyle = new Style(typeof(ShapeTextButton), shapeTextButtonBaseStyle);
            shapeTextButtonSecondStyle.Setters.Add(new Setter(DockPanel.DockProperty, Dock.Right));
            shapeTextButtonSecondStyle.Setters.Add(new Setter(ShapeTextButton.MarginProperty, new Thickness(0, 8, 10, 8)));
            shapeTextButtonSecondStyle.Setters.Add(new Setter(ShapeTextButton.WidthProperty, 24d));
            shapeTextButtonSecondStyle.Setters.Add(new Setter(ShapeTextButton.HeightProperty, 24d));
            shapeTextButtonSecondStyle.Setters.Add(new Setter(ShapeTextButton.GetContentBrush_ForWhichButtonShapePropertyProperty, ButtonShapeProperty.Stroke));
            this.TitleBarUserControl.Resources.Add(typeof(ShapeTextButton), shapeTextButtonSecondStyle);

احتمالا بخاطر اینه که بعد از تغییر استایل ئه App.Current.Resources ، مجددا استایل جدیدی را بر اساس استایل موجود (و استایل تغییر یافته) در App.Current.Resources (برای ShapeTextButton) ساختم .
درسته؟


اما هنوز این سئوال باقی میمونه که پس چرا دقیقا همین قضیه که برای استایل ShapeTextButton که در پنجره ی SettingWindow هم انجام دادم و اونجا با همون کدهای xaml به درستی کار میکنه (و فرضا مثل این نیاز نیست که استایل جدیدی زمان تغییر استایل در App.Current.Resources براش در نظر بگیریم) که ماجراش را در پست قبلی گفتم .

و هنوز این سئوال مطرح هست که مشکل اصلی کجاست که با کد بالا و شیِ جدید دادن به Resource و Style ئه مورد نظر ، مشکل حل میشه و آیا نمیشه کاری کرد که مثل دکمه های ShapeTextButton ای که در SettingWindow وجود دارن ، با کدهای xaml درست بشه و نیاز به شیِ جدید دادن به Resource و Style زمان اجرا و در کدهای سی شارپ نداشته باشه؟

تشکر استاد .
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد ، من این قضیه ای که در بالا گفتم (مشکل تغییر استایل زمانی که از BasedOn استفاده میکنیم) را در یه پروژه ی خیلی کوچیک تر هم تست کردم ، همین مشکل وجود داشت . (اون موقع میگفتین که مشکلات را در مقیاس و در پروژه های کوچیک تر تست کنیم) .

حتی این مشکل برای کنترل های دیگه هم مثل کمبوباکس وجود داشت .
نمیدونم همین قضیه (قضیه ی استفاده از BasedOn در استایل ها) را چرا زمانی که در صفحه ی تنظیمات (در پروژه پشتیبانگیر طلوع) استفاده میکنم ، به درستی کار میکنه اما در صفحات دیگه مثل صفحه ی اصلی (Main Window) استفاده میکنم ، این مشکل را داره که با تغییر استایل (مثلا به Light Style) ، اون کنترل هایی که از استایل دوم و از طریق پروپرتیِ BasedOn تنظیم شدن ، روی همون استایلِ قبلی شون میمونن .

این پروژه ی کوچیک را بازگذاری میکنم اینجا (دکمه ی ضربدر یا close کلیک شه ، باعث تغییر استایل میشه اما استایل هایی که براشون از BasedOn استفاده شده ، تغییر نمیکنن) .
من هنوز متوجه نشدم مشکل از کجاست .

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

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

بعد هم زمانی که استایلی را مینویسیم و کلیدی را براش در نظر نمیگیریم ، کلید پیش فرضش همون نوعِ خودش میشه دیگه .
فرضا استایلی برای Button مینویسیم و کلیدی را براش در نظر نمیگیریم ، کلیدش ، شی ای از نوعِ Type ئه Button میشه دیگه .
درسته؟

در این زمان ، پروپرتیِ Style برای تمامِ دکمه ها ، با اونکه ما ننویسیم شون ، بصورت کد زیر میشه دیگه :

XML:
Style="{StaticResource {x:Type Button}}"

درسته؟

اگه درستن ، خوب این هم که StaticResource هست (یعنی DynamicResource نیست) .
پس نباید با تغییر استایل (فرضا با تغییر به Light Style) ، دکمه مون ، به استایلِ Button ای که در Light Style وجود داره ، تغییر کنه (چون StaticResource هست) .اما بهش تغییر میکنه . چرا؟
تشکر استاد .
 

پیوست ها

  • WpfApp_3.rar
    241.7 کیلوبایت · بازدیدها: 0

SajjadKhati

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

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

بالا