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

the_king

مدیرکل انجمن
در استایلی که من کد نویسی کردم زمینه آیتم بصورت کامل رنگ شده بود، یا سفید بود یا آبی. فضای خالی نداشت که بگید Style ئه TabItem پوشش نداد.
اول اینکه کنترل هایی که دارای آیتم هستند (مثل combobox و TabControl و ...) ، دارای بخشی بنام TabItem هستند .
فتوای جدید ئه که ComboBox باید TabItem داشته باشه؟ در ComboBox Styles and Templates ئه TabItem هست؟

و پروپرتی ای بنام ItemContainerStyle دارند که میشه بهش استایل داد (و بنابراین Template هم میشه داد) که این استایل و تمپلیت ، استایل و شکل بخش آیتم ها را مشخص میکنه . در واقع ، وقتی به ItemContainerStyle ، استایل و تمپلیست میدیم ، اولا فقط در حیطه ی یک آیتم اِعمال میشه (یعنی این جور نیست که وقتی یه Grid ای در استایل و تمپلیتِ مربوط به ItemContainerStyle رسم میکنیم ، کلِ آیتم های موجود را شامل بشه و به اندازه ی کل آیتم های اون کنترل بشه . بلکه فقط به اندازه ی یک آیتم هست) و دوما ، استایل ای که دادیم ، استایلِ همه ی آیتم های موجود خواهد شد . یعنی همه ی آیتم ها ، اون استایل را برای خودشون رسم میکنن .
ItemContainerStyle جزئی از ItemsControl ئه، پس هر کلاسی که وارث ItemsControl باشه ItemContainerStyle داره. کاری به این نداریم که چی آیتم داره و چی نداره، اصل قضیه اینه که وارث ItemsControl باشه.
ItemsControl موقع ایجاد آیتم ها از ItemContainerStyle به عنوان Style استفاده می کنه، Style ئه یک آیتم خاص نیست، یک Style مستقل ئه که ممکنه صد تا آیتم ازش استفاده کنند.

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

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

یا اگه بخوایم دورِ کلِ آیتم های این کنترل ها (کنترل TabControl یا combobox) ، یه border رسم کنیم ، باز هم توسط پروپرتیِ ItemContainerStyle نمیشه و باید توسط پروپرتیِ Template یا پروپرتیِ Style مربوط به این کنترل ها ، این کار را انجام بدیم .
بله، TabItem برای فضای داخل تک تک آیتم ها است، فضای اطراف مجموعه اش رو پوشش نمیده. اون یک TabPanel ئه که TabItem ها داخلش قرار گرفته.

دوم اینکه پروپرتیِ Template ای که در کنترل ها هست ، باعث میشه کلِ اون کنترل را از نو رسم کنیم . اما همونطور که در نکته ی اول گفتم ، پروپرتیِ ItemContainerStyle ئه مربوط به اون کنترل ، باعث میشه استایل و تمپلیت هایی که فقط مربوط به بخش آیتم های اون کنترل هستند را رسم کنیم .
بله.

سوم اینکه در کنترل TabControl ، هر TabItem ، پروپرتی ای بنام Template و Style داره که بصورت اختصاصی میتونیم فقط استایل های مربوط به همون TabItem را تغییر بدیم (برخلاف پروپرتیِ ItemContainerStyle ئه TabControl که باهاش همه ی TabItem را میتونیم با هم به یک شکل ، استایل بدیم) .
بنابراین پروپرتی Template و Style ئه مربوط به TabItem ها ، زمانی به درد میخوره که بخوایم استایل یه آیتم خاص را تغییر بدیم . مثلا یه آیتم ، اندازه ی پیش فرض اش نسبت به بقیه ی آیتم ها بزرگ تر باشه یا هر تغییر دیگه ای .
بله.

چهارم اینکه در کنترل TabControl ها ، TabItem ، فقط بخشِ قسمتِ بالایی (سربرگ ها) را میگن (یعنی فقط بخشی که بصورت پیش فرض متن شون ، TabItem نوشته هست) . یعنی بخش محتوای TabControl (که داخل هر کدوم از صفحات شون ، کنترل های مختلف مون را قرار میدیم) ، جزء TabItem ها به حساب نمیان.
بله، ContentPresenter ربطی به ControlTemplate ئه TabItem ها نداره و در ControlTemplate ئه خود TabControl توصیف شده.

اولا ContentPresenter ، لازم نیست که فقط برای کنترل هایی از نوع ContentControl بکار برده بشه . چون ContentPresenter که در کد بالا (برای Border) اومد ، اون Border که از نوع ContentControl نیست.
نمیفهمم چی میگید، حرف شما اینه که اگر در Content تگ <Border> نوشته بشه <ContentPresenter> اشکالی نداره و لازم نیست که حتما Border یک ContentControl باشه. حرفتون درسته ولی اصلا بود و نبود ContentPresenter ربطی به خود Border نداره، شما دارید برای TabItem که یک ContentControl ئه کد توصیفی می نویسید. Border یک المنت رو به عنوان فرزند قبول می کنه که داخلش نشون بده، چه ContentPresenter باشه چه چیز دیگری فرقی بحال Border نمیکنه. ContentPresenter کاری به این نداره که داخل چی قرار گرفته، Border باشه یا Grid یا اصلا هیچی. وجود اون ContentPresenter از اونجا معنی داره که در توصیف TabItem ئه، در توصیف یک ContentControl ئه. به Border ربطی نداره.

دوما ، پروپرتی ContentSource مربوط به ContentControl ، یعنی اینکه نام پروپرتی ای را بهش بدیم که محتوای اون را نشون بده؟ اینه قضیه اش؟
اگه اینه ، پس در کد اول که ContentSource="SelectedContent" هست ، اون SelectedContent چیه و از کجا آورد؟
اگه این نیست ، پس در کد دوم که ContentSource="Header" هست ، منظورش همون Header ئه مربوط به هر TabItem هه دیگه ؟ (چون نوع ControlTemplate مون ، TabItem هست دیگه) .
ContentSource مربوط به ContentControl نیست، مربوط به خود ContentPresenter ئه. میتونه محتواش اسم فیلد یا پروپرتی یا المنت خاصی باشه اما از نظر فنی نام چیز خاصی نیست، صرفا یک رشته string ئه، فقط یک پیشوند نام ئه. برای نامگذاری محتویات ContentPresenter ئه بکار برده میشه. شرح اش رو در سایت مایکروسافت بخونید.
 

