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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
مشکل رو خودتون ایجاد کرده اید، بجای اینکه بر اساس Style کنترل پیش برید، به میل خودتون یک Style ناسازگار طراحی کرده اید که یک TextBox عادی داخلش داره و برای کلید های مکان نما هیچ برنامه ای نداره. در Style پیشفرض کنترل ئه ببینید نوع المنتی که برای PART_TextBox استفاده کرده چیه؟ از نوع TextBox ساده است؟
خیلی ممنون استاد .
بله ، نوعش یه چیز دیگه هست .
توی کلاس UpDownBase ، اتریباتسِ TemplatePart ، نوعش را TextBox مشخص کرده بود ، فکر کردم نوع TextBox بدم ، کفایت میکنه .
حالا بیشتر بررسی میکنم .

بهترین کد یعنی چی؟ بهترین کد تعریف مشخصی داره؟
XML:
<Trigger Property="IsFocused" Value="True">
    <Setter TargetName="tabItemBorder" Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource AncestorType=TabControl}, Path=Foreground}"/>
</Trigger>
خیلی ممنون استاد .
اما بخاطر تشابه خیلی زیاد نام ای که برای Border ها در دو تمپلیتِ نوع TabControl و TabItem گذاشتم ، احتمالا اشتباه متوجه شدین که مقصرش خودممم .
المنتِ tabItemsBorder که گفته بودم ، در تمپلیتِ TabControl تعریف شده . اونی که در تمپلیتِ TabItem تعریف شده ، نامش tabItemBorder هست که خیلی نام گذاریش رو شبیه هم گذاشتم (اونی که در TabControl تعریف شده ، tabItems هست که یه s بیشتر داره) .
الان اگه TargetName مون ، پروپرتیِ tabItemsBorder در تمپلیتِ TabControl باشه ، کاری میشه کرد (به همین روش کدی که شما دادید) یا اینکه با فلگ کردن بشه کاری کرد؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
مشکل رو خودتون ایجاد کرده اید، بجای اینکه بر اساس Style کنترل پیش برید، به میل خودتون یک Style ناسازگار طراحی کرده اید که یک TextBox عادی داخلش داره و برای کلید های مکان نما هیچ برنامه ای نداره. در Style پیشفرض کنترل ئه ببینید نوع المنتی که برای PART_TextBox استفاده کرده چیه؟ از نوع TextBox ساده است؟
استاد ، نوعِ WatermarkTextBox را به عنوان PART_TextBox تعریف کردم .
بکار بردنِ خودِ این نوع ، بصورت پیش فرض ، چیزی را تغییر نمیده و همونه .

توی کدش که برای WatermarkTextBox ، پروپرتی های AutoSelectBehavior و AutoMoveFocus و Watermark و WatermarkTemplate ( براشون TemplateBinding هایی که برای این پروپرتی ها) را تعریف کرد ، همون کد را برای خودم در WatermarkTextBox اش کپی میکنم ، یه عالمه ارور میده .
با ساختار این نوع TemplateBinding آشنا نیستم و نمیدونم چجوری هه .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
اما بخاطر تشابه خیلی زیاد نام ای که برای Border ها در دو تمپلیتِ نوع TabControl و TabItem گذاشتم ، احتمالا اشتباه متوجه شدین که مقصرش خودممم .
المنتِ tabItemsBorder که گفته بودم ، در تمپلیتِ TabControl تعریف شده . اونی که در تمپلیتِ TabItem تعریف شده ، نامش tabItemBorder هست که خیلی نام گذاریش رو شبیه هم گذاشتم (اونی که در TabControl تعریف شده ، tabItems هست که یه s بیشتر داره) .
الان اگه TargetName مون ، پروپرتیِ tabItemsBorder در تمپلیتِ TabControl باشه ، کاری میشه کرد (به همین روش کدی که شما دادید) یا اینکه با فلگ کردن بشه کاری کرد؟
XML:
        <Style x:Key="tabControlStyle" TargetType="{x:Type TabControl}">
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabControl}">
.
.
.
                        <ControlTemplate.Triggers>
.
.
.
                            <Trigger Property="IsKeyboardFocusWithin" Value="True">
                                <Setter TargetName="tabItemsBorder" Property="BorderBrush" Value="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
استاد ، نوعِ WatermarkTextBox را به عنوان PART_TextBox تعریف کردم .
بکار بردنِ خودِ این نوع ، بصورت پیش فرض ، چیزی را تغییر نمیده و همونه .

توی کدش که برای WatermarkTextBox ، پروپرتی های AutoSelectBehavior و AutoMoveFocus و Watermark و WatermarkTemplate ( براشون TemplateBinding هایی که برای این پروپرتی ها) را تعریف کرد ، همون کد را برای خودم در WatermarkTextBox اش کپی میکنم ، یه عالمه ارور میده .
با ساختار این نوع TemplateBinding آشنا نیستم و نمیدونم چجوری هه .
TemplateBinding صرفا به مشخصه های المنت ارجاع میده، بررسی کنید که نوع المنت ControlTemplate و Style رو به درستی مشخص کرده اید و اشاره به فضای نام هم به درستی انجام شده.
در ضمن اگر یک نمونه جدید از کنترل رو روی یک صفحه خالی قرار داده باشید، با راست کلیک کردن رویش و Edit Template و Edit Additional Templates و Edit a Copy احتمالا کد های XAML بهتری از چیزی که خودتون نوشته بودید بدست میاورید که خطا هم نده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
XML:
        <Style x:Key="tabControlStyle" TargetType="{x:Type TabControl}">
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabControl}">
.
.
.
                        <ControlTemplate.Triggers>
