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

SajjadKhati

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

the_king

مدیرکل انجمن
خیلی ممنون استاد
پس اول ، باید شکل مون را رسم کنیم . بعد به شکل مون افکت بدیم (افکتی که به این قضیه بخوره ، افکت DropShadowEffect میشه . درسته؟) .
شخصا BlurEffect رو ترجیح میدهم. اگر قراره که ShadowDepth صفر باشه و به همون خاطر مقدار Direction مهم نباشه چرا از DropShadowEffect فقط بخاطر محو کردنش استفاده کنم؟
BlurEffect که همون محو کردن رو بدون مشخصه های خاص 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 ، رسم ای انجام نمیشه .
کد:
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var rect = new Rect(grdConvertToBmp.RenderSize);           
            RenderTargetBitmap renderedBitmap = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
            renderedBitmap.Render(this.grdConvertToBmp);
            imgOpacityMask.OpacityMask = new ImageBrush(renderedBitmap);
            imgTest.Source = renderedBitmap;
        }
 

SajjadKhati

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


بله.

کد:
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var rect = new Rect(grdConvertToBmp.RenderSize);         
            RenderTargetBitmap renderedBitmap = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
            renderedBitmap.Render(this.grdConvertToBmp);
            imgOpacityMask.OpacityMask = new ImageBrush(renderedBitmap);
            imgTest.Source = renderedBitmap;
        }

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

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

                        <Ellipse Margin="17" Stroke="Red" StrokeThickness="2" Fill="Red" >
                            <Ellipse.Effect>
                                <BlurEffect RenderingBias="Quality" Radius="30"/>
                            </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>

                <Button Content="SetImageFeather" HorizontalAlignment="Left" Height="44" Margin="10,712,0,0" VerticalAlignment="Top" Width="113" Click="Button_Click_1"/>

و در سی شارپ :

کد:
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            VisualBrush visualBrush = new VisualBrush(this.grdConvertToBmp);

            DrawingVisual controlVisual = new DrawingVisual();
             DrawingContext drawingContext = controlVisual.RenderOpen();
            drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(0, 0), this.grdConvertToBmp.RenderSize));
            drawingContext.Close();

             RenderTargetBitmap renderedBitmap = new RenderTargetBitmap(Convert.ToInt32(this.grdConvertToBmp.Width), Convert.ToInt32(this.grdConvertToBmp.Height), 96, 96, PixelFormats.Pbgra32);
            renderedBitmap.Render(controlVisual);
          
            imgOpacityMask.OpacityMask = new ImageBrush(renderedBitmap);
        }

این توضیحاتی که برای کد سی شارپ میدم ، درسته؟ :

اول اینکه مثل winform که برای رسم در چیزی (مثلا بیت مپ یا روی کنترل) ، ما اول باید از اون چیز ، Graphic میگرفتیم و بعد با توابع رسمِ Graphic ، توی اون چیز ، شکلی رسم میکردیم ؛ در wpf هم کلاس DrawingContext ، از لحاظ رسم ظاهری ، عملکردی شبیه کلاس Graphic در winform داره (هر چند از لحاظ کدهای داخلی و روش ها رسم ، طبق چیزی که در توضیحات این کلاس اومده ، کاملا شیوه ی متفاوت در رسم دارند) و با متدهای Draw اش میتونیم شکلی را درون اون شی ای که با متد اون شی ، این DrawingContext را Open کردیم ، رسم کنیم . شی DrawingContext را توسط خروجی متد DrawingVisual.RenderOpen یا DrawingGroup.Open ایجاد میکنیم . حالا دقیق نمیدونم در چه زمانی ، توسط کدوم یکی از این متدها ، شیِ DrawingContext را ایجاد و استفاده کنیم .
به عبارتی دیگه ، وقتی که از خروجیِ متد DrawingVisual.RenderOpen ، شیِ DrawingContext را ایجاد کنیم ، رسمِ هایی که توسط متدهای شیِ DrawingContext انجام میدیم ، درون شی DrawingVisual رسم میشه .


نکته ی کلیدی مهم دیگه اینکه Brush ها ، شامل هر رسمی ، حتی رسم تصویر یا ویدئو و حتی اشیاء های Visual (که کنترل ها و element ها ، فرزندانِ Visual هستند) هم میتونن بشن .
و از اونجایی که بعضی از ورودی متدهای Draw در DrawingContext ، شیِ Brush میخوان و ما هم قصد رسم کنترل ایجاد شده (در این مثال) را داریم ، پس میتونیم ابتدا ، رسمِ کنترل مون را در شیِ VisualBrush که نوعی براش برای اشیاء های Visual و کنترل های بصری هست ، انجام بدیم و بعد این رسم را توسط متدهای رسم شیِ DrawingContext ، در شیِ DrawingVisual رسم کنیم .


در مرحله ی آخر ، چون برای OpacityMask ، نیاز به شیِ ImageBrush که خودِ این براش ، نیاز به شیِ ImageSource داره ، پس این شیِ DrawingVisual را باید تبدیل به ImageSource کرد .
این کارِ تبدیل را ، با شیِ RenderTargetBitmap که یکی از فرزندان ImageSource هست ، انجام میدیم (توسط متد Render شیِ RenderTargetBitmap) .
سر آخر هم این شیِ RenderTargetBitmap که یکی از فرزندان ImageSource هست را به ImageBrush مربوط به OpacityMask میدیم .

همونطور هم که گفتید ، افکت BlurEffect ، خیلی مناسب تر برای این کار هست .

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

استاد ، چرا کنترل های wpf ، عضو dispose ندارن؟
الان اگه ما ، در زمان اجرای برنامه ، توسط کد سی شارپ ، کنترل جدیدی ایجاد کنیم ، موقع بستن و تموم شدن کارمون با اون شی و کنترل ، قضیه ی dispose اش چی میشه؟

بعد اینکه نمیدونم چرا متد کاربردی Control.DrawToBitmap در winform را که رسمِ مربوط به اون کنترل را درون Bitmap ای رسم میکرد را در wpf نمیذارن (یا نذاشتن) تا مثلا اون کنترل بصری را درون مثلا ImageSource ای که بهش میدیم ، رسم کنه !
 
آخرین ویرایش:

the_king

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

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

                        <Ellipse Margin="17" Stroke="Red" StrokeThickness="2" Fill="Red" >
                            <Ellipse.Effect>
                                <BlurEffect RenderingBias="Quality" Radius="30"/>
                            </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>

                <Button Content="SetImageFeather" HorizontalAlignment="Left" Height="44" Margin="10,712,0,0" VerticalAlignment="Top" Width="113" Click="Button_Click_1"/>

و در سی شارپ :