SajjadKhati

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

خیلی ممنون استاد :rose:
در کدی که شما دادید ، جواب یک سئوالم بود . (تغییر آیتم ها) .
اما علاوه بر اون ، من تغییرِ پشت زمینه ی بخشی که آیتم ها قرار دارند (نه اینکه خود آیتم ها تغییر رنگ بدن که این ، سئوال قبلی ام بود) را میخواستم که نبود (با تغییر رنگ کنترل والد که grid هست ، رنگ اون بخش از کنترل TabControl که آیتم ها توش قرار دارند و Transparent هست ، تغییر میکنه که در تصویر زیر ، در قسمتی از TabControl که رنگ سبز هست ، مشخص هه) :

1.JPG

فتوای جدید ئه که ComboBox باید TabItem داشته باشه؟ در ComboBox Styles and Templates ئه TabItem هست؟

گفتم TabItem !! :green:
منظورم Item بود .
یعنی کلا کنترل های آیتم دار ، همونطور که از اسمشون مشخص هه ، دارای Item هستند . چون از ItemControl ارث بری میکنن (همونطور که در پایین اشاره کردین)

ItemContainerStyle جزئی از ItemsControl ئه، پس هر کلاسی که وارث ItemsControl باشه ItemContainerStyle داره. کاری به این نداریم که چی آیتم داره و چی نداره، اصل قضیه اینه که وارث ItemsControl باشه.
ItemsControl موقع ایجاد آیتم ها از ItemContainerStyle به عنوان Style استفاده می کنه، Style ئه یک آیتم خاص نیست، یک Style مستقل ئه که ممکنه صد تا آیتم ازش استفاده کنند.

بله .
من هم همین رو گفتم . که استایل ItemContainerStyle ، استایلِ یک آیتمِ خاص نیست و مربوط به همه ی آیتم هاست .

بدیهی است که جایی که محل TabItem نیست ربطی به Style ئه TabItem نداره.


پایین آیتم با پشت آیتم دو موقعیت مکانی جدا است، وقتی یک آیتمی فرضا رنگش سفید ئه، پشت اش قرمز هم باشه همچنان رنگ سفید دیده میشه، نه قرمز. اگر رنگش هم بکنید دیده نمیشه. پایین آیتم هم که اصلا جزئی از کادر آیتم ها نیست.

خیلی ممنون .

بله، TabItem برای فضای داخل تک تک آیتم ها است، فضای اطراف مجموعه اش رو پوشش نمیده. اون یک TabPanel ئه که TabItem ها داخلش قرار گرفته.

بله .
منظور من هم همین بود .

بله.


بله.


بله، ContentPresenter ربطی به ControlTemplate ئه TabItem ها نداره و در ControlTemplate ئه خود TabControl توصیف شده.

ممنون

نمیفهمم چی میگید، حرف شما اینه که اگر در Content تگ <Border> نوشته بشه <ContentPresenter> اشکالی نداره و لازم نیست که حتما Border یک ContentControl باشه. حرفتون درسته ولی اصلا بود و نبود ContentPresenter ربطی به خود Border نداره، شما دارید برای TabItem که یک ContentControl ئه کد توصیفی می نویسید. Border یک المنت رو به عنوان فرزند قبول می کنه که داخلش نشون بده، چه ContentPresenter باشه چه چیز دیگری فرقی بحال Border نمیکنه. ContentPresenter کاری به این نداره که داخل چی قرار گرفته، Border باشه یا Grid یا اصلا هیچی. وجود اون ContentPresenter از اونجا معنی داره که در توصیف TabItem ئه، در توصیف یک ContentControl ئه. به Border ربطی نداره.

آها . متوجه شدم . خیلی ممنون .
پس هر جا ContentPresenter نوشته شد (یا کلا هر چیزی که Content داره مثل ScrollContentPresenter و ...) ، حتی داخل بقیه ی کنترل ها نوشته شد ، ربطی به اون کنترل نداره . بلکه به اون کنترلی که براش تمپلیت نوشتیم (در این مثال ، برای کنترل TabItem نوشتیم) ، ربط داره . و به طبع ، اون کنترل (TabItem) باید از نوع ContentControl باشه .

ContentSource مربوط به ContentControl نیست، مربوط به خود ContentPresenter ئه. میتونه محتواش اسم فیلد یا پروپرتی یا المنت خاصی باشه اما از نظر فنی نام چیز خاصی نیست، صرفا یک رشته string ئه، فقط یک پیشوند نام ئه. برای نامگذاری محتویات ContentPresenter ئه بکار برده میشه. شرح اش رو در سایت مایکروسافت بخونید.

بله . باز هم اشتباه نوشتم . منظورم ContentSource مربوط به ContentPresenter . اشتباهی ، بجای ContentPresenter ، نوشتم ContentControl .
انگار SelectedContent ، مربوط به TabControl هست :

TabControl.SelectedContent Property (System.Windows.Controls)

پس درسته دیگه .
مقدار ContentSource ای که باید بدیم ، مربوط به نام اون عضو (پروپرتی یا فیلد) از نوعی میشه که براش استایل یا تمپلیت (در اینجا ، در کد اول ، نوع TabControl و در کد دوم ، نوع TabItem) نوشتیم .
خیلی ممنون استاد .
 

SajjadKhati

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

کد:
            <Style x:Key="SimpleTabControl" TargetType="{x:Type TabControl}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TabControl}">
                            <Grid KeyboardNavigation.TabNavigation="Local">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>

                                <!-- TabPanel is a layout container which allows the TabItems to wrap and re-order when selected
                        The implementation knows to use this control because it is marked IsItemsHost = True -->
                                <Border Grid.Row="0" BorderBrush="Red" BorderThickness="1"/>
                                <TabPanel Grid.Row="0" Margin="0,0,4,-1" x:Name="HeaderPanel" Background="Transparent" IsItemsHost="True" Panel.ZIndex="1" KeyboardNavigation.TabIndex="1"/>

                                <Border Grid.Row="1" x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="2" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.TabIndex="2">

                                    <!-- The implementation switches the content. This control must be named PART_SelectedContentHost -->
                                    <ContentPresenter Margin="4" x:Name="PART_SelectedContentHost" ContentSource="SelectedContent"/>

                                </Border>
                            </Grid>

                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
                                    <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
                                </Trigger>
                            </ControlTemplate.Triggers>

                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