.
.
.
                            <Trigger Property="IsKeyboardFocusWithin" Value="True">
                                <Setter TargetName="tabItemsBorder" Property="BorderBrush" Value="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
خیلی ممنون استاد .
این رو هم تست کردم اما IsKeyboardFocusWithin ئه TabControl ، دقیق با هدفم سازگار نیست .
هدفم اینه که فقط وقتی کاربر بتونه آیتم های TabControl را با کیبرد جابجا کنه (تا اینجا که متوجه شدم ، یعنی زمانی که فوکوس روی TabItem هاست) ، BorderBrush ئه tabItemsBorder (که درون تمپلیتِ TabControl تعریف شده) ، رنگش تغییر کنه (آبی بشه) .

اما اگه تریگر رو روی IsKeyboardFocusWithin ئه TabControl بذاریم ، کار بالا را انجام میده . اما علاوه بر اون ، زمانی که کیبرد فوکوس روی المنت های درون محتوای TabControl هست هم باز هم شرط تریگر برقرار هست .

اما من میخوام فقط وقتی که با کیبرد فقط وقتی که بشه انتخاب آیتم های TabControl را با فِلِشِ های کیبرد ، تغییر داد ، فقط در اون صورت تریگرمون اجرا بشه (تا کاربر متوجه بشه در این حالت فوکوس روی اون بخش هست و با کلیدهای فِلِشِ کیبرد میتونه تغییر آیتم بده) .

فکر میکردم اگه روی پروپرتیِ IsKeyboardFocusWithin ئه المنتِ tabItemsBorder یا المنتِ tabItemsPanel (که درون تمپلیت TabControl تعریف شدن) ، تریگر بذارم هم به این هدفم میرسم که انگار این طور نیست .
چیزی که میخوام ، (تا به اینجای کار که متوجه شدم) ، انگار فقط با تریگر گذاشتن روی TabItem انجام میشه .

الان این کار رو که گفتم ، نمیشه انجام داد؟ (یعنی وقتی اون تریگر در TabItem اجرا شد ، بِراش BorderBrush ئه tabItemsBorder (که درون تمپلیتِ TabControl تعریف شده) را تغییر بده) ؟

TemplateBinding صرفا به مشخصه های المنت ارجاع میده، بررسی کنید که نوع المنت ControlTemplate و Style رو به درستی مشخص کرده اید و اشاره به فضای نام هم به درستی انجام شده.
بله درستن .
در ضمن اگر یک نمونه جدید از کنترل رو روی یک صفحه خالی قرار داده باشید، با راست کلیک کردن رویش و Edit Template و Edit Additional Templates و Edit a Copy احتمالا کد های XAML بهتری از چیزی که خودتون نوشته بودید بدست میاورید که خطا هم نده.
خیلی ممنون . تست میکنم ، ببینم چی میشه .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
این رو هم تست کردم اما IsKeyboardFocusWithin ئه TabControl ، دقیق با هدفم سازگار نیست .
هدفم اینه که فقط وقتی کاربر بتونه آیتم های TabControl را با کیبرد جابجا کنه (تا اینجا که متوجه شدم ، یعنی زمانی که فوکوس روی TabItem هاست) ، BorderBrush ئه tabItemsBorder (که درون تمپلیتِ TabControl تعریف شده) ، رنگش تغییر کنه (آبی بشه) .

اما اگه تریگر رو روی IsKeyboardFocusWithin ئه TabControl بذاریم ، کار بالا را انجام میده . اما علاوه بر اون ، زمانی که کیبرد فوکوس روی المنت های درون محتوای TabControl هست هم باز هم شرط تریگر برقرار هست .

اما من میخوام فقط وقتی که با کیبرد فقط وقتی که بشه انتخاب آیتم های TabControl را با فِلِشِ های کیبرد ، تغییر داد ، فقط در اون صورت تریگرمون اجرا بشه (تا کاربر متوجه بشه در این حالت فوکوس روی اون بخش هست و با کلیدهای فِلِشِ کیبرد میتونه تغییر آیتم بده) .

فکر میکردم اگه روی پروپرتیِ IsKeyboardFocusWithin ئه المنتِ tabItemsBorder یا المنتِ tabItemsPanel (که درون تمپلیت TabControl تعریف شدن) ، تریگر بذارم هم به این هدفم میرسم که انگار این طور نیست .
چیزی که میخوام ، (تا به اینجای کار که متوجه شدم) ، انگار فقط با تریگر گذاشتن روی TabItem انجام میشه .

الان این کار رو که گفتم ، نمیشه انجام داد؟ (یعنی وقتی اون تریگر در TabItem اجرا شد ، بِراش BorderBrush ئه tabItemsBorder (که درون تمپلیتِ TabControl تعریف شده) را تغییر بده) ؟
شرط مرکب بذارید :
XML:
<ControlTemplate.Triggers>
<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition SourceName="tabContainerBorder" Property="IsKeyboardFocusWithin" Value="False"/>
        <Condition SourceName="tabItemsPanel" Property="IsKeyboardFocusWithin" Value="True"/>
    </MultiTrigger.Conditions>
    <MultiTrigger.Setters>
        <Setter TargetName="tabItemsBorder" Property="BorderBrush" Value="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"/>
    </MultiTrigger.Setters>