کد:
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            VisualBrush visualBrush = new VisualBrush(this.grdConvertToBmp);

            DrawingVisual controlVisual = new DrawingVisual();
             DrawingContext drawingContext = controlVisual.RenderOpen();
            drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(0, 0), this.grdConvertToBmp.RenderSize));
            drawingContext.Close();

             RenderTargetBitmap renderedBitmap = new RenderTargetBitmap(Convert.ToInt32(this.grdConvertToBmp.Width), Convert.ToInt32(this.grdConvertToBmp.Height), 96, 96, PixelFormats.Pbgra32);
            renderedBitmap.Render(controlVisual);
         
            imgOpacityMask.OpacityMask = new ImageBrush(renderedBitmap);
        }

این توضیحاتی که برای کد سی شارپ میدم ، درسته؟ :
اول اینکه مثل winform که برای رسم در چیزی (مثلا بیت مپ یا روی کنترل) ، ما اول باید از اون چیز ، Graphic میگرفتیم و بعد با توابع رسمِ Graphic ، توی اون چیز ، شکلی رسم میکردیم ؛ در wpf هم کلاس DrawingContext ، از لحاظ رسم ظاهری ، عملکردی شبیه کلاس Graphic در winform داره (هر چند از لحاظ کدهای داخلی و روش ها رسم ، طبق چیزی که در توضیحات این کلاس اومده ، کاملا شیوه ی متفاوت در رسم دارند) و با متدهای Draw اش میتونیم شکلی را درون اون شی ای که با متد اون شی ، این DrawingContext را Open کردیم ، رسم کنیم . شی DrawingContext را توسط خروجی متد DrawingVisual.RenderOpen یا DrawingGroup.Open ایجاد میکنیم . حالا دقیق نمیدونم در چه زمانی ، توسط کدوم یکی از این متدها ، شیِ DrawingContext را ایجاد و استفاده کنیم .
به عبارتی دیگه ، وقتی که از خروجیِ متد DrawingVisual.RenderOpen ، شیِ DrawingContext را ایجاد کنیم ، رسمِ هایی که توسط متدهای شیِ DrawingContext انجام میدیم ، درون شی DrawingVisual رسم میشه .
بله.

نکته ی کلیدی مهم دیگه اینکه Brush ها ، شامل هر رسمی ، حتی رسم تصویر یا ویدئو و حتی اشیاء های Visual (که کنترل ها و element ها ، فرزندانِ Visual هستند) هم میتونن بشن .
و از اونجایی که بعضی از ورودی متدهای Draw در DrawingContext ، شیِ Brush میخوان و ما هم قصد رسم کنترل ایجاد شده (در این مثال) را داریم ، پس میتونیم ابتدا ، رسمِ کنترل مون را در شیِ VisualBrush که نوعی براش برای اشیاء های Visual و کنترل های بصری هست ، انجام بدیم و بعد این رسم را توسط متدهای رسم شیِ DrawingContext ، در شیِ DrawingVisual رسم کنیم .
بله، ولی اون قسمتی که میگید رسم در شیِ VisualBrush انجام میشه درست نیست، در VisualBrush رسم انجام نمی دهید، چگونگی رسم رو تعریف می کنید.

در مرحله ی آخر ، چون برای OpacityMask ، نیاز به شیِ ImageBrush که خودِ این براش ، نیاز به شیِ ImageSource داره ، پس این شیِ DrawingVisual را باید تبدیل به ImageSource کرد .
این کارِ تبدیل را ، با شیِ RenderTargetBitmap که یکی از فرزندان ImageSource هست ، انجام میدیم (توسط متد Render شیِ RenderTargetBitmap) .
سر آخر هم این شیِ RenderTargetBitmap که یکی از فرزندان ImageSource هست را به ImageBrush مربوط به OpacityMask میدیم .
بله.
استاد ، چرا کنترل های wpf ، عضو dispose ندارن؟
الان اگه ما ، در زمان اجرای برنامه ، توسط کد سی شارپ ، کنترل جدیدی ایجاد کنیم ، موقع بستن و تموم شدن کارمون با اون شی و کنترل ، قضیه ی dispose اش چی میشه؟
چیزی که نگران Dispose شدنش باشند ندارند. وقتی یک کنترل فرضا TextBox میساختید با Dispose خود شیء TextBox که نابود نمیشد، null که نمیشد، شیء اش همچنان سر جاش بود.
چیزی که با Dispose نابود میشد اون منابعی بود که از جای دیگری مثل سیستم عامل گرفته شده بود، مثلا پنجره اش نابود میشد. اون TextBox یک کلاس NET. داشت اما اساسش یک پنجره و کلاس TextBox ویندوز بود که برای ساختنش از منابع ویندوز استفاده شده بود.
اما در WPF با یکسری اشیاء انتزاعی کار می کنید که ارتباط مستقیمی با منابع در دست سیستم عامل یا حتی DirectX ندارند. کنترل در WPF یک شیء کاملا انتزاعی است که نمایش و عملکرد اش مستقل از شیء ئه.
حتی نخی که رسم کنترل رو انجام میده هم مستقل ئه. موقع ساختن یک کنترل در WPF منابعی که مدیریت اش نظارت برنامه نویس رو بخواد دریافت نمی کنه که نگران آزاد شدنش باشه.

بعد اینکه نمیدونم چرا متد کاربردی Control.DrawToBitmap در winform را که رسمِ مربوط به اون کنترل را درون Bitmap ای رسم میکرد را در wpf نمیذارن (یا نذاشتن) تا مثلا اون کنترل بصری را درون مثلا ImageSource ای که بهش میدیم ، رسم کنه !

دو تا مورد متفاوت هستند. DrawToBitmap برای یک تصویر Device Context یا همون DC دریافت می کنه و کنترل رو بجای رسم عادی که در DC خود کنترل انجام میشد اینبار در DC اون تصویر رسم می کنه.
اون چیزی که DrawToBitmap به عنوان ورودی میخواد تصویر ئه.
اما ImageSource که خود تصویر نیست، تعریف منبعی است که تصویر رو میشه از طریق اون ایجاد کرد.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
استاد ، یه Control Template برای CheckBox نوشتم (شبیه checkbox در تنظیمات powerdvd) :