و کد دوم :

کد:
            <Style x:Key="SimpleTabControl" TargetType="{x:Type TabControl}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TabControl}">
                            <Grid KeyboardNavigation.TabNavigation="Local">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>

                                <!-- TabPanel is a layout container which allows the TabItems to wrap and re-order when selected
                        The implementation knows to use this control because it is marked IsItemsHost = True -->
                                <Border Grid.Row="0" BorderBrush="Red" BorderThickness="1"/>
                                <TabPanel Grid.Row="0" Margin="0,0,4,-1" x:Name="HeaderPanel" Background="Transparent" IsItemsHost="True" Panel.ZIndex="1" KeyboardNavigation.TabIndex="1"/>

                                <Border Grid.Row="1" x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="2" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.TabIndex="2">


                                </Border>

                                <!-- The implementation switches the content. This control must be named PART_SelectedContentHost -->
                                <ContentPresenter Margin="4" x:Name="PART_SelectedContentHost" ContentSource="SelectedContent"/>

                            </Grid>

                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
                                    <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
                                </Trigger>
                            </ControlTemplate.Triggers>

                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

تغییرش هم فقط اینه که اون ContentPresenter را از داخل (فرزند بودنِ) Border جدا کردم و مستقیما فرزند Grid (که فرزند TabControl هست) (فرزند ، از لحاظ کد xml منظورمه) کردم .
چرا تفاوت دارن؟
 

the_king

مدیرکل انجمن
و یه سئوال دیگه اینکه استاد ، اگه ContentPresenter ای که مینویسیم ، به المنت پدر (پدر ، از لحاظ کدهای xml میگم) ربط نداره و به استایل و تمپلیتِ اون نوعی که مینویسیم ربط داره ، پس کدهای زیر ، نباید نتیجه شون با هم فرق کنند . اما کد دوم ، کاملا نتیجه اش فرق میکنه و قاتی میکنه . چرا؟
این چه جور نتیجه گیری ئه. فرضا یک کیف پول هست. مال کیه؟ مال شما است، چه توی پارچ آب باشه و چه توی صندوق امانات بانک و چه توی جیب شلوار، به هر حال مال شما است، هر جا باشه مال شما است.
اینکه کجا قرار بگیره روی اینکه شما صاحبش هستید تاثیری نمیذاره.
اما فرقی نمی کنه که توی پارچ آب سرد خیس شده باشه یا توی جیب گرم و خشک باشه؟ اون ContentPresenter وقتی داخل Border بود نسبت به موقعیت کادر Border و در Grid.Row اندیس 1 نمایش داده میشد.
شما از اون تو که آوردیدش بیرون که دیگه نه موقعیتش اون فضای قبلی است و نه Grid.Row اش مشخص شده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
این چه جور نتیجه گیری ئه. فرضا یک کیف پول هست. مال کیه؟ مال شما است، چه توی پارچ آب باشه و چه توی صندوق امانات بانک و چه توی جیب شلوار، به هر حال مال شما است، هر جا باشه مال شما است.
اینکه کجا قرار بگیره روی اینکه شما صاحبش هستید تاثیری نمیذاره.
اما فرقی نمی کنه که توی پارچ آب سرد خیس شده باشه یا توی جیب گرم و خشک باشه؟ اون ContentPresenter وقتی داخل Border بود نسبت به موقعیت کادر Border و در Grid.Row اندیس 1 نمایش داده میشد.
شما از اون تو که آوردیدش بیرون که دیگه نه موقعیتش اون فضای قبلی است و نه Grid.Row اش مشخص شده.

آها خیلی ممنون استاد .
پس بخاطر این ، اون کد دوم خراب شد که طبق اطلاعات سایت و تمپلیت TabControl :

TabControl Styles and Templates - WPF

فقط قسمتِ محتوای TabItem (نه اینکه قسمتی که فقط خودِ TabItem باشه) (یا به عبارتی ، قسمتی که ما در TabControl مون ، کنترل هامون را میچینیم) ، نیاز به شی ContentPresenter داره (که باید هم نامش PART_SelectedContentHost باشه) .
حالا چون Grid مون را به 2 بخش تقسیم کردیم (2 سطرش کردیم) پس باید به ContentPresenter بگیم که محتوای بخش دومِ Grid (یعنی Grid.Row=1) را نشون بده .اما چون در کد دوم ، اون تگ ContentPresenter را برداشتم و به عنوان فرزند Grid بردم ، چون به تگ ContentPresenter نگفتم که Grid.Row اش را برابر 1 کنه ، بصورت پیش فرض ، Grid.Row اش را برابر 0 میکنه و بنابراین ، مقدار پروپرتیِ ContentSource اش را که SelectedContent قرار دادیم (یعنی هر اشیایی که در پروپرتیِ SelectedContent در کنترل TabControl هست) (یعنی محتوای اون سربرگ هایی که انتخاب کردیم) را در بخش Grid.Row=0 (یعنی در بخش بالای Grid مون) قرار میده و رسم میکنه . واسه همین به نظر میرسید که قاتی کرد .

بنابراین اگه در کد دوم که ContentPresenter را فرزند تگ Grid کردیم ، مقدار Grid.Row=1 در تگ ContentPresenter قرار بدیم ، درست میشه :