</MultiTrigger>
.
.
.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد . :rose:
استاد ، تمپلیت TabControl آماده شد (در این پست ضمیمه میکنم) .
چک نهایی را کردم ، مشکلی نداشت . اگه وقت کردین ، شما هم چک میکنین که مشکلی اگه داشت ، بهم بگین (از لحاظ padding و alignment و enable و...) (البته اگه وقت دارین) .

تمپلیت ، شبیه TabControl در صفحه ی Preference ئه After Effect 2019 هست .
تشکر استاد :rose:
 

پیوست ها

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد ، این تمپلیت combobox که در زیر میذارم (همون تمپلیت کمبوباکس قبلی) ، یه مشکل کوچیک داره اون هم اینه که وقتی روی کمبوباکس کلیک کردیم (و popup ئه کمبوباکس باز شد) ، حالا وقتی روی کلید tab (در کیبرد) بزنیم ، ممکنه انتخاب ، روی آیتم بعدی در popup نره . در واقع از لحاظ منطقی انتخاب میشه اما فقط ممکنه رسم و شکل ظاهریِ انتخاب انجام نشه .

جالب اینجا هست که همزمان وقتی داریم کلید tab (در کیبرد) را فشار میدیم ، اگه همون زمان ، موس را هم تکون بدیم ، این انتخاب (رسم انتخاب آیتم بعدی در popup) ، بدون مشکل انجام میشه . اما اگه موس را همون لحظه (ای که tab را میزنیم) ، حرکت ندیم ، ممکنه رسم برای آیتم بعدی ، صورت نگیره .

باز هم جالب اینجاست که اگه با کلیدهای فِلِش های کیبرد این کار را کنیم ، بدون مشکل ، آیتم بعدی در popup انتخاب میشه (بدون حرکت موس) .

میدونن مشکل واسه چیه؟ (اگه زحمت داره نمیخواد . مشکل مهمی نیست) .
تشکر استاد :rose:
 

پیوست ها

the_king

مدیرکل انجمن
سلامی مجدد
استاد ، این تمپلیت combobox که در زیر میذارم (همون تمپلیت کمبوباکس قبلی) ، یه مشکل کوچیک داره اون هم اینه که وقتی روی کمبوباکس کلیک کردیم (و popup ئه کمبوباکس باز شد) ، حالا وقتی روی کلید tab (در کیبرد) بزنیم ، ممکنه انتخاب ، روی آیتم بعدی در popup نره . در واقع از لحاظ منطقی انتخاب میشه اما فقط ممکنه رسم و شکل ظاهریِ انتخاب انجام نشه .

جالب اینجا هست که همزمان وقتی داریم کلید tab (در کیبرد) را فشار میدیم ، اگه همون زمان ، موس را هم تکون بدیم ، این انتخاب (رسم انتخاب آیتم بعدی در popup) ، بدون مشکل انجام میشه . اما اگه موس را همون لحظه (ای که tab را میزنیم) ، حرکت ندیم ، ممکنه رسم برای آیتم بعدی ، صورت نگیره .

باز هم جالب اینجاست که اگه با کلیدهای فِلِش های کیبرد این کار را کنیم ، بدون مشکل ، آیتم بعدی در popup انتخاب میشه (بدون حرکت موس) .

میدونن مشکل واسه چیه؟ (اگه زحمت داره نمیخواد . مشکل مهمی نیست) .
تشکر استاد :rose:
این ایراد نیست، کارکرد طبیعی Tab ئه، در Style پیشفرض هم همینه. با Tab دارید Focus رو جابجا می کنید ولی Select نمی کنید، اینکه با جابجا شدن ماوس Select میشه بخاطر قرار گرفتن ماوس روی گزینه است، نه Focus ای که قبلا جابجا کرده اید. آیتم میتونه IsFocused باشه ولی IsSelected نباشه.
اگر تمایل دارید می توانید EventTrigger ای اضافه کنید که وقتی آیتمی صاحب Focus شد، IsSelected اش رو True کنه.
XML:
                <Style TargetType="ComboBoxItem">
                    <Style.Triggers>
                        <EventTrigger RoutedEvent="GotFocus">
                            <BeginStoryboard>
                                <Storyboard>
                                    <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
                                        <DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
                                    </BooleanAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </Style.Triggers>
                </Style>
چرا با EventTrigger و Storyboard نوشتم اش؟ چرا از Trigger برای IsFocused استفاده نمی کنم؟ چون EventTrigger فقط برای وقتی رخداد اتفاق افتاد کاری انجام میده ولی Trigger میخواد هر کاری که در برقراری شرط انجام داده با برقرار نبودن شرط خنثی کنه. ما نمی خواهیم وقتی آیتمی Focus رو از دست داد، تغییری در مقدار IsSelected رخ بده. میخواهیم آیتم همچنان انتخاب شده بمونه.
Trigger وقتی شرط اش نقض میشه، مقداری که در شرایط برقراری شرط خودش با Setter داده بود پس میگیره و به مقدار قبل از اجرای Setter بر میگردونه. یعنی اگر آیتمی رو به دلیل IsFocused انتخاب کرد و IsSelected اش رو True کرد، وقتی Popup بسته شد و Focus رو از دست داد، میخواد IsSelected ای که خودش True کرده بود False کنه. کاری که نمیخواهیم انجام بشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
این ایراد نیست، کارکرد طبیعی Tab ئه، در Style پیشفرض هم همینه. با Tab دارید Focus رو جابجا می کنید ولی Select نمی کنید، اینکه با جابجا شدن ماوس Select میشه بخاطر قرار گرفتن ماوس روی گزینه است، نه Focus ای که قبلا جابجا کرده اید. آیتم میتونه IsFocused باشه ولی IsSelected نباشه.
اگر تمایل دارید می توانید EventTrigger ای اضافه کنید که وقتی آیتمی صاحب Focus شد، IsSelected اش رو True کنه.
XML:
                <Style TargetType="ComboBoxItem">
                    <Style.Triggers>
                        <EventTrigger RoutedEvent="GotFocus">
                            <BeginStoryboard>
                                <Storyboard>
                                    <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
                                        <DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
                                    </BooleanAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </Style.Triggers>
                </Style>