کد:
                <ControlTemplate x:Key="checkBoxCustTemplate" TargetType="CheckBox">
                    <Grid>

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="16"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>

                        <Border Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top"  Width="16" Height="16" CornerRadius="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1">
                            <Border.Child>
                                <Path Name="tickPath"  Stroke="{TemplateBinding BorderBrush}" StrokeThickness="1" Fill="{TemplateBinding BorderBrush}" StrokeStartLineCap="Triangle" StrokeEndLineCap="Triangle">
                                    <Path.Data>

                                        <PathGeometry>
                                            <PathGeometry.Figures>
                                                <PathFigure StartPoint="1, 7">
                                                    <PathFigure.Segments>

                                                        <QuadraticBezierSegment Point1="3, 7" Point2="5, 9" />
                                                        <QuadraticBezierSegment Point1="8, 4" Point2="12, 2" />

                                                    </PathFigure.Segments>


                                                </PathFigure>

                                                <PathFigure StartPoint="1, 7">
                                                    <PathFigure.Segments>

                                                        <QuadraticBezierSegment Point1="3.2, 7.2" Point2="5, 11" />
                                                        <QuadraticBezierSegment Point1="8.2, 4.2" Point2="12, 2" />

                                                    </PathFigure.Segments>


                                                </PathFigure>


                                            </PathGeometry.Figures>
                                        </PathGeometry>

                                    </Path.Data>
                                </Path>
                            </Border.Child>
                        </Border>

                        <ContentPresenter Grid.Column="1" Margin="4, 0, 0, 0"/>

                    </Grid>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="false">
                            <Trigger.Setters>
                                <Setter  TargetName="tickPath" Property="Visibility" Value="Hidden"/>
                            </Trigger.Setters>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

وقتی روی قسمت Content اش کلیک میکنم ، مشکلی نیست .
ولی وقتی روی قسمت Border اش کلیک میکنم ، نمیدونم چرا گاها تیک اش عمل میکنه (تیک میزنه) و گاها عمل نمیکنه (تیک نمیزنه) !!
نمیدونم متوجه ی منظورم شدید یا نه .
واسه ی خودمم جای تعجب داره .

البته نمیدونم بخاطر این باشه که Grid ام را ستون بندی کردم یا نه .
اما اگه واسه ی ستون بندی اش باشه ، نمیشه این کد را با حفظ ستون بندی ، درست کرد؟
کلا مشکلش از کجاست؟


بله، ولی اون قسمتی که میگید رسم در شیِ VisualBrush انجام میشه درست نیست، در VisualBrush رسم انجام نمی دهید، چگونگی رسم رو تعریف می کنید.

خیلی ممنون استاد .
آها . اگه اشتباه نکنم ، زمانی میگیم رسم ای انجام شد که روی پنجره و کنترلی ، چیزی رسم بشه . در واقع در Device Context مربوط به اون پنجره ، رسم ای اتفاق بیفته . (هر چند مفهوم Device Context در کنترل ها را دقیق نمیدونم) .
اما وقتی شی Brush ای داریم ، این شی ، صرفا یه شی در حافظه هست . که صرفا شامل توصیفات اون رسم هست که وقتی از روی این توصیفات ، Render ای در Device Context مربوط به فلان کنترل ، صورت بگیره ، در اون زمان میگیم که رسم ای انجام شد . نه اینکه وقتی شی Brush ای داریم ، در شی Brush ، چیزی رسم شده باشه . چون شی Brush مون که رسم و رندر ای نداره .
درسته؟

چیزی که نگران Dispose شدنش باشند ندارند. وقتی یک کنترل فرضا TextBox میساختید با Dispose خود شیء TextBox که نابود نمیشد، null که نمیشد، شیء اش همچنان سر جاش بود.
چیزی که با Dispose نابود میشد اون منابعی بود که از جای دیگری مثل سیستم عامل گرفته شده بود، مثلا پنجره اش نابود میشد. اون TextBox یک کلاس NET. داشت اما اساسش یک پنجره و کلاس TextBox ویندوز بود که برای ساختنش از منابع ویندوز استفاده شده بود.

بله . میدونم .
قبلا زحمت توضیح اینها را کشیده بودین .

اما در WPF با یکسری اشیاء انتزاعی کار می کنید که ارتباط مستقیمی با منابع در دست سیستم عامل یا حتی DirectX ندارند. کنترل در WPF یک شیء کاملا انتزاعی است که نمایش و عملکرد اش مستقل از شیء ئه.

دقیقا متوجه نشدم .
منظورتون از اشیاء انتزاعی ، چیه؟ منظورتون از ارتباط غیرمستقیم چیه؟
خوب در winform هم ارتباط مستقیم ندارند . چون اول کلاس ها و کنترلهای .net را فراخونی میکنیم (مثلا Button را) . بعد توی اون کلاس ها ، از منابع و api های سیستم عامل استفاده میشه . پس در اونجا هم ارتباط مستقیمی با api های ویندوز نداریم .
حالا چه مستقیم یا غیر مستقیم ، بالاخره وقتی در wpf ، ارتباط غیر مستقیم هم باشه ، بالاخره از api های ویندوز استفاده شده و چون منابع unmanaged هستند ، بعد از اتمام استفاده ، باید dispose بشن دیگه . درسته؟
اگه آره ، پس dispose ای نداره که dispose کنیم .

حتی نخی که رسم کنترل رو انجام میده هم مستقل ئه. موقع ساختن یک کنترل در WPF منابعی که مدیریت اش نظارت برنامه نویس رو بخواد دریافت نمی کنه که نگران آزاد شدنش باشه.

منظورتون اینه که مثلا توابع رسم اش در نخ مجزایی هست اما موقعی که میخوان رسم ای انجام بدن ، در نخ اصلی نرم افزار انجام میدن دیگه؟ مثل قضیه ی متد Invoke در winform . درسته؟
اگه درست نیست ، مگه امکان پذیره؟ یعنی ما هم میتونیم در نخ مجزایی در wpf ، رسم مون را انجام بدیم؟!!
البته من درباره ی Freezable Object در wpf یه چیزهایی خوندم که اونم اگه قابلیت freez این اشیاء ها را فعال کنیم (که باعث میشه اعضاش فقط قابل خوندن بشن و دیگه نمیشه توی اعضاش چیزی را نوشت) ، میتونیم توی نخ مجزا با این اشیاء کار کنیم . و همچنین افزایش کارایی خواهند داشت . اما خیلی از کنترل ها که Freezable Object نیستند .

کلا این مورد را متوجه نشدم که قضیه اش چیه؟

دو تا مورد متفاوت هستند. DrawToBitmap برای یک تصویر Device Context یا همون DC دریافت می کنه و کنترل رو بجای رسم عادی که در DC خود کنترل انجام میشد اینبار در DC اون تصویر رسم می کنه.
اون چیزی که DrawToBitmap به عنوان ورودی میخواد تصویر ئه.
اما ImageSource که خود تصویر نیست، تعریف منبعی است که تصویر رو میشه از طریق اون ایجاد کرد.

حالا منظورم ImageSource یا فرزندش BitmapImage بود .
 

the_king

مدیرکل انجمن
استاد ، یه Control Template برای CheckBox نوشتم (شبیه checkbox در تنظیمات powerdvd) :