کد:
            <Style x:Key="SimpleTabControl" TargetType="{x:Type TabControl}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TabControl}">
                            <Grid KeyboardNavigation.TabNavigation="Local">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>

                                <!-- TabPanel is a layout container which allows the TabItems to wrap and re-order when selected
                        The implementation knows to use this control because it is marked IsItemsHost = True -->
                                <Border Grid.Row="0" BorderBrush="Red" BorderThickness="1"/>
                                <TabPanel Grid.Row="0" Margin="0,0,4,-1" x:Name="HeaderPanel" Background="Transparent" IsItemsHost="True" Panel.ZIndex="1" KeyboardNavigation.TabIndex="1"/>

                                <Border Grid.Row="1" x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="2" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.TabIndex="2">

                                    <!-- The implementation switches the content. This control must be named PART_SelectedContentHost -->
                                   
                                </Border>

                                <ContentPresenter Grid.Row="1" Margin="4" x:Name="PART_SelectedContentHost" ContentSource="SelectedContent"/>

                            </Grid>

                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
                                    <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/>
                                </Trigger>
                            </ControlTemplate.Triggers>

                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

خیلی ممنون . :rose:
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
استاد ، میشه بعد از رسم یه کنترل ، یا مثلا وقتی که به یه کنترل (یا تصویری) که clip کردیم (به پروپرتی clip اون کنترل مقدار دادیم تا فقط همون قسمت از اون کنترل نمایش داده بشه) ، میشه feather هم بهش بدیم (مثل فتوشاپ) ؟ منظورم را متوجه شدین؟
البته با کدنویسیِ زیاد ، بلدم این قابلیت را دسته و پا شکسته بدم اما منظورم یه پروپرتی آماده یا روش ساده تر و دقیق تر هست .


بعد اینکه استاد ، قبلا در تاپیک سی شارپ ، درباره ی دسترسی از یه نخ ، به اشیایی که در نخ دیگه تعریف کردیم (مثلا در نخ اصلی ، یه کنترل بصری ای تعریف کرده باشیم) پرسیده بودم که چجوری میشه متوجه شد به این شی میشه دسترسی داشت تا بهمون ارور نده .
جوابش در wpf اینه که از متد CheckAccess در DispacherObject استفاده کنیم تا متوجه بشیم که آیا میتونیم از این نخ جاری ای که شی DispacherObject را فراخونی کردیم ، استفاده کنیم یا نه . درسته؟
اگه خروجی این متد ، false بود ، همون از متد Invoke استفاده میکنیم. درسته؟
 
آخرین ویرایش:

the_king

مدیرکل انجمن
استاد ، میشه بعد از رسم یه کنترل ، یا مثلا وقتی که به یه کنترل (یا تصویری) که clip کردیم (به پروپرتی clip اون کنترل مقدار دادیم تا فقط همون قسمت از اون کنترل نمایش داده بشه) ، میشه feather هم بهش بدیم (مثل فتوشاپ) ؟ منظورم را متوجه شدین؟
البته با کدنویسیِ زیاد ، بلدم این قابلیت را دسته و پا شکسته بدم اما منظورم یه پروپرتی آماده یا روش ساده تر و دقیق تر هست .
Geometry صرفا یک ناحیه است، Transform داره که دوران بدید یا کوچیک و بزرگ کنید و ... ولی همچنان فقط یک ناحیه است، قابلیتی که باهاش فرضا گوشه هاش رو محو کنید نداره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
Geometry صرفا یک ناحیه است، Transform داره که دوران بدید یا کوچیک و بزرگ کنید و ... ولی همچنان فقط یک ناحیه است، قابلیتی که باهاش فرضا گوشه هاش رو محو کنید نداره.

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


بعد اینکه استاد ، قبلا در تاپیک سی شارپ ، درباره ی دسترسی از یه نخ ، به اشیایی که در نخ دیگه تعریف کردیم (مثلا در نخ اصلی ، یه کنترل بصری ای تعریف کرده باشیم) پرسیده بودم که چجوری میشه متوجه شد به این شی میشه دسترسی داشت تا بهمون ارور نده .
جوابش در wpf اینه که از متد CheckAccess در DispacherObject استفاده کنیم تا متوجه بشیم که آیا میتونیم از این نخ جاری ای که شی DispacherObject را فراخونی کردیم ، استفاده کنیم یا نه . درسته؟
اگه خروجی این متد ، false بود ، همون از متد Invoke استفاده میکنیم. درسته؟
 

the_king

مدیرکل انجمن
خیلی ممنون استاد.
از هیچ روش دیگه هم نمیشه استفاده کرد که پیچیده نباشه؟
چرا. فرضا یک Ellipse دارید که میخواهید گوشه هاش محو باشه، یک تصویر png نیمه شفاف میسازید که یک دایره Blur شده روی زمینه شفاف ئه و بعد یا به Resources پروژه تون اضافه اش می کنید یا Add > Existing Item می کنید که اونم Build Action اش Resource میشه.
بعد بر اساس اون تصویر یک ImageBrush میسازید (در پنجره Properties برای Ellipse انتخاب شده اول OpacityMask رو انتخاب می کنید و بعد زیرش Title brush) و برای Ellipse ئه OpacityMask اش می کنید.
کد:
        <Ellipse Fill="#FF549535">
            <Ellipse.OpacityMask>
                <ImageBrush ImageSource="brush2.png"/>
            </Ellipse.OpacityMask>
        </Ellipse>

بعد اینکه استاد ، قبلا در تاپیک سی شارپ ، درباره ی دسترسی از یه نخ ، به اشیایی که در نخ دیگه تعریف کردیم (مثلا در نخ اصلی ، یه کنترل بصری ای تعریف کرده باشیم) پرسیده بودم که چجوری میشه متوجه شد به این شی میشه دسترسی داشت تا بهمون ارور نده .
جوابش در wpf اینه که از متد CheckAccess در DispacherObject استفاده کنیم تا متوجه بشیم که آیا میتونیم از این نخ جاری ای که شی DispacherObject را فراخونی کردیم ، استفاده کنیم یا نه . درسته؟
اگه خروجی این متد ، false بود ، همون از متد Invoke استفاده میکنیم. درسته؟
بله، شبیه همون Control.InvokeRequired و Control.Invoke ئه.
 

SajjadKhati

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

the_king