چرا با EventTrigger و Storyboard نوشتم اش؟ چرا از Trigger برای IsFocused استفاده نمی کنم؟ چون EventTrigger فقط برای وقتی رخداد اتفاق افتاد کاری انجام میده ولی Trigger میخواد هر کاری که در برقراری شرط انجام داده با برقرار نبودن شرط خنثی کنه. ما نمی خواهیم وقتی آیتمی Focus رو از دست داد، تغییری در مقدار IsSelected رخ بده. میخواهیم آیتم همچنان انتخاب شده بمونه.
Trigger وقتی شرط اش نقض میشه، مقداری که در شرایط برقراری شرط خودش با Setter داده بود پس میگیره و به مقدار قبل از اجرای Setter بر میگردونه. یعنی اگر آیتمی رو به دلیل IsFocused انتخاب کرد و IsSelected اش رو True کرد، وقتی Popup بسته شد و Focus رو از دست داد، میخواد IsSelected ای که خودش True کرده بود False کنه. کاری که نمیخواهیم انجام بشه.

خیلی ممنون استاد . :rose:
نه استاد . منظورم اینه که همزمان که کلید tab در کیبرد رو میزنیم ، همون زمان ، موس را بیرون از اون کنترل combobox (و popup ئه مربوط به کمبوباکس) حرکت میدیم ، کار میکنه و آیتم های بعدی در popup ئه کمبوباکس ، فوکوس میشن .
در استایل پیش فرض کمبوباکسِ wpf ، مشکلی نیست و در این حالت ، بدون مشکل کار میکنه .


بعد اینکه استاد در کدی که در این پست پیوست میکنم (اگه کد کاملش نیازه ، بقیه ی کدهاش همونی هست که در پست قبلی گذاشته بودم) :

قصد دارم تا پروپرتیِ StrokeThickness شیِ comboboxRectangle که در کلید ComboBoxsToggleButtonTemplate (تگِ ToggleButton) تعریف شد را به پروپرتیِ BorderThickness در کلید ComboBoxStyle (تگِ ComboBox) متصل کنم .
اما Binding ای که برای پروپرتیِ StrokeThickness شیِ comboboxRectangle نوشتم ، کار نمیکنه . چرا و چی کار باید کنم؟

بعد اینکه میتونم Padding ئه کمبوباکس را در ContentSite (که نوعش ContentPresenter هست) ای که در کلید ComboBoxStyle تعریف شد ، binding کنم؟ چون ContentPresenter ، پروپرتیِ Padding نداره (منظورم این نیست که پروپرتیِ Margin ئه ContentPresenter را بجای Padding بکار ببرم) . اگه آره ، چجوری میشه؟

تشکر استاد .
 

پیوست ها

the_king

مدیرکل انجمن
نه استاد . منظورم اینه که همزمان که کلید tab در کیبرد رو میزنیم ، همون زمان ، موس را بیرون از اون کنترل combobox (و popup ئه مربوط به کمبوباکس) حرکت میدیم ، کار میکنه و آیتم های بعدی در popup ئه کمبوباکس ، فوکوس میشن .
خودتونم دارید میگید فوکوس میشه، فوکوس با سلکت شدن فرق داره. دو تا ویژگی جداست، یک آیتم میتونه سلکت شده باشه ولی فوکوس نداشته باشه و برعکس. Tab کاری با Select شدن نداره، وظیفه متعارف Tab و Shift+Tab جابجا کردن فوکوس ئه، نه سلکت. اینکه آیتمی Focus بگیره معنی اش این نیست که Select هم شده.

در استایل پیش فرض کمبوباکسِ wpf ، مشکلی نیست و در این حالت ، بدون مشکل کار میکنه .
من در ComboBox با Style پیشفرض هم با Tab صرفا Focus رو روی آیتم بعدی میبرم، آیتم قبلی همچنان Select شده میمونه، فقط Focus رو از دست میده، اون نقطه چین اطراف آیتم مربوط به Focus ئه، نه Select شدن.

بعد اینکه استاد در کدی که در این پست پیوست میکنم (اگه کد کاملش نیازه ، بقیه ی کدهاش همونی هست که در پست قبلی گذاشته بودم) :