کد:
                <ControlTemplate x:Key="checkBoxCustTemplate" TargetType="CheckBox">
                    <Grid>

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="16"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>

                        <Border Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top"  Width="16" Height="16" CornerRadius="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1">
                            <Border.Child>
                                <Path Name="tickPath"  Stroke="{TemplateBinding BorderBrush}" StrokeThickness="1" Fill="{TemplateBinding BorderBrush}" StrokeStartLineCap="Triangle" StrokeEndLineCap="Triangle">
                                    <Path.Data>

                                        <PathGeometry>
                                            <PathGeometry.Figures>
                                                <PathFigure StartPoint="1, 7">
                                                    <PathFigure.Segments>

                                                        <QuadraticBezierSegment Point1="3, 7" Point2="5, 9" />
                                                        <QuadraticBezierSegment Point1="8, 4" Point2="12, 2" />

                                                    </PathFigure.Segments>


                                                </PathFigure>

                                                <PathFigure StartPoint="1, 7">
                                                    <PathFigure.Segments>

                                                        <QuadraticBezierSegment Point1="3.2, 7.2" Point2="5, 11" />
                                                        <QuadraticBezierSegment Point1="8.2, 4.2" Point2="12, 2" />

                                                    </PathFigure.Segments>


                                                </PathFigure>


                                            </PathGeometry.Figures>
                                        </PathGeometry>

                                    </Path.Data>
                                </Path>
                            </Border.Child>
                        </Border>

                        <ContentPresenter Grid.Column="1" Margin="4, 0, 0, 0"/>

                    </Grid>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="false">
                            <Trigger.Setters>
                                <Setter  TargetName="tickPath" Property="Visibility" Value="Hidden"/>
                            </Trigger.Setters>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

وقتی روی قسمت Content اش کلیک میکنم ، مشکلی نیست .
ولی وقتی روی قسمت Border اش کلیک میکنم ، نمیدونم چرا گاها تیک اش عمل میکنه (تیک میزنه) و گاها عمل نمیکنه (تیک نمیزنه) !!
نمیدونم متوجه ی منظورم شدید یا نه .
واسه ی خودمم جای تعجب داره .

البته نمیدونم بخاطر این باشه که Grid ام را ستون بندی کردم یا نه .
اما اگه واسه ی ستون بندی اش باشه ، نمیشه این کد را با حفظ ستون بندی ، درست کرد؟
کلا مشکلش از کجاست؟
ستون بندی مشکلی نداره اما مشکل Hit Test داره، null بودن Background در Grid و Border باعث شده که با روال پیشفرض کلیک روی نقاط داخل Border منجر به دریافت Hit نشه.
یا به Grid ئه یا به Border ئه یک Background غیر از {x:Null} بدهید، مثلا <"Grid Background="Transparent> . لازم نیست واقعا رنگ بشه، همون Transparent اگر زمینه Border یا Grid باشه کفایت می کنه.

خیلی ممنون استاد .
آها . اگه اشتباه نکنم ، زمانی میگیم رسم ای انجام شد که روی پنجره و کنترلی ، چیزی رسم بشه
قطعا همینطوره.
. در واقع در Device Context مربوط به اون پنجره ، رسم ای اتفاق بیفته . (هر چند مفهوم Device Context در کنترل ها را دقیق نمیدونم).
در واقع نه. در Device Context رسم نمی کنید ولی به وسیله Device Context رسم می کنید. Device Context مجموعه تنظیماتی رو نگه میداره که برای رسم بکار می برید. مثلا وقتی می خواهید با چاپگر چیزی رو چاپ کنید، DC چاپگر تنظیمات dpi و مود رنگ و Brush و Font و ... اون رسم روی چاپگر رو نگهداری می کنه، روی چاپگر رسم می کنید، اما توسط تنظیمات اون DC، در خود DC رسم نمی کنید و البته بدون DC روی چاپگر یا کنترل یا هر Device دیگری رسم ای انجام نمیشه.

اما وقتی شی Brush ای داریم ، این شی ، صرفا یه شی در حافظه هست . که صرفا شامل توصیفات اون رسم هست که وقتی از روی این توصیفات ، Render ای در Device Context مربوط به فلان کنترل ، صورت بگیره ، در اون زمان میگیم که رسم ای انجام شد . نه اینکه وقتی شی Brush ای داریم ، در شی Brush ، چیزی رسم شده باشه . چون شی Brush مون که رسم و رندر ای نداره .
درسته؟
بله.

دقیقا متوجه نشدم .
منظورتون از اشیاء انتزاعی ، چیه؟ منظورتون از ارتباط غیرمستقیم چیه؟
شما وقتی در Windows Forms یک کنترل ایجاد می کنید یک کنترل واقعی ویندوز ایجاد میشه، برایش پنجره ویندوز ایجاد میشه، مثل سایر پنجره های ویندوز پیام هایی به اون پنجره ارسال میشه و ازش پیام دریافت میشه. فقط یک کلاس انتزاعی NET. نیست که خیال کنیم دکمه ای هست اما در واقع فقط یک نقش روی تصویر باشه. درسته که یک شیء نرم افزاری است اما نسبت به پنجره ها در ویندوز انتزاعی نیست، واقعا یک کنترل ویندوز ئه، پنجره داره.
اما در WPF قراره DirectX بعدا بر اساس اشیاء خاصی مثل TextBox روی یک تصویر بزرگ که یک پنجره واقعی است یکسری اجزاء رو رسم کنه، انیمیشن نشون بده که باور کنید اون TextBox اونجا هست.
انگار که با Paint یک دکمه رو روی یک عکس بکشید، اون Paint فقط یک نقش روی تصویر ئه، واقعا دکمه یک شیء مستقل روی پنجره نیست، برای همین کنترل های WPF پنجره ندارند. اشیاء انتزاعی هستند.
شما وقتی درخواست رسم یک دکمه Windows Forms رو می کنید اون دکمه توسط نخ ایجاد کننده اش در پنجره خودش رسم میشه. می توانید هر زمان خواستید درخواست رسمش رو بکنید.
اما در WPF نخ رسم کننده اصلا ارتباطی به نخ دکمه نداره، کل پنجره رو هم رسم می کنه، خاص رسم یک دکمه نیست، خود دکمه نه کاری با DirectX داره و نه رسم اش.

خوب در winform هم ارتباط مستقیم ندارند . چون اول کلاس ها و کنترلهای .net را فراخونی میکنیم (مثلا Button را) . بعد توی اون کلاس ها ، از منابع و api های سیستم عامل استفاده میشه . پس در اونجا هم ارتباط مستقیمی با api های ویندوز نداریم .
من در مورد API ویندوز صحبت نکردم، در مورد منابعی صحبت کردم که با ساختن فرضا دکمه ایجاد میشه و باید آزاد بشوند. شما وقتی یک دکمه در WPF می سازید چه منبع unmanaged ای صرف شده که نگران Dispose شدنش باشیم؟ فرض کنیم که 1000 تا دکمه ساختید و امکان Dispose شدنشون هم بود و به هر دلیلی Dispose نشدند، حالا چه چیزی هدر رفته؟ چه منبعی؟