مدیرکل انجمن
سلامی مجدد استاد
استاد ، قبلا یه کلاسی درست کرده بودین که افکت های مختلفی را برای کلاس Bitmap میشد اِعمال کرد (مثل افکت تار و blur کردن و موارد افکت بسیار زیادِ دیگه) . یادتون هست؟
اون کلاسی که ساختین ، با کلاس BitmapImage که معادل و شبیه کلاس Bitmap اما در wpf هست هم قابل استفاده هست؟
یا کلا بجز کلاسی که شما نوشته بودین ، توی سایت و جای دیگه ای ، کلاسی هست که افکت های متنوع را بشه روی BitmapImage پیاده کرد؟
بله، همونطور که داده های داخل Bitmap رو میشه در آرایه کپی کرد و بعد تغییر مجددا در Bitmap قرار داد، داده های BitmapImage رو در آرایه کپی کرد یا بر اساس آرایه BitmapImage رو پر کرد.
البته اون کد برای درک و آموزش الگوریتم های پردازش تصویر مناسب ئه، نه استفاده گسترده، چون ذاتا کند ئه.
استفاده از کد های #C برای پردازش تصویر توصیه نمیشه چون ذاتا هر چقدر هم کد بهینه ای باشه، فیلتر کندی خواهد شد، هر چقدر بتوانید از امکانات موجود و DirectX استفاده کنید بهتره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آها خیلی ممنون .
کلا میخواستم مخصوصا افکت feather را برای اون قسمتی که مشخص میکنیم ، برای شکلی که بهش میدیم یا برای اون قسمت هایی از تصویر که alpha اش 0 هست را بصورت تدریجی کم کنه تا بصورت feather در فتوشاپ در بیاد تا اون تصویر را برای اِعمال افکت ، بصورت clip برای کنترل یا تصویری در wpf اِعمال کنیم .
توی آموزش هام ، این کار را کردم اما اولا برای شکل های مستطیلی طراحی شده بود (نه برای هر نوع شکلی مثل دایره و ...) و دوما الگوریتمش دقیق نبود و لبه های مستطیل ، feather نمیشد .
یه الگوریتمی میخواستم که به هر شکلی بدم ، لبه هاش را مثل feather در فتوشاپ تحویل بده .

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

کد:
                <Grid Name="gridGeometry" HorizontalAlignment="Left" Height="224" Margin="230,10,0,0" VerticalAlignment="Top" Width="552">

                    <Path Fill="LightSkyBlue" Stroke="Black" StrokeThickness="2">
                        <Path.Data>
                            <PathGeometry>
                                <PathGeometry.Figures>
                                    <PathFigure StartPoint="10, 10">
                                        <PathFigure.Segments>
                                            <LineSegment Point="100, 50"/>
                                        </PathFigure.Segments>
                                    </PathFigure>
                                </PathGeometry.Figures>
                            </PathGeometry>
                        </Path.Data>
                    </Path>
                   
                    <Path Data="M36,74 L154.75,141.75" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="68.75" Margin="36,74,0,0" Stretch="Fill" Stroke="Black" VerticalAlignment="Top" Width="119.75"/>

                </Grid>

دو شکل و shape از نوع path داریم اما data یکی ، geometry اش بصورت "M36,74 L154.75,141.75" هست (کد دوم) و data ئه یکی دیگه بصورت صریح ، geometry را به اون صورتی که میبینید ، استفاده کرده .
شما کدوم نوع data را ترجیح میدین استفاده کنیم؟
به نظرم هر چند کد اول بیشتر میشه اما راحت تر از کد اول هه . حالا در کد بالا ، هر دو را یه خط تحویل میده اما وقتی شکل ها ، پیچیده تر مثل منحنی و اینها و حتی خیلی پیچیده تر باشن ، درک کد اول ، خیلی راحت تر هه . درست میگم؟
کلا برای مبتدی ها مثل من ، استفاده از کدوم کد را پیشنهاد میکنین؟
نظر خودم ، روی کد اولی هست .
 

the_king

مدیرکل انجمن
آها خیلی ممنون .
کلا میخواستم مخصوصا افکت feather را برای اون قسمتی که مشخص میکنیم ، برای شکلی که بهش میدیم یا برای اون قسمت هایی از تصویر که alpha اش 0 هست را بصورت تدریجی کم کنه تا بصورت feather در فتوشاپ در بیاد تا اون تصویر را برای اِعمال افکت ، بصورت clip برای کنترل یا تصویری در wpf اِعمال کنیم .
توی آموزش هام ، این کار را کردم اما اولا برای شکل های مستطیلی طراحی شده بود (نه برای هر نوع شکلی مثل دایره و ...) و دوما الگوریتمش دقیق نبود و لبه های مستطیل ، feather نمیشد .
یه الگوریتمی میخواستم که به هر شکلی بدم ، لبه هاش را مثل feather در فتوشاپ تحویل بده .
کلا خارج از کارکرد اصلی WPF ئه اما اگر مثال های RenderTargetBitmap رو ببینید این امکان رو میده که تصویری رو بر اساس ظاهر یک المنت و کلا یک Visual بسازید، همونطور که برای Control ها DrawToBitmap وجود داشت. شاید بتوانید با RenderTargetBitmap اول تصویر Mask رو بسازید و بعد روی کنترل تون اعمال کنید، البته کاری که میکنید عادی نیست.

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

کد:
                <Grid Name="gridGeometry" HorizontalAlignment="Left" Height="224" Margin="230,10,0,0" VerticalAlignment="Top" Width="552">

                    <Path Fill="LightSkyBlue" Stroke="Black" StrokeThickness="2">
                        <Path.Data>
                            <PathGeometry>
                                <PathGeometry.Figures>
                                    <PathFigure StartPoint="10, 10">
                                        <PathFigure.Segments>
                                            <LineSegment Point="100, 50"/>
                                        </PathFigure.Segments>
                                    </PathFigure>
                                </PathGeometry.Figures>
                            </PathGeometry>
                        </Path.Data>
                    </Path>
                  
                    <Path Data="M36,74 L154.75,141.75" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="68.75" Margin="36,74,0,0" Stretch="Fill" Stroke="Black" VerticalAlignment="Top" Width="119.75"/>

                </Grid>