قصد دارم تا پروپرتیِ StrokeThickness شیِ comboboxRectangle که در کلید ComboBoxsToggleButtonTemplate (تگِ ToggleButton) تعریف شد را به پروپرتیِ BorderThickness در کلید ComboBoxStyle (تگِ ComboBox) متصل کنم .
اما Binding ای که برای پروپرتیِ StrokeThickness شیِ comboboxRectangle نوشتم ، کار نمیکنه . چرا و چی کار باید کنم؟
برای دلیل مشکل نوع داده StrokeThickness و BorderThickness رو مقایسه کنید. یا برای Binding از مقدار هم نوع اش مثلا BorderThickness.Left استفاده کنید، یا یک Converter اختصاصی کد نویسی کنید که تبدیلش کنه و برای Binding اون Converter رو معرفی کنید. فکر کنم روش اول رو انتخاب کنید.

بعد اینکه میتونم Padding ئه کمبوباکس را در ContentSite (که نوعش ContentPresenter هست) ای که در کلید ComboBoxStyle تعریف شد ، binding کنم؟ چون ContentPresenter ، پروپرتیِ Padding نداره (منظورم این نیست که پروپرتیِ Margin ئه ContentPresenter را بجای Padding بکار ببرم) . اگه آره ، چجوری میشه؟
شما میخواهید برای Content ای Padding در نظر بگیرید در حالی که نمیدونید Content چیه و از Padding میتونه استفاده بکنه یا نه. Content یک object ئه، Padding برای هر object ای معنی نداره. شما که نمیدونید Content قراره چی نوعی باشه، بجای اینکار مثلا یک المنت Grid برای والد اون ContentPresenter در نظر بگیرید که احاطه اش کنه و Grid ئه Margin دلخواه شما رو داشته باشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
در ضمن اگر یک نمونه جدید از کنترل رو روی یک صفحه خالی قرار داده باشید، با راست کلیک کردن رویش و Edit Template و Edit Additional Templates و Edit a Copy احتمالا کد های XAML بهتری از چیزی که خودتون نوشته بودید بدست میاورید که خطا هم نده.
خیلی ممنون استاد :rose:
زودتر یادآوری میکردین استاد ها :)
نمیدونم چرا به فکر خودم نرسید .

استاد ، تمپلیت زیر را برای DoubleUpDown درست کردم (که کدش را در زیر پیوست میکنم) .
قسمت سمت راست کنترل که شکل فِلِش (بالا و پایین) گذاشتم ، توی xaml desinger که میبینم ، دقیقا هر دو یکسان و دقیق اندازه ی هم هستن اما زمان اجرای برنامه ، نمیدونم خطای دید من هست که حس میکنم ارتفاعِ فِلِش بالا ، کمتره یا واقعا این طوره .
در صورتی که طبق کد زیر (بخشی از کدی که پیوست شد ، که به این قضیه ی اندازه ی فلش ها ربط داره) :

XML:
                                <Grid x:Name="gridContent" Grid.Column="1" Width="23">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*"/>
                                        <RowDefinition Height="*"/>
                                    </Grid.RowDefinitions>

                                    <RepeatButton x:Name="PART_IncreaseButton" Content="M 0 5 L 5 0 L 10 5" IsTabStop="{TemplateBinding IsTabStop}" Style="{StaticResource UpDownSpinerButtonStyle}" Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type ToolKit:DoubleUpDown}, Mode=FindAncestor}, Path=Foreground}"/>
                                    <RepeatButton x:Name="PART_DecreaseButton" Grid.Row="1" Content="M 0 0 L 5 5 L 10 0" IsTabStop="{TemplateBinding IsTabStop}" Style="{StaticResource UpDownSpinerButtonStyle}" Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type ToolKit:DoubleUpDown}, Mode=FindAncestor}, Path=Foreground}"/>
                                </Grid>
هم ارتفاع Grid درست و یکسان به دو قسمت مساوی تقسیم شد و هم در Data ی شکل رسم شده (که Content ئه RepeatButton در کد بالا هست) ، ارتفاع هر دو شکل ، 5 و پهناشون هم 10 هست .
تشکر استاد
 

پیوست ها

the_king

مدیرکل انجمن
قسمت سمت راست کنترل که شکل فِلِش (بالا و پایین) گذاشتم ، توی xaml desinger که میبینم ، دقیقا هر دو یکسان و دقیق اندازه ی هم هستن اما زمان اجرای برنامه ، نمیدونم خطای دید من هست که حس میکنم ارتفاعِ فِلِش بالا ، کمتره یا واقعا این طوره .
ابعاد Align میشه به نقطه ها، تا خطوط محو دیده نشن و شارپ باشن.
ارتفاع شیء 5 ئه، فرد ئه، اگر در فضایی با ارتفاع زوج مثلا 20 قرار بگیره میخواد از دو طرف فاصله مساوی بگیره، باید مقدار فرد 5-20 یعنی 15 بین بالا و پایین تقسیم بشه که در رسم 7.5 نمیشه، یک طرف 7 نقطه فاصله میگیره و یک طرف 8 نقطه. حالا وقتی خود فضای 20 حاصل تقسیم یک ارتفاع فرد 41 بین دو بخش بالا و پایین باشه دیگه بدتر، در رسم 20.5 نمیشن، به یکی شون 20 میرسه و به یکی شون 21.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ابعاد Align میشه به نقطه ها، تا خطوط محو دیده نشن و شارپ باشن.
ارتفاع شیء 5 ئه، فرد ئه، اگر در فضایی با ارتفاع زوج مثلا 20 قرار بگیره میخواد از دو طرف فاصله مساوی بگیره، باید مقدار فرد 5-20 یعنی 15 بین بالا و پایین تقسیم بشه که در رسم 7.5 نمیشه، یک طرف 7 نقطه فاصله میگیره و یک طرف 8 نقطه. حالا وقتی خود فضای 20 حاصل تقسیم یک ارتفاع فرد 41 بین دو بخش بالا و پایین باشه دیگه بدتر، در رسم 20.5 نمیشن، به یکی شون 20 میرسه و به یکی شون 21.
خیلی ممنون استاد .
متوجه شدم اما نه خیلی کامل .
نمیدونم چرا نمیتونه به دو قسمت مساوی تقسیم کنه . و نمیدونم چرا زمان xaml designer که نشون میده ، هیچ مشکلی نداره و از همه جالب تر اینکه همین کد رو توی template ئه قبلیِ DoubleUpDown (که خودم همه شو نوشته بودم و از استایل پیش فرض اش را ویرایش نکرده بودم و همونطور که میدونید و قبلا گفته بودم که مشکل فوکوس کیبرد داشت) استفاده کرده بودم اما زمان اجرا ، این مشکل را نداشت .
از UniformGrid بجای اون Grid (در کد پست قبلی) استفاده کردم ، اما باز هم همین مشکل را داره .