منظورتون اینه که مثلا توابع رسم اش در نخ مجزایی هست اما موقعی که میخوان رسم ای انجام بدن ، در نخ اصلی نرم افزار انجام میدن دیگه؟ مثل قضیه ی متد Invoke در winform . درسته؟
نه. رسم WPF شباهتی به Windows Form نداره، در WPF خود نخ ایجاد کننده کنترل رسم کننده کنترل نیست.

اگه درست نیست ، مگه امکان پذیره؟ یعنی ما هم میتونیم در نخ مجزایی در wpf ، رسم مون را انجام بدیم؟!!
قضیه برعکس ئه. در WPF کد شما درگیر روال رسم نیست، همونطور که GC مستقل بود و نخ های خودش رو داشت، این موتور رندر WPF هم مستقل ئه و نخ های خودش رو داره.
در نخ های مجزای خاص خودش رسم رو انجام میده. کاری به نخ اصلی کد شما نداره. کاری به نخ ایجاد کننده اون کنترل ها نداره.

البته من درباره ی Freezable Object در wpf یه چیزهایی خوندم که اونم اگه قابلیت freez این اشیاء ها را فعال کنیم (که باعث میشه اعضاش فقط قابل خوندن بشن و دیگه نمیشه توی اعضاش چیزی را نوشت) ، میتونیم توی نخ مجزا با این اشیاء کار کنیم . و همچنین افزایش کارایی خواهند داشت . اما خیلی از کنترل ها که Freezable Object نیستند .
اینکه در نخ های مجزا با کنترل کار کنید ارتباطی با موضوع رسم شون نداره.

حالا منظورم ImageSource یا فرزندش BitmapImage بود .
فرقی نمی کنه، Source همیشه Source ئه، BitmapImage خودش تصویر نیست، تعریف منبعی است که تصویر Bitmap رو ایجاد می کنه.
 

SajjadKhati

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

استاد ، توی سی شارپ اگه بخوایم بدونیم کدوم کلاس ، توی کدوم فضای نام هست ، به اسناد اون کلاس (که مثلا میتونه سایت مایکروسافت باشه و ...) مراجعه کنیم و بعد متوجه بشیم که فضای نام اون کلاس چیه و نام فضای نام اش را using کنیم تا از اون کلاس ها و اعضای فضای نام ، استفاده کنیم . حتی میتونیم از object browser در خود ویژال استودیو هم کمک بگیریم .
حالا اگه توی xml در wpf ، یه کلاسی را بخوایم استفاده کنیم و فضای نام اون کلاس را ندونیم ، نام اون فضای نام را چجوری میتونیم در wpf پیدا کنیم؟
 

the_king

مدیرکل انجمن
استاد ، توی سی شارپ اگه بخوایم بدونیم کدوم کلاس ، توی کدوم فضای نام هست ، به اسناد اون کلاس (که مثلا میتونه سایت مایکروسافت باشه و ...) مراجعه کنیم و بعد متوجه بشیم که فضای نام اون کلاس چیه و نام فضای نام اش را using کنیم تا از اون کلاس ها و اعضای فضای نام ، استفاده کنیم . حتی میتونیم از object browser در خود ویژال استودیو هم کمک بگیریم .
حالا اگه توی xml در wpf ، یه کلاسی را بخوایم استفاده کنیم و فضای نام اون کلاس را ندونیم ، نام اون فضای نام را چجوری میتونیم در wpf پیدا کنیم؟
در این مورد من فرقی بین Windows Forms و WPF نمی بینم، در جفت شون همون زبان #C ئه و همون ویژوال استدیو. همون کاری که در Windows Forms می توانستید بکنید در WPF هم می کنید.
مثلا در کد #C یا XAML روی هر نوع داده یا المنت ای راست کلیک کنید گزینه Go To Definition داره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
در این مورد من فرقی بین Windows Forms و WPF نمی بینم، در جفت شون همون زبان #C ئه و همون ویژوال استدیو. همون کاری که در Windows Forms می توانستید بکنید در WPF هم می کنید.
مثلا در کد #C یا XAML روی هر نوع داده یا المنت ای راست کلیک کنید گزینه Go To Definition داره.

البته من این سئوال را قبلا پرسیدم ولی به نتیجه ی نهایی نرسیدم .
الان مثلا من میخوام از کلاسی استفاده کنم که خود کلاس ، در بخش reference هست اما فضای نام اش پیوست نشده . بنابراین کلاس اش را نمیشناسه .
بنابراین وقتی در xml در wpf ، نام کلاس اش را توی تگ ای مینویسم ، نمیشناسه .
در این صورت ، اگه زبان سی شارپ بود ، با استفاده از using ، یا با نوشتن نام کامل فضای نام اش ، اون کلاس را در لیست intelisense مون داشتیم . اما در xaml در wpf باید چی کار کنیم که بشناسه؟
چون در xml در wpf ، فضای نام ها ، لینک url دارن که حداقل من ربط شون را با فضای نام ای که در فایل های dll (یا هر نوع فایل دیگه) که در بخش reference هستند ، متوجه نمیشم چجوری هه.

خیلی ممنون استاد .
 

the_king

مدیرکل انجمن
البته من این سئوال را قبلا پرسیدم ولی به نتیجه ی نهایی نرسیدم .
الان مثلا من میخوام از کلاسی استفاده کنم که خود کلاس ، در بخش reference هست اما فضای نام اش پیوست نشده . بنابراین کلاس اش را نمیشناسه .
بنابراین وقتی در xml در wpf ، نام کلاس اش را توی تگ ای مینویسم ، نمیشناسه .
در این صورت ، اگه زبان سی شارپ بود ، با استفاده از using ، یا با نوشتن نام کامل فضای نام اش ، اون کلاس را در لیست intelisense مون داشتیم . اما در xaml در wpf باید چی کار کنیم که بشناسه؟
چون در xml در wpf ، فضای نام ها ، لینک url دارن که حداقل من ربط شون را با فضای نام ای که در فایل های dll (یا هر نوع فایل دیگه) که در بخش reference هستند ، متوجه نمیشم چجوری هه.