دو شکل و shape از نوع path داریم اما data یکی ، geometry اش بصورت "M36,74 L154.75,141.75" هست (کد دوم) و data ئه یکی دیگه بصورت صریح ، geometry را به اون صورتی که میبینید ، استفاده کرده .
شما کدوم نوع data را ترجیح میدین استفاده کنیم؟
به نظرم هر چند کد اول بیشتر میشه اما راحت تر از کد اول هه . حالا در کد بالا ، هر دو را یه خط تحویل میده اما وقتی شکل ها ، پیچیده تر مثل منحنی و اینها و حتی خیلی پیچیده تر باشن ، درک کد اول ، خیلی راحت تر هه . درست میگم؟
کلا برای مبتدی ها مثل من ، استفاده از کدوم کد را پیشنهاد میکنین؟
نظر خودم ، روی کد اولی هست .
پیشنهادی ندارم، سلیقه شخصی تعیین کننده است. مهم اینه که اون ظاهر توصیف بشه، اینکه چطور توصیف میشه در نتیجه تاثیری نداره.
 

SajjadKhati

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

دوم اینکه ، چرا وقتی BezierSegment ای رسم میخوایم کنیم ، نقاط Point1 و Point 2 اش را که دادیم ، رسم ای که انجام میشه ، به این نقاط ، مماس نمیشن؟
چون انتظارِ کاربر اینه که وقتی نقطه ای که داده شد ، رسم ، با اون نقطه تماس ایجاد کنه مثل نقطه ی شروع و پایانش . چون اگه قرار باشه اون دو نقطه ی وسطی که براش مشخص کردیم ، باهاشون تماس ایجاد نکنه ، پس نمیتونیم دقیق متوجه شیم که اون انحنای رسم ، از کدوم نقاط میگذره (منظورم از نقاط ، کل نقاط منحنی نیست . بلکه نقاط هایی که راس قوس هستند ، هست) :

کد:
                <Grid Name="gridGeometry" HorizontalAlignment="Left" Height="224" Margin="230,10,0,0" VerticalAlignment="Top" Width="552">

                    <Path Fill="LightSkyBlue" Stroke="Black" StrokeThickness="2">
                        <Path.Data>
                            <PathGeometry>
                                <PathGeometry.Figures>
                                    <PathFigure StartPoint="10, 10">
                                        <PathFigure.Segments>
                                            <BezierSegment Point1="40, 0" Point2="80, 0" Point3="100, 100"/>
                                        </PathFigure.Segments>
                                    </PathFigure>
                                </PathGeometry.Figures>
                            </PathGeometry>
                        </Path.Data>
                    </Path>

                </Grid>

سوم اینکه در ArcSegment ، پروپرتیِ Size ، در واقع همون نسبت طول و عرض را مشخص میکنه ، نه اینکه طول و عرض را بر حسب پیکسل یا چیز دیگه ای مشخص کنه . درسته؟
خوب ، پس چرا همچین استراکچر Size ای براش در نظر گرفتن؟ یه استراکچر با نام دیگه براش در نظر میگرفتن دیگه :

کد:
                <Grid Name="gridGeometry" HorizontalAlignment="Left" Height="224" Margin="230,10,0,0" VerticalAlignment="Top" Width="552">

                    <Path Fill="DodgerBlue" Stroke="Black" StrokeThickness="2">
                        <Path.Data>
                            <PathGeometry>
                                <PathGeometry.Figures>
                                    <PathFigure StartPoint="50, 200">
                                        <PathFigure.Segments>
                                            <ArcSegment Point="200, 200" Size="3, 1" SweepDirection="Clockwise"/>
                                        </PathFigure.Segments>
                                    </PathFigure>
                                </PathGeometry.Figures>
                            </PathGeometry>
                        </Path.Data>
                    </Path>

                </Grid>

این ArcSegment ، پروپرتی های دیگه مثل RotationAngle و IsLargeArc هم داره که هر چی تغییرش میدم ، نمیدونم چرا هیچ تغییری در رسم انجام نمیشه اما در سایت مایکروسافت ، با تغییرش ، شکل ای که رسم کرده بود ، تغییر میکنه .

و چهارم اینکه فرق QuadraticBezier با Bezier اینه که Bezier ، با 4 نقطه رسم میشه و QuadraticBezier با 3 نقطه؟

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

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

the_king

مدیرکل انجمن
خیلی ممنون استاد .
استاد ، میگم که چرا رسم هایی که در wpf انجام میدیم ، اگه محیط مربوط به رسم مون ، جوری بشه که خارج از فضای اون کنترل والد ای که هست ، بشه ، در محیط خارج از کنترل والد هم رسم اش ادامه دار خواهد بود؟
این که دیگه معنا نداره که رسم در یک فرزند ، از محیط والدش هم فراتر بره و بیرون بزنه . داره؟
اجباری نیست، اختیاری ئه. پیشفرض اش همون حالت ئه و UIElement.ClipToBounds برای همینه که مشخص کنه رسم خود المنت و فرزندانش به کادرش محدوده بشه یا نه.
به سادگی "ClipToBounds="True رو به المنت اضافه می کنید و رسم Clip میشه.
دوم اینکه ، چرا وقتی BezierSegment ای رسم میخوایم کنیم ، نقاط Point1 و Point 2 اش را که دادیم ، رسم ای که انجام میشه ، به این نقاط ، مماس نمیشن؟
چون انتظارِ کاربر اینه که وقتی نقطه ای که داده شد ، رسم ، با اون نقطه تماس ایجاد کنه مثل نقطه ی شروع و پایانش . چون اگه قرار باشه اون دو نقطه ی وسطی که براش مشخص کردیم ، باهاشون تماس ایجاد نکنه ، پس نمیتونیم دقیق متوجه شیم که اون انحنای رسم ، از کدوم نقاط میگذره (منظورم از نقاط ، کل نقاط منحنی نیست . بلکه نقاط هایی که راس قوس هستند ، هست) :
چون منحنی Bezier همونطوریه، نقاط راهنمای میانی که مشخص می کنید نقاط خود منحنی نیست که بخواد از اون رد بشه، بردار انحراف ئه. منحنی Bezier در نرم افزار ها و کاربرد های مختلف با تعداد نقاط متفاوتی مشخص میشه اما در همه شون همینطوریه که یکسری نقاط میانی برای مشخص کردن بردار انحراف ئه.
curve1.png
curve2.jpg