الان باید برای رفع مشکل این قضیه ، دقیقا چی کار کنم؟
اون Grid که 2 تا سطر داره (در کد پست قبلی) ، فکر نکنم مشکلی داشته باشه . داره؟ ارتفاع این Grid هه که مشکل ایجاد میکنه یا ارتفاع RepeatButton ها؟
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
متوجه شدم اما نه خیلی کامل .
نمیدونم چرا نمیتونه به دو قسمت مساوی تقسیم کنه . و نمیدونم چرا زمان xaml designer که نشون میده ، هیچ مشکلی نداره و از همه جالب تر اینکه همین کد رو توی template ئه قبلیِ DoubleUpDown (که خودم همه شو نوشته بودم و از استایل پیش فرض اش را ویرایش نکرده بودم و همونطور که میدونید و قبلا گفته بودم که مشکل فوکوس کیبرد داشت) استفاده کرده بودم اما زمان اجرا ، این مشکل را نداشت .
از UniformGrid بجای اون Grid (در کد پست قبلی) استفاده کردم ، اما باز هم همین مشکل را داره .
تنظیمات زوم designer رو چک کنید.
شما می توانید به دو قسمت مساوی تقسیمش کنید؟ این فلش 5x3 رو طوری در این ناحیه 6x6 قرار بدهید که فاصله از چپ و راست (یا بالا و پایین) برابر باشه؟
center.png
الان باید برای رفع مشکل این قضیه ، دقیقا چی کار کنم؟
اگر نظر من رو بخواهید، هیچ کاری. صرفا برای حفظ تناسب موقع استفاده ازشون ابعاد روی طوری مشخص کنید که در تقسیم باقیمانده اعشاری نداشته باشه، وگرنه بدیهی است که فرضا 3 پیکسل رو نمیشه به دو قسمت 1.5 پیکسلی تقسیم کرد، نصف پیکسل که نداریم، یک طرف 1 پیکسل میشه و طرف دیگه 2 پیکسل.

اون Grid که 2 تا سطر داره (در کد پست قبلی) ، فکر نکنم مشکلی داشته باشه . داره؟ ارتفاع این Grid هه که مشکل ایجاد میکنه یا ارتفاع RepeatButton ها؟
هیچ کدوم مشکلی ندارند، مساله نحوه رندر کردن رسم ئه. ظاهر یک المنت با طول 4.5 باید چه فرقی با ظاهر المنتی با طول 4 یا 5 داشته باشه؟ اگر بخواد اون 0.5 رو دخالت بده کادرش محو دیده میشه، بد دیده میشه. همون بهتر که یک پیکسل کم یا زیاد بشه ولی شارپ بمونه.
XML:
        <Border SnapsToDevicePixels="True" Width="4" Height="4" Margin="10,20" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Blue" BorderThickness="1"/>
        <Border SnapsToDevicePixels="True" Width="4" Height="5" Margin="20,20" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Blue" BorderThickness="1"/>
        <Border SnapsToDevicePixels="False" Width="4.5" Height="4.5" Margin="30,20" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Blue" BorderThickness="1"/>
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
تنظیمات زوم designer رو چک کنید.
شما می توانید به دو قسمت مساوی تقسیمش کنید؟ این فلش 5x3 رو طوری در این ناحیه 6x6 قرار بدهید که فاصله از چپ و راست (یا بالا و پایین) برابر باشه؟
مشاهده پیوست 113610

اگر نظر من رو بخواهید، هیچ کاری. صرفا برای حفظ تناسب موقع استفاده ازشون ابعاد روی طوری مشخص کنید که در تقسیم باقیمانده اعشاری نداشته باشه، وگرنه بدیهی است که فرضا 3 پیکسل رو نمیشه به دو قسمت 1.5 پیکسلی تقسیم کرد، نصف پیکسل که نداریم، یک طرف 1 پیکسل میشه و طرف دیگه 2 پیکسل.