خیلی ممنون استاد .
در کد XAML ها فضای نام ای شبیه "xmlns:local="clr-namespace:WpfApp1 رو ندیدید؟
فرض کنیم یک MyElement ای دارید که در فضای نام MyNamespace تعریف شده. یعنی در کد #C تون MyNamespace.MyElement ای قابل دسترسی است.
حالا در XAML مثل سایر xmlns ها می توانید اون فضای نام رو معرفی کنید. شبیه اش رو در مورد xmlns:local می توانید ببینید.
در تگ Window (یا تگ بیرونی دیگری، لازم نیست که حتما در Window باشه) فضای نام MyNamespace رو با پیشوند دلخواه تعریف می کنید.
مثلا پیشوند ns :
کد:
        <Grid xmlns:ns="clr-namespace:MyNamespace">
            <ns:MyElement>

            </ns:MyElement>
        </Grid>
یا فضای نام رو در خود MyElement مشخص می کنید :
کد:
        <MyElement xmlns="clr-namespace:MyNamespace">

        </MyElement>
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
در کد XAML ها فضای نام ای شبیه "xmlns:local="clr-namespace:WpfApp1 رو ندیدید؟
فرض کنیم یک MyElement ای دارید که در فضای نام MyNamespace تعریف شده. یعنی در کد #C تون MyNamespace.MyElement ای قابل دسترسی است.
حالا در XAML مثل سایر xmlns ها می توانید اون فضای نام رو معرفی کنید. شبیه اش رو در مورد xmlns:local می توانید ببینید.
در تگ Window (یا تگ بیرونی دیگری، لازم نیست که حتما در Window باشه) فضای نام MyNamespace رو با پیشوند دلخواه تعریف می کنید.
مثلا پیشوند ns :
کد:
        <Grid xmlns:ns="clr-namespace:MyNamespace">
            <ns:MyElement>

            </ns:MyElement>
        </Grid>
یا فضای نام رو در خود MyElement مشخص می کنید :
کد:
        <MyElement xmlns="clr-namespace:MyNamespace">

        </MyElement>

آها .
خیلی ممنون استاد .
پس بجای WPF_Practice در xmlns:local="clr-namespace:WPF_Practice" ، نامِ فضای نام مورد نظرمون که در فایل مربوط به سی شارپ مون هست را مینویسیم . درسته؟
و قسمت clr-namespace را دست نمیزنیم . درسته؟
و اگه فضای نام دیگه ای خواستیم اضافه کنیم (علاوه بر فضای نام موجود ، خواستیم فضای نام یه کلاس دیگه را هم اضافه کنیم) ، نام پیشوندش را که در اینجا local هست را عوض میکنیم . درسته؟ چون 2 تا پیشوند با نام یکسان را قبول نمیکنه .

خیلی ممنون استاد .
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
استاد ، ماه رمضان تون مبارک .
استاد ، من بخش XAML root elements and XAML namespaces در لینک زیر را خوندم :

XAML overview - WPF

اما ریزه کاری هاشو متوجه نشدم .
گاها معنی هاشو و مخصوصا مفاهیم شو .
بنابراین اون توضیحی که در بخش آخرش داد (که گفت) :

کد:
The WPF implementation of its XAML processor includes an infrastructure that has awareness of the WPF core assemblies. The WPF core assemblies are known to contain the types that support the WPF mappings to the default XAML namespace. This is enabled through configuration that is part of your project build file and the WPF build and project systems. Therefore, declaring the default XAML namespace as the default xmlns is all that is necessary in order to reference XAML elements that come from WPF assemblies.

و بنابراین نتیجه گیری کرد که استفاده از فضای نام پیش فرض (یعنی xmlns) ، برای ارجاع و ریفرنس دادن به کلاس های موجود در اسمبلی های wpf ضروری هست را متوجه نشدم .

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

من آخر دلیل اینکه فضای نام را با لینک url وب میدن ، متوجه نشدم . مخصوصا الان که متوجه شدم بصورت :

کد:
xmlns:System="clr-namespace:System;assembly=mscorlib"

هم فضای نام و هم اسمبلی در سی شارپ را میشه مشخص کرد .
پس اون لینک وب در اینجا نباید کاربرد داشته باشه .
بله . لینک وب میتونه در فضای نام دادن در برنامه های دیگه بجز wpf کاربرد داشته باشه اما نه در wpf که به این شیوه ای که گفتین ، میشه فضای نام کلاس هامون را مشخص کنیم .

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

استاد ، چجوری میشه وقتی یه shape ای رسم میکنیم (مثلا ellipse) ، فاصله ای برای رسم اش نسبت به طول و عرض اش در نظر بگیریم؟ به این معنا که مثلا ellipse مون به ابعاد 100 در 100 بود ، رسم اش ، یه 10 پیکسل از هر طرف از داخلش شروع بشه (یعنی مماس با طول و عرضش نشه) و یعنی رسم اش در ابعاد 80 در 80 باشه؟
در واقع میخوام عین margin عمل کنه منتها margin ، نسبت به کنترل های والدش عمل میکنه ولی من میخوام رسم اش نسبت به کنترل خودش margin بشه . البته این کار را با دو کنترل (مثل grid و shape) میتونم انجام بدم . ولی منظورم اینه که با یه کنترل (کنترل shape به تنهایی) میشه این کار را انجام داد و مثلا پروپرتی خاصی برای این کار نداره؟

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

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

the_king

مدیرکل انجمن
استاد ، ماه رمضان تون مبارک .
استاد ، من بخش XAML root elements and XAML namespaces در لینک زیر را خوندم :

XAML overview - WPF

اما ریزه کاری هاشو متوجه نشدم .
گاها معنی هاشو و مخصوصا مفاهیم شو .
بنابراین اون توضیحی که در بخش آخرش داد (که گفت) :

کد:
The WPF implementation of its XAML processor includes an infrastructure that has awareness of the WPF core assemblies. The WPF core assemblies are known to contain the types that support the WPF mappings to the default XAML namespace. This is enabled through configuration that is part of your project build file and the WPF build and project systems. Therefore, declaring the default XAML namespace as the default xmlns is all that is necessary in order to reference XAML elements that come from WPF assemblies.

و بنابراین نتیجه گیری کرد که استفاده از فضای نام پیش فرض (یعنی xmlns) ، برای ارجاع و ریفرنس دادن به کلاس های موجود در اسمبلی های wpf ضروری هست را متوجه نشدم .
نمیگه ضروری است، میگه is all that is necessary . یعنی تمامی چیزی است که لازمه. یعنی کاری بیشتر از این لازم نیست انجام بدهید.
یعنی برای ارجاع دادن به المنت های XAML لازم نیست کار خیلی پیچیده و عجیب و غریبی بکنید و در فکر تعریف فضای نام برای مواردی مثل System.Windows.Controls باشید، میگه فقط کافیه فضای نام پیشفرض XAML رو به عنوان xmlns پیشفرض اعلام کنید.
-------------------------------

من آخر دلیل اینکه فضای نام را با لینک url وب میدن ، متوجه نشدم . مخصوصا الان که متوجه شدم بصورت :