سوم اینکه در ArcSegment ، پروپرتیِ Size ، در واقع همون نسبت طول و عرض را مشخص میکنه ، نه اینکه طول و عرض را بر حسب پیکسل یا چیز دیگه ای مشخص کنه . درسته؟
خوب ، پس چرا همچین استراکچر Size ای براش در نظر گرفتن؟ یه استراکچر با نام دیگه براش در نظر میگرفتن دیگه :
به Size بودنش خللی وارد نشده، Size ئه، فقط واحدش فرق می کنه و نسبی در نظر گرفتنش. برای این نسبی بودن هم دلیل موجهی وجود داره، اگر نسبی نبود برای مشخص کردن ابعاد مناسب باید معادله ریاضی حل می کردید.
حساب کردن ابعاد مناسب با واحد غیر نسبی برای منحنی ای که از نقطه فلان الی بهمان با زاویه RotationAngle فلان در جهت SweepDirection فلان رسم میشه کار راحتی نیست.

این ArcSegment ، پروپرتی های دیگه مثل RotationAngle و IsLargeArc هم داره که هر چی تغییرش میدم ، نمیدونم چرا هیچ تغییری در رسم انجام نمیشه اما در سایت مایکروسافت ، با تغییرش ، شکل ای که رسم کرده بود ، تغییر میکنه .
توضیحات RotationAngle رو در همون سایت مایکروسافت بخونید، نوشته که اگر مقادیر با چه شرایطی تعیین شده باشند تغییر ظاهری ایجاد نمیشه (no effect).

و چهارم اینکه فرق QuadraticBezier با Bezier اینه که Bezier ، با 4 نقطه رسم میشه و QuadraticBezier با 3 نقطه؟
بله، فرمول ریاضی شون فرق داره، اون Bezier در واقع اسم کاملش Cubic Bezier ئه.

میگم استاد ، طراحی wpf ، مخصوصا این قضیه ی ترکیب کردن کنترل ها با هم ، یه چیز جالبی هه و واقعا هم در رسم کنترل ها ، دست آدم را خیلی باز میذاره .
اما حتی میتونستن اگه طراحی شون را شبیه افترافکت ، یعنی بصورت لایه ای میکردن ، دیگه برای ساخت انیمیشن و حتی رسم های پیچیده ، دیگه به اوج خودش میرسید . کارهای افترافکت و فتوشاپ را اون موقع توی wpf میشد انجام داد :green:
نمیدونم چرا این کار را نکردن . طراحی اش شاید پیچیده و دشوار میشد .
لایه داره دیگه. ZIndex داره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آها . متوجه شدم . خیلی ممنون استاد :rose:
درباره ی اون ZIndex هم میدونم . منظورم اون حالت نبود . ZIndex برای اینه که مشخص کنه که یه کنترل ، جلوی چه کنترلی قرار بگیره یا نگیره . اون لایه های افترافکت ، باعث میشن هر افکت ای که به هر لایه اِعمال میشه ، لایه های زیرین اش را تحت تاثیر قرار بدن یا ندن . حالا بماند .

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

An open-source solution for on-the-fly processing of images using .NET :: ImageProcessor
و
ImageProcessor 2.8.0

مستنداتش هم :

ImageProcessor :: ImageProcessor
و
Alpha :: ImageProcessor

از این بهتر هم کتابخونه ی پردازش تصویر رو میشناسین، معرفی کنین؟

نحوه ی تبدیل کلاس Bitmap به BitmapImage (کلاس مربوط به بیت مپ wpf) هم :

Converting BitmapImage to Bitmap and vice versa

معرفی کتابخونه های دیگه ی پردازش تصویر هم در لینک های زیر :

4 Best C# Libraries for Image Processing - C# Station
و
.NET Core Image Processing | .NET Blog
و
Image Processing Lab in C#
 
آخرین ویرایش:

the_king

مدیرکل انجمن
از این بهتر هم کتابخونه ی پردازش تصویر رو میشناسین، معرفی کنین؟
من مقایسه بهتر و بدتر نمی کنم، گاهی اوقات برای یک کار ساده ImageProcessor با حجم کمتر کفایت می کنه اما برای یک قابلیت خاص شاید مجبور باشید با کتابخانه حجیم تری مثل Magick.NET کار کنید.
تا حالا بجز ImageProcessor با GraphicsMagick و Magick.NET هم کار کرده ام. بر اساس نیاز نرم افزار تصمیم می گیرم.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
من مقایسه بهتر و بدتر نمی کنم، گاهی اوقات برای یک کار ساده ImageProcessor با حجم کمتر کفایت می کنه اما برای یک قابلیت خاص شاید مجبور باشید با کتابخانه حجیم تری مثل Magick.NET کار کنید.
تا حالا بجز ImageProcessor با GraphicsMagick و Magick.NET هم کار کرده ام. بر اساس نیاز نرم افزار تصمیم می گیرم.