هیچ کدوم مشکلی ندارند، مساله نحوه رندر کردن رسم ئه. ظاهر یک المنت با طول 4.5 باید چه فرقی با ظاهر المنتی با طول 4 یا 5 داشته باشه؟ اگر بخواد اون 0.5 رو دخالت بده کادرش محو دیده میشه، بد دیده میشه. همون بهتر که یک پیکسل کم یا زیاد بشه ولی شارپ بمونه.
XML:
        <Border SnapsToDevicePixels="True" Width="4" Height="4" Margin="10,20" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Blue" BorderThickness="1"/>
        <Border SnapsToDevicePixels="True" Width="4" Height="5" Margin="20,20" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Blue" BorderThickness="1"/>
        <Border SnapsToDevicePixels="False" Width="4.5" Height="4.5" Margin="30,20" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Blue" BorderThickness="1"/>
خیلی ممنون استاد .
پس چرا کد قبلی (که مشکل فوکوس داشت و قبلا کدش را داده بودم) ، همچین مشکلی نداره؟ (همین رسمِ فِلِش با همین ابعاد هه . خودِ شیِ کنترلِ DoubleUpDown اش هم همین ابعاد هه ) .
بعد اینکه پس چجوری هه که توی thickness و اینها ، میشه چند دهم (حالا نمیدونم پیکسل واحدشونه یا چه چیزی دقیقا) هم میشه داد؟
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
پس چرا کد قبلی (که مشکل فوکوس داشت و قبلا کدش را داده بودم) ، همچین مشکلی نداره؟ (همین رسمِ فِلِش با همین ابعاد هه . خودِ شیِ کنترلِ DoubleUpDown اش هم همین ابعاد هه ) .
نظرم رو گفتم، مشکلی نداره. چرا سوالاتی که من ازتون می کنم رو جواب نمیدید؟
بعد اینکه پس چجوری هه که توی thickness و اینها ، میشه چند دهم (حالا نمیدونم پیکسل واحدشونه یا چه چیزی دقیقا) هم میشه داد؟
همونجوریه که Width و Height رو هم بصورت اعشاری مشخص می کنید، ولی تعداد پیکسل رو صفحه نمایش که اعشاری نمیشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نظرم رو گفتم، مشکلی نداره. چرا سوالاتی که من ازتون می کنم رو جواب نمیدید؟
خیلی ممنون استاد . :rose:
اگه منظورتون قضیه ی شکلی که در پست 434 پرسیدید هست ، خوب سئوال تون استفهامی بود و من هم چون متوجه اش شدم ، دیگه لازم به جواب نبود دیگه .

همونجوریه که Width و Height رو هم بصورت اعشاری مشخص می کنید، ولی تعداد پیکسل رو صفحه نمایش که اعشاری نمیشه.
width و height اش را عدد فرد میدادم ، درست میشد .
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
در مورد محدوده دسترسی اسامی داخل ControlTemplate که قبلا صحبت کرده ایم و نیازی به تکرارشون نیست.
قضیه باید برعکس باشه، این ControlTemplate ئه که باید در هنگام توصیف مقادیری رو از Style بگیره، نه اینکه Style بخواد ControlTemplate رو زیر و رو کنه تا مقدار بخشی اش رو ویرایش کنه. شما ControlTemplate رو کجا توصیف می کنید؟ همونجا مقادیر لازم رو بهش بدهید، نه اینکه اول توصیف اش کنید و بعد به فکر این باشید که چطور میشه توسط Style دستکاری اش کرد.
شما می توانید برای اون مقادیر Resource تعریف کنید، مثلا MyBackground، خیلی ساده.
XML:
    <Style x:Key="DarkStyle">
        <Style.Resources>
            <Style TargetType="CheckBox">
                <Setter Property="Template" Value="{DynamicResource checkBoxCustTemplate}"/>
                <Style.Resources>
                    <SolidColorBrush x:Key="MyBackground" Color="Black"/>
                </Style.Resources>
            </Style>
        </Style.Resources>
    </Style>

    <Style x:Key="LightStyle">
        <Style.Resources>
            <Style TargetType="CheckBox">
                <Setter Property="Template" Value="{DynamicResource checkBoxCustTemplate}"/>
                <Style.Resources>
                    <SolidColorBrush x:Key="MyBackground" Color="LightGray"/>
                </Style.Resources>
            </Style>
        </Style.Resources>
    </Style>
XML:
<Border Name="checkBorder" Background="{DynamicResource ResourceKey=MyBackground}" ...
سلامی مجدد استاد .
استاد ، الان توی این قضیه ی استایل ، اگه قرار باشه در تمپلیت ها ، بصورت DynamicResource ، به منبع مون متصل بشیم ، خوب چه نیازی هست که اون منبع (MyBackground در مثال بالا) را دوبار بنویسیم؟
در این صورت ، اون منبع (MyBackground) را یه بار مینویسیم و در زمان اجرا ، مقدارش را تغییر میدیم دیگه (البته چون همه ی استایل و تمپلیت و بِراش ها آماده هست ، تمایل چندانی به تغییر بِراش ها و استایل ها در زمان اجرا ندارم) (تا حد امکان ، میخوام منابع هام مثل تمپلیت و بِراش و استایل و اینها ، دوبار ، کپی نشن) .

روشی ندارین که بشه از StaticResource استفاده کرد؟
چون من همه ی تمپلیت ام را با StaticResource به منبع ام (Brush ها) متصل کردم .
البته یه روش هست (برای استفاده از StaticResource) که همه ی کدها (به همراه کل تمپلیت ها) را دوبار کپی کنم که یکی از تمپلیت ها ، منابعِ Brush با یک رنگ و تمپلیت دیگه ، منابعِ Brush با رنگِ دیگه ای را داشته باشن .
ولی چون تمپلیتِ هر دو استایل ، یکی هست ، کپی کردنش ، شاید کار ویرایش دفعات بعد را سخت کنه و اصولی نباشه .

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