کد:
xmlns:System="clr-namespace:System;assembly=mscorlib"

هم فضای نام و هم اسمبلی در سی شارپ را میشه مشخص کرد .
پس اون لینک وب در اینجا نباید کاربرد داشته باشه .
بله . لینک وب میتونه در فضای نام دادن در برنامه های دیگه بجز wpf کاربرد داشته باشه اما نه در wpf که به این شیوه ای که گفتین ، میشه فضای نام کلاس هامون را مشخص کنیم .
در پست 76# عرض کردم که این url جزو تعاریف XML ئه، ربطی به نیازهای WPF و XAML نداره. استاندارد XML ئه که فضای نام در قالب url باشه، هر فرمتی که بر اساس XML طراحی بشه باید این قواعد استاندارد XML رو رعایت کنه. XML از ابتدا برای استفاده در اینترنت طراحی شده بود، برای همین از url استفاده کرده. WPF فقط داره از این استاندارد استفاده می کنه و طبعا باید قواعدش رو رعایت کنه، ممکنه یک مواردی در استاندارد XML باشه که برای XAML وجودش ضرورتی نداشته.
------------------------------
استاد ، چجوری میشه وقتی یه shape ای رسم میکنیم (مثلا ellipse) ، فاصله ای برای رسم اش نسبت به طول و عرض اش در نظر بگیریم؟ به این معنا که مثلا ellipse مون به ابعاد 100 در 100 بود ، رسم اش ، یه 10 پیکسل از هر طرف از داخلش شروع بشه (یعنی مماس با طول و عرضش نشه) و یعنی رسم اش در ابعاد 80 در 80 باشه؟
در واقع میخوام عین margin عمل کنه منتها margin ، نسبت به کنترل های والدش عمل میکنه ولی من میخوام رسم اش نسبت به کنترل خودش margin بشه . البته این کار را با دو کنترل (مثل grid و shape) میتونم انجام بدم . ولی منظورم اینه که با یه کنترل (کنترل shape به تنهایی) میشه این کار را انجام داد و مثلا پروپرتی خاصی برای این کار نداره؟
کد:
        <Ellipse Fill="SkyBlue" Width="100" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top">
            <Ellipse.RenderTransform>
                <ScaleTransform CenterX="50" CenterY="50" ScaleX="0.8" ScaleY="0.8"/>
            </Ellipse.RenderTransform>
        </Ellipse>
 

SajjadKhati

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

Routed Events Overview - WPF

در مثال اولش ، این کد را آورد :

کد:
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

حالا من میخوام در کد زیر ام:

کد:
                <TabControl Style="{StaticResource SimpleTabControl }" HorizontalAlignment="Left" Height="155" Margin="10,316,0,0" VerticalAlignment="Top" Width="400">
                    <TabItem Header="TabItem" >
                        <Grid Background="#FFE5E5E5">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="89*"/>
                                <ColumnDefinition Width="16*"/>
                                <ColumnDefinition Width="289*"/>
                            </Grid.ColumnDefinitions>
                            <Button Content="Button" HorizontalAlignment="Left" Height="39" Margin="153.25,49,0,0" VerticalAlignment="Top" Width="98" Grid.Column="2"/>
                            <CheckBox Content="CheckBox" HorizontalAlignment="Left" Height="19" Margin="10,28,0,0" VerticalAlignment="Top" Width="112" Grid.Column="2"/>
                            <Button Content="Button" HorizontalAlignment="Left" Height="39" Margin="10,63,0,0" VerticalAlignment="Top" Width="98" Grid.ColumnSpan="3"/>
                        </Grid>
                    </TabItem>
                </TabControl>

در قسمت (المنت) TabItem یا در قسمت Grid ، به عنوان attributes ، کد Button.Click="CommonClickHandler" را اضافه کنم ، وقتی مینویسم Button ، چیزی برای توی اینتلیسنس نمیاره .
چرا اونجا آورد و اینجا نمیاره؟ چی کار باید کنم بیاره؟

و اینکه Routed Events هم قابلیتی هه که میشه همه ی فرزندان یک کنترل را بصورت مشترک ، یه رویداد را براشون ست کرد . درسته؟
البته در همون لینک ، یه چیزهایی هم درباره حباب و ست شدن این نوع رویداد به المنتِ (از نظر xml) والد گفت که من زیاد متوجه نشدم .
وقتی در یک المنت ، ست میکنیم ، المنت های فرزندانش به اون هندلرِ رویداد ست میشن . دیگه به المنت والد چی کار داره؟ یعنی در مثال اون لینک (کد اول) ، به رویداد شی Border چی کار داره؟
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
استاد ، در لینک زیر (درباره ی Routed Events) :

Routed Events Overview - WPF

در مثال اولش ، این کد را آورد :

کد:
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

حالا من میخوام در کد زیر ام:

کد:
                <TabControl Style="{StaticResource SimpleTabControl }" HorizontalAlignment="Left" Height="155" Margin="10,316,0,0" VerticalAlignment="Top" Width="400">
                    <TabItem Header="TabItem" >
                        <Grid Background="#FFE5E5E5">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="89*"/>
                                <ColumnDefinition Width="16*"/>
                                <ColumnDefinition Width="289*"/>
                            </Grid.ColumnDefinitions>
                            <Button Content="Button" HorizontalAlignment="Left" Height="39" Margin="153.25,49,0,0" VerticalAlignment="Top" Width="98" Grid.Column="2"/>
                            <CheckBox Content="CheckBox" HorizontalAlignment="Left" Height="19" Margin="10,28,0,0" VerticalAlignment="Top" Width="112" Grid.Column="2"/>
                            <Button Content="Button" HorizontalAlignment="Left" Height="39" Margin="10,63,0,0" VerticalAlignment="Top" Width="98" Grid.ColumnSpan="3"/>
                        </Grid>
                    </TabItem>
                </TabControl>

در قسمت (المنت) TabItem یا در قسمت Grid ، به عنوان attributes ، کد Button.Click="CommonClickHandler" را اضافه کنم ، وقتی مینویسم Button ، چیزی برای توی اینتلیسنس نمیاره .
چرا اونجا آورد و اینجا نمیاره؟ چی کار باید کنم بیاره؟
شما به من بفرمایید چیکار کردید که آورد، برای من در هیچ کدوم از دو مثال با نوشتن Button چیزی نمیاره.
و اینکه Routed Events هم قابلیتی هه که میشه همه ی فرزندان یک کنترل را بصورت مشترک ، یه رویداد را براشون ست کرد . درسته؟
بله.
وقتی در یک المنت ، ست میکنیم ، المنت های فرزندانش به اون هندلرِ رویداد ست میشن .
ست نمیشه، اضافه میشه. اگر برای دکمه NoButton یک متد Click مجزا تعریف کنید هم اون متد ئه فراخوانی میشه و هم CommonClickHandler ئه.
دیگه به المنت والد چی کار داره؟
"به المنت والد چی کار داره" یعنی فرض رو بر این گرفته ام که Button.Click متعلق به والد ئه، در حالی که اینطور نیست.
شما وقتی در المنت Button می نویسید "Grid.Column="0، متعلق به Button ئه؟ StackPanel مشخصه Button داره که Button.Click متعلق به StackPanel باشه؟
یعنی در مثال اون لینک (کد اول) ، به رویداد شی Border چی کار داره؟
هیچ کاری. شما در کد اول رویدادی برای Border توصیف نکرده اید.
 