خیلی ممنون استاد .
توی اینها هم نگاه کردم ، انگار قابلیتی ندارند که وقتی یه شکل یا geometry ای را به عنوان clip به تصویرمون دادیم (و اون بخش از تصویرمون فقط به نمایش دراومد) ، بتونیم به اون قسمتِ clip شده ، feather بدیم .
انگار الگوریتم feather هم آسون نیست . درسته؟
شما کلا الگوریتم feather را بلدین که هر شکلی که به عنوان clip دادیم ، لبه هاش را feather کنه؟ (مثل فتوشاپ) .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
توی اینها هم نگاه کردم ، انگار قابلیتی ندارند که وقتی یه شکل یا geometry ای را به عنوان clip به تصویرمون دادیم (و اون بخش از تصویرمون فقط به نمایش دراومد) ، بتونیم به اون قسمتِ clip شده ، feather بدیم .
انگار الگوریتم feather هم آسون نیست . درسته؟
شما در خود فتوشاپ هم نتیجه Feather رو بصورت یک تصویر سیاه و سفید Mask ذخیره می کنید، در همون فتوشاپ هم Feather جزئی از خصوصیات Clip نیست.
در فتوشاپ وقتی دور یک ناحیه رو با Feather محو می کنید نتیجه ذخیره نمیشه، Mask اش می کنید که ذخیره شدنی باشه.
در فتوشاپ هم اگر تصویری Mask تصویر دیگری باشه مادامی که اون Mask رو ویرایش نکنید تغییری در ناحیه Clip شده ایجاد نمیشه.
شما کلا الگوریتم feather را بلدین که هر شکلی که به عنوان clip دادیم ، لبه هاش را feather کنه؟ (مثل فتوشاپ) .
خیر. من میدونم که به Clip یک Geometry داده میشه و Geometry هم فقط یک ناحیه است، لایه آلفا نداره که یکجاش شفاف باشه و یکجاش نیمه شفاف.
اینکه میگید Clip محو بشه یعنی زحمت مطالعه Clip و Geometry رو نکشیدید. اون چیزی که میتونه اینطوری یکجاش شفاف و یکجاش نیمه شفاف باشه OpacityMask ئه، نه Clip
من بلدم که چطور هر شکلی رو بصورت یک ناحیه Feather شده محو کنم و برای المنت OpacityMask کنم، که اون هم قبلا راهش رو بهتون گفتم.
اگر ناحیه ای رو به عنوان Clip مشخص کردید، پس حتما میخواستید همون ناحیه Clip بشه، اگر میخواستید لبه هاش محو بشه ناحیه محو نشده رو برای چی به عنوان Clip بهش دادید؟
من اگر میخواستم یک ناحیه رو محو کنم و به عنوان Mask برای المنت ای در نظر بگیرم، با کد نویسی اول اون ناحیه رو با المنت ها میساختم، با افکت ها محو اش می کردم، رندر می کردم و تبدیل به تصویرش می کردم و تصویر رو به المنت به عنوان OpacityMask تحویل می دادم، نه اینکه ناحیه ای که لبه هاش محو نیست و نمیخوام با این وضعیت Clip بشه رو به عنوان Clip مشخص کنم.
 

SajjadKhati

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

خیر. من میدونم که به Clip یک Geometry داده میشه و Geometry هم فقط یک ناحیه است، لایه آلفا نداره که یکجاش شفاف باشه و یکجاش نیمه شفاف.
اینکه میگید Clip محو بشه یعنی زحمت مطالعه Clip و Geometry رو نکشیدید. اون چیزی که میتونه اینطوری یکجاش شفاف و یکجاش نیمه شفاف باشه OpacityMask ئه، نه Clip
من بلدم که چطور هر شکلی رو بصورت یک ناحیه Feather شده محو کنم و برای المنت OpacityMask کنم، که اون هم قبلا راهش رو بهتون گفتم.
اگر ناحیه ای رو به عنوان Clip مشخص کردید، پس حتما میخواستید همون ناحیه Clip بشه، اگر میخواستید لبه هاش محو بشه ناحیه محو نشده رو برای چی به عنوان Clip بهش دادید؟
من اگر میخواستم یک ناحیه رو محو کنم و به عنوان Mask برای المنت ای در نظر بگیرم، با کد نویسی اول اون ناحیه رو با المنت ها میساختم، با افکت ها محو اش می کردم، رندر می کردم و تبدیل به تصویرش می کردم و تصویر رو به المنت به عنوان OpacityMask تحویل می دادم، نه اینکه ناحیه ای که لبه هاش محو نیست و نمیخوام با این وضعیت Clip بشه رو به عنوان Clip مشخص کنم.

خیلی ممنون استاد
پس اول ، باید شکل مون را رسم کنیم . بعد به شکل مون افکت بدیم (افکتی که به این قضیه بخوره ، افکت DropShadowEffect میشه . درسته؟) .
بعد باید شکل مون را تبدیل به ImageSource کنیم . انگار با استفاده از کلاس RenderTargetBitmap و با متد Render اش این تبدیل را انجام میدن . درسته؟
بعد باید این RenderTargetBitmap (که از نوع و فرزند ImageSource هست) را به پروپرتیِ اون OpacityMask مربوط به کنترلی که میخوایم برای اون همین قضیه ی feather را رقم بزنیم ، بدیم . درسته؟

ولی من نمیدونم کدم چه اشکالی داره که RenderTargetBitmap ام رسمی انجام نمیده (در کد زیر) :

کد:
                <Grid Name="grdConvertToBmp" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10, 490, 0, 0" Width="200" Height="200" ClipToBounds="True">
                    <Grid.Children>

                        <Ellipse Margin="15" Stroke="Red" StrokeThickness="2" Fill="Red" >
                            <Ellipse.Effect>
                                <DropShadowEffect BlurRadius="30" Direction="0" RenderingBias="Quality" ShadowDepth="0" />
                            </Ellipse.Effect>
                        </Ellipse>

                    </Grid.Children>
                </Grid>

                <Image Name="imgOpacityMask" HorizontalAlignment="Left" Height="206" Margin="230,484,0,0" VerticalAlignment="Top" Width="335" Stretch="Fill">
                    <Image.Source>
                        <BitmapImage UriSource="E:\Tasavir\Shakhsiat ha\Dr Abbasi\dr hassan abbasi 1.jpg"/>
                    </Image.Source>
                </Image>
              
                <Image Name="imgTest" HorizontalAlignment="Left" Height="206" Margin="600,484,0,0" VerticalAlignment="Top" Width="331"/>
              
                <Button Content="Button" HorizontalAlignment="Left" Height="44" Margin="10,712,0,0" VerticalAlignment="Top" Width="113" Click="Button_Click_1"/>

کد بالا ، درون Window هستن که ننوشتمش .

و در زمان اجرا هم :

کد:
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            RenderTargetBitmap renderedBitmap = new RenderTargetBitmap(Convert.ToInt32(this.grdConvertToBmp.Width), Convert.ToInt32(this.grdConvertToBmp.Height), 120, 96, PixelFormats.Pbgra32);
            renderedBitmap.Render(this.grdConvertToBmp);

            //imgOpacityMask.OpacityMask = new ImageBrush(renderedBitmap);

            imgTest.Source = renderedBitmap;
        }

توی کنترل imgTest ، رسم ای انجام نمیشه .
 

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

بالا