the_king

مدیرکل انجمن
سلامی مجدد استاد .
استاد ، الان توی این قضیه ی استایل ، اگه قرار باشه در تمپلیت ها ، بصورت DynamicResource ، به منبع مون متصل بشیم ، خوب چه نیازی هست که اون منبع (MyBackground در مثال بالا) را دوبار بنویسیم؟
نیازش رو شما ایجاد کردید، نه من. من به جای شما تصمیم بگیرم نیازی هست یا نیست؟ اگر DarkStyle و LightStyle در رنگ ها با هم فرقی ندارند که دلیلی نداره DarkStyle و LightStyle ای داشته باشید، فقط یک Style می سازید که کاربر به انتخاب خودش برای رنگ ها تصمیم میگیره، اما اگر رنگ های متفاوتی رو بکار می برند، بالاخره در یکجایی باید دو تا رنگ متفاوت رو یک المنت مشابه اعمال کنید، اگر در Style ای رنگی Black میشه و در Style دیگری LightGray میشه دو تا کد مشابه میخواد که یک کار یکسان رو با دو مقدار متفاوت انجام بدن. اگر سه تا Style باشه سه تا کد تکراری میخواد. اگر چهار تا Style باشه چهار تا کد تکراری می خواد. در ضمن با کلاس سازی می توانید برای این رنگ بندی ها مفاهیم بهتری طراحی کنید.

در این صورت ، اون منبع (MyBackground) را یه بار مینویسیم و در زمان اجرا ، مقدارش را تغییر میدیم دیگه (البته چون همه ی استایل و تمپلیت و بِراش ها آماده هست ، تمایل چندانی به تغییر بِراش ها و استایل ها در زمان اجرا ندارم) (تا حد امکان ، میخوام منابع هام مثل تمپلیت و بِراش و استایل و اینها ، دوبار ، کپی نشن) .
اگر کاربر این Style فقط خودتون هستید هر کاری که دلتون خواست انجام بدهید، اما اگر قرار بر این هست که کاربران دیگری ازش استفاده کنند دیگه تمایل شما ملاک نیست.

روشی ندارین که بشه از StaticResource استفاده کرد؟
چون من همه ی تمپلیت ام را با StaticResource به منبع ام (Brush ها) متصل کردم .
اگر قراره مقدار Resource ها قابل تغییر باشه کار اشتباهی انجام داده اید و می توانید StaticResource ها رو به سادگی ویرایش کنید.

البته یه روش هست (برای استفاده از StaticResource) که همه ی کدها (به همراه کل تمپلیت ها) را دوبار کپی کنم که یکی از تمپلیت ها ، منابعِ Brush با یک رنگ و تمپلیت دیگه ، منابعِ Brush با رنگِ دیگه ای را داشته باشن .
ولی چون تمپلیتِ هر دو استایل ، یکی هست ، کپی کردنش ، شاید کار ویرایش دفعات بعد را سخت کنه و اصولی نباشه .
کد Template مشابه رو دیگه برای چی کپی کنید؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نیازش رو شما ایجاد کردید، نه من. من به جای شما تصمیم بگیرم نیازی هست یا نیست؟ اگر DarkStyle و LightStyle در رنگ ها با هم فرقی ندارند که دلیلی نداره DarkStyle و LightStyle ای داشته باشید، فقط یک Style می سازید که کاربر به انتخاب خودش برای رنگ ها تصمیم میگیره، اما اگر رنگ های متفاوتی رو بکار می برند، بالاخره در یکجایی باید دو تا رنگ متفاوت رو یک المنت مشابه اعمال کنید، اگر در Style ای رنگی Black میشه و در Style دیگری LightGray میشه دو تا کد مشابه میخواد که یک کار یکسان رو با دو مقدار متفاوت انجام بدن. اگر سه تا Style باشه سه تا کد تکراری میخواد. اگر چهار تا Style باشه چهار تا کد تکراری می خواد. در ضمن با کلاس سازی می توانید برای این رنگ بندی ها مفاهیم بهتری طراحی کنید.


اگر کاربر این Style فقط خودتون هستید هر کاری که دلتون خواست انجام بدهید، اما اگر قرار بر این هست که کاربران دیگری ازش استفاده کنند دیگه تمایل شما ملاک نیست.


اگر قراره مقدار Resource ها قابل تغییر باشه کار اشتباهی انجام داده اید و می توانید StaticResource ها رو به سادگی ویرایش کنید.


کد Template مشابه رو دیگه برای چی کپی کنید؟
خیلی ممنون استاد .
پس پیشنهادتون اینه که کلا همه را بصورت DynamicResource به منابع متصل کنم؟
اما DynamicResource ، نسبت به StaticResource ، منابع سخت افزاری بیشتری را درگیر نمیکنه؟
اگه آره ، تا حدودا چقدر درگیر میکنه؟ و چند درصد در کاهش کارایی و سرعت برنامه مون تاثیر میذاره؟

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

راستی استاد ، DynamicResource را نمیذاره برای پروپرتی Value ئه Setter ، سِت کنیم .
پس کلا مجبورم از StaticResource استفاده کنم دیگه . درسته؟
 
آخرین ویرایش:

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

بالا