SajjadKhati

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

خیلی ممنون استاد .
نیاورد . سئوالم اصلا همین بود که چرا نمیاره و چی کار باید کرد که بیاره .
مثال اول که برای مایکروسافت (از اون لینکی که دادم) بود که من تست نکردم .
مثال دوم که کد خودم بود ، گفتم که نمیاره و چیکار باید کرد که بیاره؟

بله.

ست نمیشه، اضافه میشه. اگر برای دکمه NoButton یک متد Click مجزا تعریف کنید هم اون متد ئه فراخوانی میشه و هم CommonClickHandler ئه.

آها خیلی ممنون . متوجه شدم .

"به المنت والد چی کار داره" یعنی فرض رو بر این گرفته ام که Button.Click متعلق به والد ئه، در حالی که اینطور نیست.
شما وقتی در المنت Button می نویسید "Grid.Column="0، متعلق به Button ئه؟ StackPanel مشخصه Button داره که Button.Click متعلق به StackPanel باشه؟
هیچ کاری. شما در کد اول رویدادی برای Border توصیف نکرده اید.

نه . منظورم این نبود .
توی همون لینکی که دادم ، یه چیزهایی درباره ی حباب (bubble) نوشته و در توضیحش یه چیزهایی در این باره میگه که انگار Routed Event ، به المنت های والدش هم کار داره که من زیاد متوجه نشدم چی میگه :

The event route can travel in one of two directions depending on the event definition, but generally the route travels from the source element and then "bubbles" upward through the element tree until it reaches the element tree root (typically a page or a window). This bubbling concept might be familiar to you if you have worked with the DHTML object model previously.



In this simplified element tree, the source of a Click event is one of the Button elements, and whichever Button was clicked is the first element that has the opportunity to handle the event. But if no handler attached to the Button acts on the event, then the event will bubble upwards to the Button parent in the element tree, which is the StackPanel. Potentially, the event bubbles to Border, and then beyond to the page root of the element tree (not shown).

In other words, the event route for this Click event is:
Button-->StackPanel-->Border-->...
 

the_king

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

نه . منظورم این نبود .
توی همون لینکی که دادم ، یه چیزهایی درباره ی حباب (bubble) نوشته و در توضیحش یه چیزهایی در این باره میگه که انگار Routed Event ، به المنت های والدش هم کار داره که من زیاد متوجه نشدم چی میگه :
توی متن انگلیسی ای که نقل قول کردید "به المنت های والدش کار داره" ترجمه یا تفسیر کدوم کلمات بود؟
 

SajjadKhati

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

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

من که کد اول را تست نکردم . کد اول مال مایکروسافت بوده . حتما واسشون کار میکرده که گذاشتن دیگه . حتما الان اضافه شده هست که این مثال را زدن دیگه . مگه میشه چیزی که در آینده بخوان اضافه کنن ، مثالش را قبل از اون آماده کنن.

توی متن انگلیسی ای که نقل قول کردید "به المنت های والدش کار داره" ترجمه یا تفسیر کدوم کلمات بود؟

نه .
منظورم روح کلی مطلب بود .
شما هم که همیشه به ریزِ جزئیات دقت میکنین :green:
گفته :

but generally the route travels from the source element and then "bubbles" upward through the element tree until it reaches the element tree root (typically a page or a window).​

In other words, the event route for this Click event is:
Button-->StackPanel-->Border-->...​
 

the_king

مدیرکل انجمن
من که کد اول را تست نکردم . کد اول مال مایکروسافت بوده . حتما واسشون کار میکرده که گذاشتن دیگه . حتما الان اضافه شده هست که این مثال را زدن دیگه . مگه میشه چیزی که در آینده بخوان اضافه کنن ، مثالش را قبل از اون آماده کنن.
کار می کنه یک چیز ئه، اینکه در Intellisense بیاره یک چیز دیگه.
طوری نوشته شده که کلاس ای که رخداد داره بیاره و کاری به کلاس های بدون رخداد نداشته باشه، سلیقه طراح اش بوده. برای همین فرضا ButtonBase رو که Click متعلق به اونه میاره ولی Button رو که رخداد ای به ButtonBase اضافه نکرده نمیاره. حتما الان به چی اضافه شده؟ تاریخ نگارش اون صفحه و مثال اش 2017/03/30 بوده، سه سال پیش.

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

but generally the route travels from the source element and then "bubbles" upward through the element tree until it reaches the element tree root (typically a page or a window).​

In other words, the event route for this Click event is:
Button-->StackPanel-->Border-->...​
مسیر ئه، برای پیدا کردن رخداد مسیر از یک جهت یا دو جهت رو پیمایش می کنه. نه اینکه به والد یا فرزند کار داشته باشه. انگار بپرسید بانک ملی کجاست؟ بگن سمت چپ، نبش چهار راه. اون بانک متعلق به چهار راه نیست. شما هم به خود چهار راه که کاری ندارید، در مسیر بهش میرسید. وقتی در StackPanel یک Button.Click نوشته شده این Button.Click ئه خود StackPanel نیست، برای هر Button ای که در مسیر بهش برسه استفاده میشه، برای خود StackPanel هیچ کارکردی نداره، بهش ربطی نداره. برای همین نمی توانید بنویسید :
کد:
            <StackPanel>
                <StackPanel.Button Click="CommonClickHandler" />
                .
                .
                .
            </StackPanel>
 

SajjadKhati

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

استاد ، میگم من لینک زیر را کلا خوندم :

XAML overview - WPF

البته میانه هاش ، مطالب دیگه هم خوندم مثل Style & Template In Wpf و Geometry را تقریبا کامل خوندم و همچنین چندین تاپیک دیگه را بصورت سطحی نگاه کردم .
حالا میگم برای ادامه ، چه مطالبی نیازه بخونم تا با کلیات wpf آشنا بشم؟ (منظورم موارد اصلی هستن که با کلیات کار آشنا بشم) . تاپیک زیر نیازه هست . درسته؟ :

XAML Syntax In Detail - WPF

باز چه مواردی نیازه؟
 

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

بالا