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

SajjadKhati

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

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

فایل های xaml تون رو اجرا می کنه؟ شما بعد این همه توضیحات مکرر همچنان فکر می کنید فایل های xaml اجرایی هستند؟
از اون گذشته قبلا در مورد اینکه فایل های xaml به چی تبدیل می شوند توضیح داده بودم.
فایل اجرایی برنامه شما بعد کامپایل هیچ کاری به فایل های cs. و xaml. و csproj. و ... پروژه نداره، وقتی به اون فایل ها کاری نداشته باشه طبعا مسیر فایل شون هم اهمیتی نداره. دلیل اینکه چرا فایل اجرایی دیگه کاری با فایل های منبع پروژه نداره رو هم که لابد خودتون میدونید.

والا من دقیق نمیدونم .
اگه اشتباه نکنم ، قبلا درباره ی این گفته بودید که فایل های xaml بصورت مستقیم استفاده نمیشن بلکه به فایل baml تبدیل میشن و فایل baml مورد استفاده قرار میگیرن (البته میگم ، اگه اشتباه متوجه نشده باشم) .
ولی فایل baml ای هم توی پوشه ی bin ام هم وجود نداشت .

یعنی اطلاعات را کمپایل که کرد ، دیگه لازم نداره؟ بالاخره توی هارد که باید ذخیره کنه (برای استفاده برای اجرای دفعه ی بعد) . این طور نیست؟
تشکر استاد :rose:
 

the_king

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

والا من دقیق نمیدونم .
اگه اشتباه نکنم ، قبلا درباره ی این گفته بودید که فایل های xaml بصورت مستقیم استفاده نمیشن بلکه به فایل baml تبدیل میشن و فایل baml مورد استفاده قرار میگیرن (البته میگم ، اگه اشتباه متوجه نشده باشم) .
ولی فایل baml ای هم توی پوشه ی bin ام هم وجود نداشت .

یعنی اطلاعات را کمپایل که کرد ، دیگه لازم نداره؟ بالاخره توی هارد که باید ذخیره کنه (برای استفاده برای اجرای دفعه ی بعد) . این طور نیست؟
باز دارید حدس می زنید؟ در همون مطالب قبلی توضیح دادم که جزئی از Resources برنامه میشه.
شما قبلا داخل یک فایل dll رو برای کنکاش قالب DoubleUpDown دیدید، فایل های baml داخل Resources اش هم رو دیدید.
اون فایل های baml رو از روی هارد دیسک پیدا کردید یا داخل همون فایل dll؟ بر اساس مواردی که خودتون تجربه کردید جای همچین استدلالی بود؟
 

SajjadKhati

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

خیلی ممنون استاد .
پیوست نکردم . حواس رو میبینی :green:
بفرمایید . الان پیوست کردم .

باز دارید حدس می زنید؟ در همون مطالب قبلی توضیح دادم که جزئی از Resources برنامه میشه.
شما قبلا داخل یک فایل dll رو برای کنکاش قالب DoubleUpDown دیدید، فایل های baml داخل Resources اش هم رو دیدید.
اون فایل های baml رو از روی هارد دیسک پیدا کردید یا داخل همون فایل dll؟ بر اساس مواردی که خودتون تجربه کردید جای همچین استدلالی بود؟

آره استاد .
اون فایل baml ، داخل فایل dll بود .
ولی من از این قضایا زیاد سر در نمیارم (چون جریانش را از مبدا نمیدونم) و زود هم فراموش میکنم .

تشکر استاد .
 

پیوست ها

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

the_king

مدیرکل انجمن
خیلی ممنون استاد .
پیوست نکردم . حواس رو میبینی :green:
بفرمایید . الان پیوست کردم .
شما یک Style برای نوع Window ساخته اید، اما اون Window ای که دارید خود Window نیست. از نوع MyShape.MainWindow ئه، x:Class داره.
نوعش فرق داره. اون Style بصورت پیشفرض برای وارثین بکار برده نمیشه. اگر شما برای {x:Type Control} ها Style بسازید خود به خود روی Button ها اعمال نمیشه.

 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد .
استاد ، پروپرتی و رویدادهای مربوط به Keyboard Focus (مثل پروپرتی UIElement.IsKeyboardFocused یا رویدادهای مربوطه) ، فقط برای فوکوس توسط کیبرد نیستند .
یعنی مثلا وقتی توسط موس ، روی اون کنترل کلیک میشه (که باعث فوکوس شدن روی اون کنترل میشه) هم باعث اجرای این رویدادها یا مقدارِ true گرفتنِ این پروپرتی UIElement.IsKeyboardFocused میشه .
روشی وجود داره که متوجه بشیم که آیا فقط و فقط توسط کیبرد فوکوس شده یا نه؟

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

تشکر استاد .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
استاد ، پروپرتی و رویدادهای مربوط به Keyboard Focus (مثل پروپرتی UIElement.IsKeyboardFocused یا رویدادهای مربوطه) ، فقط برای فوکوس توسط کیبرد نیستند .
یعنی مثلا وقتی توسط موس ، روی اون کنترل کلیک میشه (که باعث فوکوس شدن روی اون کنترل میشه) هم باعث اجرای این رویدادها یا مقدارِ true گرفتنِ این پروپرتی UIElement.IsKeyboardFocused میشه .
روشی وجود داره که متوجه بشیم که آیا فقط و فقط توسط کیبرد فوکوس شده یا نه؟
IsKeyboardFocused به این معنی نیست که توسط Keyboard عمل Focus صورت گرفته. معنی اش اینه که حالا Keyboard روی این المنت Focus داره یا نداره، کاری به این نداره چرا و توسط کدوم عامل Focus منتقل شده. برای همین اینکه عامل Focus چی بوده دخالتی در این قضیه نداره. اگر شما با کد نویسی هم Focus رو روی اون المنت انتقال بدهید، نه صفحه کلید و نه ماوس و نه هیچ ابزار دیگری عامل انتقال Focus نبوده اند ولی به هر حال Keyboard روی این المنت Focus خواهد داشت.
رخداد هایی مثل PreviewMouseDown قبل از GotKeyboardFocus اتفاق می افته، پس میشه با تغییر مقدار یک متغیر در رخداد هایی مثل PreviewMouseDown و LostKeyboardFocus مشخص کرد که الان چه عاملی میخواد Focus رو انتقال بده.
 

SajjadKhati

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

XML:
        <ControlTemplate x:Key="ToolTipTemplate" TargetType="{x:Type ToolTip}">
            <Grid>
                <Path Name="BallonPath" Stroke="White" StrokeThickness="2" Fill="#FF0A0A0A">
                    <Path.Data>
                        <CombinedGeometry GeometryCombineMode="Union" Geometry1="M15,40 L15,55 L25,40">
                            <CombinedGeometry.Geometry2>
                                <RectangleGeometry  Rect="1,  1, 100, 40" RadiusX="10" RadiusY="10"/>
                            </CombinedGeometry.Geometry2>
                        </CombinedGeometry>
                    </Path.Data>
                </Path>
            </Grid>
        </ControlTemplate>

آیا روشی هست که بجای اینکه صریحا مقدار Rect ئه RectangleGeometry را بدم ، بتونم یه چیزی شبیه به HorizontalAlignment ئه کنترل ها را مقدار Stretch میذارن و باعث میشه کنترل جاری ، به اندازه ی کل محدوده ی کنترل والد (تا جایی که امکان پذیره) بشه ، میتونم یه چیزی شبیه به این عمل را برای RectangleGeometry پیاده سازی کنم تا بصورت مستقیم مقدار Rect اش را مقداردهی نکنم تا به اندازه ی المنت Path اش (که والدش هست) بشه؟

تشکر استاد .
 

the_king

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

XML:
        <ControlTemplate x:Key="ToolTipTemplate" TargetType="{x:Type ToolTip}">
            <Grid>
                <Path Name="BallonPath" Stroke="White" StrokeThickness="2" Fill="#FF0A0A0A">
                    <Path.Data>
                        <CombinedGeometry GeometryCombineMode="Union" Geometry1="M15,40 L15,55 L25,40">
                            <CombinedGeometry.Geometry2>
                                <RectangleGeometry  Rect="1,  1, 100, 40" RadiusX="10" RadiusY="10"/>
                            </CombinedGeometry.Geometry2>
                        </CombinedGeometry>
                    </Path.Data>
                </Path>
            </Grid>
        </ControlTemplate>

آیا روشی هست که بجای اینکه صریحا مقدار Rect ئه RectangleGeometry را بدم ، بتونم یه چیزی شبیه به HorizontalAlignment ئه کنترل ها را مقدار Stretch میذارن و باعث میشه کنترل جاری ، به اندازه ی کل محدوده ی کنترل والد (تا جایی که امکان پذیره) بشه ، میتونم یه چیزی شبیه به این عمل را برای RectangleGeometry پیاده سازی کنم تا بصورت مستقیم مقدار Rect اش را مقداردهی نکنم تا به اندازه ی المنت Path اش (که والدش هست) بشه؟

تشکر استاد .
این سوال و جواب رو ببینید :
 

SajjadKhati

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

خیلی ممنون استاد .
ای کاش من قابلیت جستجوی شما را داشتم (جستجو کرده بودم ولی این تاپیک را پیدا نکردم) :rose:
پس باید از MultiBinding و همچنین از MultiConverter استفاده کنیم .
استاد ، در کدهای زیر که نوشته بود :

C#:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
    // you can pass in the value to divide by if you want
    return new Rect(0, 0, (double)values[0], (double)values[1] / 3.33);
}

و همچنین :

XML:
<RectangleGeometry.Rect>
        <MultiBinding Converter="{StaticResource rectConverter}">
            <Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType={x:Type Button}}" />
            <Binding Path="ActualHeight" RelativeSource="{RelativeSource AncestorType={x:Type Button}}" />
        </MultiBinding>
    </RectangleGeometry.Rect>

وقتی درون کد سی شارپ ، مقدار values[0] فراخونی شد ، یعنی اولین خط از کدی که درون MultiBinding (در xaml که converter اش از نوع همین کلاسی که متد Convert پیاده سازی شد) ، عمل بایندینگ انجام شد ، اون رو به عنوان مقدار values[0] در نظر میگیره؟

و همچنین چون در کد xaml بالا ، دو تا بایندینگ (از نوع Converter ئه همین کلاسی که متد Convert پیاده سازی شد) ، براش تعریف شد ، پس در متد Convert در کد سی شارپ ، پارامتر values ما هم حاوی 2 تا عضو هست که اولیش برابر با ActualWidth ئه Button والد و دومی هم برابر با ActualHeight اش هست . درسته؟


بعد اینکه من میخواستم با کد xaml کار کنم . حالا که کد سی شارپ هم قراره وسط بیاد ، به نظرتون بهتر نیست بجای پیاده سازی اینترفیس MultiConverter ، کلا یه کلاسی تعریف کنم که از کلاس ToolTip ارث بری کنه و بجای متد Convert (در قضیه ی MultiConverter) هم یه پروپرتی تعریف کنم که این کارها را انجام بده؟
یا این روشی که گفت (پیاده سازی اینترفیس MultiConverter) بهتره؟

تشکر استاد .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
ای کاش من قابلیت جستجوی شما را داشتم (جستجو کرده بودم ولی این تاپیک را پیدا نکردم) :rose:
پس باید از MultiBinding و همچنین از MultiConverter استفاده کنیم .
نه الزاما، اون فرد چون خواسته مقدار Width و Height رو بده MultiConverter ساخته، شاید شما ترجیح بدهید که بجای طول و عرض، خود المنت رو بدهید و در خود Converter ابعادش رو برداره.
وقتی درون کد سی شارپ ، مقدار values[0] فراخونی شد ، یعنی اولین خط از کدی که درون MultiBinding (در xaml که converter اش از نوع همین کلاسی که متد Convert پیاده سازی شد) ، عمل بایندینگ انجام شد ، اون رو به عنوان مقدار values[0] در نظر میگیره؟
بله، اعضاء آرایه است. میتونه ده تا Binding پشت سر هم باشه و یک آرایه 10 عضوی بگیره.
و همچنین چون در کد xaml بالا ، دو تا بایندینگ (از نوع Converter ئه همین کلاسی که متد Convert پیاده سازی شد) ، براش تعریف شد ، پس در متد Convert در کد سی شارپ ، پارامتر values ما هم حاوی 2 تا عضو هست که اولیش برابر با ActualWidth ئه Button والد و دومی هم برابر با ActualHeight اش هست . درسته؟
بله.
بعد اینکه من میخواستم با کد xaml کار کنم . حالا که کد سی شارپ هم قراره وسط بیاد ، به نظرتون بهتر نیست بجای پیاده سازی اینترفیس MultiConverter ، کلا یه کلاسی تعریف کنم که از کلاس ToolTip ارث بری کنه و بجای متد Convert (در قضیه ی MultiConverter) هم یه پروپرتی تعریف کنم که این کارها را انجام بده؟
یا این روشی که گفت (پیاده سازی اینترفیس MultiConverter) بهتره؟
پیشنهادی ندارم، هیچ روشی بهتر نیست، سلیقه و علایق خودتون مطرحه. فقط مساله اینجا است که اگر کلاسی بر پایه ToolTip بسازید کاری رو فقط برای کلاس خودتون کرده اید و اگر برای کلاس دیگری هم لازم باشه دیگه اون پیاده سازی قبلی بدردش نمیخوره، اما اگر Converter ای (حالا نه الزاما Multi) بسازید برای هر نوع المنتی بجز ToolTip هم میتونه قابل استفاده باشه.
 

SajjadKhati

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


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

اگه متوجه شدید ، چی کار باید کنم؟ از چه متد یا روشی استفاده کنم؟

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

بعد اینکه نمیدونم مایکروسافت چرا توی Tooltip در wpf ، پروپرتی هایی که برای کنترل زمان برای نمایش tooltip هست را در کلاس ToolTipService ارائه کرد . پروپرتی هایی مثل ShowDuration و BetweenShowDelay و InitialShowDelay .
خوب مثل winform ، در همون کلاس tooltip ارائه میکرد دیگه . مخصوصا اینکه برای تاخیر انداختن (زمانی که یه tooltip در حال نمایش هست و فورا موس را روی یه کنترل دارای tooltip ئه دیگه ببریم) ، پروپرتی BetweenShowDelay را برای اینکار بصورت مجزا ارائه کرد که اون هم باید روی هر دو کنترل ، (مقدار 0 را) تنظیم کنیم .

تشکر استاد .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
استاد ، در سی شارپ ، متد VisualTreeHelper.GetChild :


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

اگه متوجه شدید ، چی کار باید کنم؟ از چه متد یا روشی استفاده کنم؟
بعضی المنت ها هستند که از خانواده Panel ها هستند و فرزند دارند، مثلا Grid یا StackPanel
و اگه فرضا دو تا Button داخلشون قرار بدهید، Children اش می شوند، مثل Grid1.Children و StackPanel1.Children که شبیه همون Controls در Windows Forms ئه.
اما اگر فرضا در Button که Children نمیتونه داشته باشه یک Grid رو قرار بدهید، اون Grid فرزندش نیست، محتوا شه، Content ئه، Content هم نوع اصلی اش object ئه، میتونه Grid باشه یا هر شیء دیگری. مثلا Button1.Content میتونه null باشه یا یک string یا یک ComboBox یا هر چیز دیگری.

بعد اینکه نمیدونم مایکروسافت چرا توی Tooltip در wpf ، پروپرتی هایی که برای کنترل زمان برای نمایش tooltip هست را در کلاس ToolTipService ارائه کرد . پروپرتی هایی مثل ShowDuration و BetweenShowDelay و InitialShowDelay .
خوب مثل winform ، در همون کلاس tooltip ارائه میکرد دیگه . مخصوصا اینکه برای تاخیر انداختن (زمانی که یه tooltip در حال نمایش هست و فورا موس را روی یه کنترل دارای tooltip ئه دیگه ببریم) ، پروپرتی BetweenShowDelay را برای اینکار بصورت مجزا ارائه کرد که اون هم باید روی هر دو کنترل ، (مقدار 0 را) تنظیم کنیم .
اگه توضیحات ToolTipService رو بخونید خیلی خوب و کامل این مساله رو توضیح داده. ساختار ToolTip در Windows Forms هم تفاوت زیادی با ToolTip در WPF داره، اون با IExtenderProvider صرفا یک مشخصه برای متن ToolTip به کنترل اضافه میکرد، یعنی داده خود کمپوننت ToolTip بود که ظاهری در لیست مشخصه های یک کنترل دیگه نمایش داده میشد. اما در WPF هر المنت میتونه نه تنها متن ToolTip داشته باشه که حتی برای خودش یک شیء ToolTip با سفارشی سازی های خاص و مجزا توصیف کنه، کلا یه معماری دیگه است. حالا این ToolTip های مجزا بخوان تنظیمات اشتراکی داشته باشند باید تعداد زیادی مشخصه الحاقی باشه. و اگر یکسری ToolTip بخوان تنظیمات خاص منحصر بفرد داشته باشند یکسری تنظیمات غیر الحاقی لازمه.
اگه ToolTipService به اون شکل مشخصه های الحاقی رو تفکیک شده ارائه نمی کرد هم معماری ToolTip ها انعطاف پذیری کمتری داشت و هم تفکیک تنظیمات اشتراکی و انحصاری دشوار میشد.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بعضی المنت ها هستند که از خانواده Panel ها هستند و فرزند دارند، مثلا Grid یا StackPanel
و اگه فرضا دو تا Button داخلشون قرار بدهید، Children اش می شوند، مثل Grid1.Children و StackPanel1.Children که شبیه همون Controls در Windows Forms ئه.
اما اگر فرضا در Button که Children نمیتونه داشته باشه یک Grid رو قرار بدهید، اون Grid فرزندش نیست، محتوا شه، Content ئه، Content هم نوع اصلی اش object ئه، میتونه Grid باشه یا هر شیء دیگری. مثلا Button1.Content میتونه null باشه یا یک string یا یک ComboBox یا هر چیز دیگری.

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

اما مشکل من اینه که میخوام همه ی اینها را جستو کنم (تا مقدار attached property ئه BetweenShowDelay و InitialShowDelay و ShowDuration ئه همه ی اون کنترل ها را تنظیم کنم) .
اما Window جزء ContentControl هاست . از اون طرف هم panel ها را داریم که child دارن که ترکیب شون کار را قر و قاتی میکنه .

کلا میخوام هر چی پنل یا ContentControl ای که هست (اون ContentControl چه بخواد Window باشه یا Button یا هر چیز دیگه) و داخل شون هر UIElement ای که بود را برام پیدا کنه .

با این متد VisualTreeHelper.GetChild هم تنها مشکلی که دارم اینه که میره مثلا tooltip رو برای کنترلی که تنظیم کردم را هم پیدا میکنه (در صورتی که پروپرتی tooltip که جزء content یا child محسوب نمیشه که به حسابش میاره) و همچنین میره المنت هایی که در تمپلیت ها (ی این tooltip و کلا المنت ها در در تمپلیت های) مربوط به اون را هم پیدا میکنه .
اگه روشی باشه که متوجه شیم که بتونیم فقط المنت هایی که در پروپرتیِ child و content ئه کنترل ها بکار بردیم را جدا کنیم و همچنین کنترل های پیدا شده در تمپلیت ها را هم جدا کنیم ، فکر نکنم دیگه با این متد مشکلی میداشتم .

اگه توضیحات ToolTipService رو بخونید خیلی خوب و کامل این مساله رو توضیح داده. ساختار ToolTip در Windows Forms هم تفاوت زیادی با ToolTip در WPF داره، اون با IExtenderProvider صرفا یک مشخصه برای متن ToolTip به کنترل اضافه میکرد، یعنی داده خود کمپوننت ToolTip بود که ظاهری در لیست مشخصه های یک کنترل دیگه نمایش داده میشد. اما در WPF هر المنت میتونه نه تنها متن ToolTip داشته باشه که حتی برای خودش یک شیء ToolTip با سفارشی سازی های خاص و مجزا توصیف کنه، کلا یه معماری دیگه است. حالا این ToolTip های مجزا بخوان تنظیمات اشتراکی داشته باشند باید تعداد زیادی مشخصه الحاقی باشه. و اگر یکسری ToolTip بخوان تنظیمات خاص منحصر بفرد داشته باشند یکسری تنظیمات غیر الحاقی لازمه.
اگه ToolTipService به اون شکل مشخصه های الحاقی رو تفکیک شده ارائه نمی کرد هم معماری ToolTip ها انعطاف پذیری کمتری داشت و هم تفکیک تنظیمات اشتراکی و انحصاری دشوار میشد.

تشکر استاد از توضیح کامل تون .
من دقیق متوجه نشدم .
پس چرا برای پروپرتی های دیگه ی tooltip این کار را نکردن؟
مثلا چرا پروپرتیِ Placement و خیلی های دیگه را بصورت شی گرا در tooltip گذاشتن اما پروپرتی های مربوط به زمان را بصورت attached property این کار را کردن!
تشکر استاد .
 
آخرین ویرایش:

the_king

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

اما مشکل من اینه که میخوام همه ی اینها را جستو کنم (تا مقدار attached property ئه BetweenShowDelay و InitialShowDelay و ShowDuration ئه همه ی اون کنترل ها را تنظیم کنم) .
اما Window جزء ContentControl هاست . از اون طرف هم panel ها را داریم که child دارن که ترکیب شون کار را قر و قاتی میکنه .

کلا میخوام هر چی پنل یا ContentControl ای که هست (اون ContentControl چه بخواد Window باشه یا Button یا هر چیز دیگه) و داخل شون هر UIElement ای که بود را برام پیدا کنه .

با این متد VisualTreeHelper.GetChild هم تنها مشکلی که دارم اینه که میره مثلا tooltip رو برای کنترلی که تنظیم کردم را هم پیدا میکنه (در صورتی که پروپرتی tooltip که جزء content یا child محسوب نمیشه که به حسابش میاره) و همچنین میره المنت هایی که در تمپلیت ها (ی این tooltip و کلا المنت ها در در تمپلیت های) مربوط به اون را هم پیدا میکنه .
اگه روشی باشه که متوجه شیم که بتونیم فقط المنت هایی که در پروپرتیِ child و content ئه کنترل ها بکار بردیم را جدا کنیم و همچنین کنترل های پیدا شده در تمپلیت ها را هم جدا کنیم ، فکر نکنم دیگه با این متد مشکلی میداشتم .
تعاریف خودتونه که قاطی پاتی ئه، VisualTreeHelper.GetChild فرزندان بصری المنت رو تحویل میده، که ToolTip و هر جزء بصری دیگری که به هر ترتیبی ظاهر المنت رو بوجود آورده شامل میشه. اینکه شما از اجزاء بصری تعریف درستی ندارید یا ToolTip رو به حساب نمیارید که ایراد GetChild نیست. کدوم پروپرتی Child مد نظرتونه؟ و در #C برای اینکه تطابق نوع یک شیء با مورد خاصی رو بررسی کنند، از is و ()GetType و as و ... استفاده میشه.

تشکر استاد از توضیح کامل تون .
من دقیق متوجه نشدم .
پس چرا برای پروپرتی های دیگه ی tooltip این کار را نکردن؟
مثلا چرا پروپرتیِ Placement و خیلی های دیگه را بصورت شی گرا در tooltip گذاشتن اما پروپرتی های مربوط به زمان را بصورت attached property این کار را کردن!
مثال تون با سوال تون مطابقت داره؟ ToolTipService.Placement مربوط به زمان نیست، attached property هم هست.
گمان نمی کنم توضیحات ToolTipService رو خونده باشید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
تعاریف خودتونه که قاطی پاتی ئه، VisualTreeHelper.GetChild فرزندان بصری المنت رو تحویل میده، که ToolTip و هر جزء بصری دیگری که به هر ترتیبی ظاهر المنت رو بوجود آورده شامل میشه. اینکه شما از اجزاء بصری تعریف درستی ندارید یا ToolTip رو به حساب نمیارید که ایراد GetChild نیست. کدوم پروپرتی Child مد نظرتونه؟

خیلی ممنون استاد .
الان منظور مایکروسافت از فرزندان بصری ، دقیقا چجوری هه؟
کد زیر را در نظر بگیرید (هیچ کدِ اضافه ترِ دیگه ای نداره . یعنی در Application و قسمت های دیگه اش ، منابع و Resource ئه دیگه ای وجود نداره) :

XML:
<Window x:Class="Wpf_GetChild.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Name="MyMainWindow" Title="MainWindow" Width="600" Height="400" Loaded="MyMainWindow_Loaded">

    <Grid Name="MainGrid">
        <Button Name="Button_1" Content="Button_1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Height="30" Margin="10" />
       
        <CheckBox Name="CheckBox_1" Content="CheckBox_1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Height="30" Margin="120, 10 , 0, 0" />

        <Button Name="Button_2"  HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Height="30" Margin="220, 10, 0, 0" >
            <Rectangle Name="ContentRectangle" Width="50" Height="20" Stroke="Blue"  StrokeThickness="3"/>
        </Button>
    </Grid>
   
</Window>

خروجیِ این کد ، در پنلِ Live Visual Tree ، شکل زیر هست :

1.JPG

انتظار من از فرزندان بصری (در کد xaml بالا) هم یه همچین شکلی هست .
اما وقتی من کد زیر را (در رویداد Load ئه Window) اجرا میکنم :

C#:
            int childCount = VisualTreeHelper.GetChildrenCount(this);
            DependencyObject obj = VisualTreeHelper.GetChild(this, 0);

شیِ Border را به من برمیگردونه . در کد بالا ، اصلا Border ای به عنوان فرزند (یا نوادگانِ) Window بکار نرفت همونطور که میبینید .
منظورش از Border ، استایل و تمپلیتِ پیش فرض برای یکی از کنترل هایی که در کد بالا توسط مایکروسافت استفاده شده هست؟ چون من که نه استایل و نه هیچ تمپلیت ای در پروژه ی بالا برای هیچ کنترلی استفاده نکردم .

کلا میخوام بگم که متد VisualTreeHelper.GetChild ، چیزهایی که میخوام (این کنترل هایی که بصورت درخت در عکس بالا هستند) را برمیگردونه اما علاوه بر اون ، بسیاری از کنترل ها و المنت های دیگه که معلوم نیست چی و از کجا بوجود اومدن را هم همراشون برمیگردونه .

کد کامل اینه (در رویداد لود ویندوز) :

C#:
            foreach (Visual visualChildrens in this.FindAllElement(this))
            {

            }

و متد :

C#:
        private IEnumerable<Visual> FindAllElement(Visual parent)
        {
            if (parent != null)
            {
                int parentChildsCount = VisualTreeHelper.GetChildrenCount(parent);
                for (int parentChildsIterator = 0; parentChildsIterator < parentChildsCount; parentChildsIterator++)
                {
                    DependencyObject parentsChild = VisualTreeHelper.GetChild(parent, parentChildsIterator);
                    if (parentsChild != null && parentsChild is Visual)
                    {
                        yield return (Visual)parentsChild;

                        foreach (Visual childOfChild in this.FindAllElement(parentsChild as Visual))
                        {
                            yield return childOfChild;
                        }
                    }
                }
            }
        }

اما همونطور که گفتم ، خیلی از المنت های دیگه که معلوم نیستن چی هستن و از کجا اومدن را هم برمیگردونه که نمیدونم چجوری میشه از المنت هایی که خودم نوشتم (و مثل عکس بالا میخوام بدست بیارم) ، جداشون کنم؟

و در #C برای اینکه تطابق نوع یک شیء با مورد خاصی رو بررسی کنند، از is و ()GetType و as و ... استفاده میشه.

بله میدونم .
منظورم یه چیز دیگه بود (چیزی که در بالا توضیح دادم بود) .

مثال تون با سوال تون مطابقت داره؟ ToolTipService.Placement مربوط به زمان نیست، attached property هم هست.
گمان نمی کنم توضیحات ToolTipService رو خونده باشید.

منظورم پروپرتی Placement ئه کلاس ToolTip بود .

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

the_king

مدیرکل انجمن
خیلی ممنون استاد .
الان منظور مایکروسافت از فرزندان بصری ، دقیقا چجوری هه؟
چرا مستنداتشو نمیخونید؟ هم توضیح داده که visual tree شامل چیه و هم ازش مثال زده و هم نوع مشترک بین فرزندان رو مشخص کرده.

کد زیر را در نظر بگیرید (هیچ کدِ اضافه ترِ دیگه ای نداره . یعنی در Application و قسمت های دیگه اش ، منابع و Resource ئه دیگه ای وجود نداره) :

XML:
<Window x:Class="Wpf_GetChild.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Name="MyMainWindow" Title="MainWindow" Width="600" Height="400" Loaded="MyMainWindow_Loaded">

    <Grid Name="MainGrid">
        <Button Name="Button_1" Content="Button_1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Height="30" Margin="10" />
      
        <CheckBox Name="CheckBox_1" Content="CheckBox_1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Height="30" Margin="120, 10 , 0, 0" />

        <Button Name="Button_2"  HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Height="30" Margin="220, 10, 0, 0" >
            <Rectangle Name="ContentRectangle" Width="50" Height="20" Stroke="Blue"  StrokeThickness="3"/>
        </Button>
    </Grid>
  
</Window>

خروجیِ این کد ، در پنلِ Live Visual Tree ، شکل زیر هست :

مشاهده پیوست 113772

انتظار من از فرزندان بصری (در کد xaml بالا) هم یه همچین شکلی هست .
اما وقتی من کد زیر را (در رویداد Load ئه Window) اجرا میکنم :

C#:
            int childCount = VisualTreeHelper.GetChildrenCount(this);
            DependencyObject obj = VisualTreeHelper.GetChild(this, 0);

شیِ Border را به من برمیگردونه . در کد بالا ، اصلا Border ای به عنوان فرزند (یا نوادگانِ) Window بکار نرفت همونطور که میبینید .
منظورش از Border ، استایل و تمپلیتِ پیش فرض برای یکی از کنترل هایی که در کد بالا توسط مایکروسافت استفاده شده هست؟ چون من که نه استایل و نه هیچ تمپلیت ای در پروژه ی بالا برای هیچ کنترلی استفاده نکردم .
انتظار شما که قرار نیست روال چیزی رو تعیین کنه، شما در پنجره Properties هم الزاما همه مشخصه ها رو نمی بینید، اینکه در پنجره Properties چی می بینید که کارکرد Type.GetProperties رو تعیین نمی کنه.

visual-png.113773



کلا میخوام بگم که متد VisualTreeHelper.GetChild ، چیزهایی که میخوام (این کنترل هایی که بصورت درخت در عکس بالا هستند) را برمیگردونه اما علاوه بر اون ، بسیاری از کنترل ها و المنت های دیگه که معلوم نیست چی و از کجا بوجود اومدن را هم همراشون برمیگردونه .

کد کامل اینه (در رویداد لود ویندوز) :

C#:
            foreach (Visual visualChildrens in this.FindAllElement(this))
            {

            }

و متد :

C#:
        private IEnumerable<Visual> FindAllElement(Visual parent)
        {
            if (parent != null)
            {
                int parentChildsCount = VisualTreeHelper.GetChildrenCount(parent);
                for (int parentChildsIterator = 0; parentChildsIterator < parentChildsCount; parentChildsIterator++)
                {
                    DependencyObject parentsChild = VisualTreeHelper.GetChild(parent, parentChildsIterator);
                    if (parentsChild != null && parentsChild is Visual)
                    {
                        yield return (Visual)parentsChild;

                        foreach (Visual childOfChild in this.FindAllElement(parentsChild as Visual))
                        {
                            yield return childOfChild;
                        }
                    }
                }
            }
        }

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

بله میدونم .
منظورم یه چیز دیگه بود (چیزی که در بالا توضیح دادم بود) .
منظورم پروپرتی Placement ئه کلاس ToolTip بود .
خودتون میگید "پروپرتی های مربوط به زمان را بصورت attached property این کار را کردن!"، مگه پروپرتی های نامرتبط با زمان رو بصورت attached property نداشتن؟ اون Placement که میگید در ToolTip هست در ToolTipService هم هست، ربطی هم به زمان نداره.
 

پیوست ها

  • visual.png
    visual.png
    40.8 کیلوبایت · بازدیدها: 9

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
چرا مستنداتشو نمیخونید؟ هم توضیح داده که visual tree شامل چیه و هم ازش مثال زده و هم نوع مشترک بین فرزندان رو مشخص کرده.


انتظار شما که قرار نیست روال چیزی رو تعیین کنه، شما در پنجره Properties هم الزاما همه مشخصه ها رو نمی بینید، اینکه در پنجره Properties چی می بینید که کارکرد Type.GetProperties رو تعیین نمی کنه.

visual-png.113773




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

آها ، خیلی ممنون استاد :rose:
کلا 2 نوع درخت در wpf داریم :

بصورت خلاصه ، یه درختی که من شکل اش را در 595 دادم . که شامل المنت و کنترل هایی هست که به Window مون اضافه میکنیم (و شاید بشه گفت واقعی هستند . حالا نمیدونم چه اصطلاحی را به کار ببرم براش) . به این نوع درخت ، Logical Tree میگن (همون چیزی که در اینجا مد نظرمه) . و با کلاس LogicalTreeHelper میشه پیمایش این نوع درخت را انجام داد .

یک نوع دیگه ، درختی که علاوه بر درخت منطقی (Logical Tree) ، شامل تمام المنت ها و کنترل هایی که به عنوان template ، برای تمام المنت ها و کنترل های Logical Tree استفاده شده ، هست که در شکل پست 596 (احتمالا با غیر فعال کردن گزینه ی Show just My Xaml) نشون دادید . به این نوع درخت ، Visual Tree میگن .
درست میگم؟

که در سایت زیر ، بصورت خلاصه با شکل توضیح داد :


البته در سایت مایکروسافت با جزئیات بیشتری توضیح داد اما چون شکل نداره و اینها ، درکش سخت تره .


خودتون میگید "پروپرتی های مربوط به زمان را بصورت attached property این کار را کردن!"، مگه پروپرتی های نامرتبط با زمان رو بصورت attached property نداشتن؟ اون Placement که میگید در ToolTip هست در ToolTipService هم هست، ربطی هم به زمان نداره.

پروپرتی های نامرتبط با زمان (مثل همین Placement) رو بصورت attached property در ToolTipService داشتن اما همه ی اونها را بصورت پروپرتیِ شی گرا ، در کلاس ToolTip هم گذاشتن .
تنها ، پروپرتی های مرتبط با زمان (مثل InitialShowDelay و ...) را در کلاس ToolTip نذاشتن که دقیق متوجه نشدم چرا اینها را نذاشتن و اونها را گذاشتن (در کلاس ToolTip) .

تشکر استاد
 

the_king

مدیرکل انجمن
آها ، خیلی ممنون استاد :rose:
کلا 2 نوع درخت در wpf داریم :
نه، از رفتار دو تا کلاس همچین نتیجه ای نمیشه گرفت. این محدودیت در انواع درخت در WPF نیست، صرفا دو تا کلاس با رفتار متفاوت بصورت پیشفرض ارائه شده. محدود به تعداد خاصی معنی نمیده. از درخت اشیاء (object tree) که همه شیء ها رو شامل میشه، دو تا کلاس به نام های LogicalTreeHelper و VisualTreeHelper به شیوه خودشون یکسری اجزاء رو جدا میکنن و ارائه میدن. شما یا هر شخص دیگری ممکنه کلاس های دیگری بسازه که با شرایط و معیار های دیگه ای اجزاء ای رو برگردونده. از اینکه دو کلاس هست که فلان معیار ها رو دارند نمیتونیم نتیجه بگیریم که در WPF این تعداد درخت هست.

بصورت خلاصه ، یه درختی که من شکل اش را در 595 دادم . که شامل المنت و کنترل هایی هست که به Window مون اضافه میکنیم (و شاید بشه گفت واقعی هستند . حالا نمیدونم چه اصطلاحی را به کار ببرم براش) . به این نوع درخت ، Logical Tree میگن (همون چیزی که در اینجا مد نظرمه) . و با کلاس LogicalTreeHelper میشه پیمایش این نوع درخت را انجام داد.

یک نوع دیگه ، درختی که علاوه بر درخت منطقی (Logical Tree) ، شامل تمام المنت ها و کنترل هایی که به عنوان template ، برای تمام المنت ها و کنترل های Logical Tree استفاده شده ، هست که در شکل پست 596 (احتمالا با غیر فعال کردن گزینه ی Show just My Xaml) نشون دادید . به این نوع درخت ، Visual Tree میگن .
درست میگم؟
بله. البته تعریف کردن کارکرد دو تا کلاس با چند جمله عملی نیست، ریزه کاری دارن.

پروپرتی های نامرتبط با زمان (مثل همین Placement) رو بصورت attached property در ToolTipService داشتن اما همه ی اونها را بصورت پروپرتیِ شی گرا ، در کلاس ToolTip هم گذاشتن .
تنها ، پروپرتی های مرتبط با زمان (مثل InitialShowDelay و ...) را در کلاس ToolTip نذاشتن که دقیق متوجه نشدم چرا اینها را نذاشتن و اونها را گذاشتن (در کلاس ToolTip) .
اگه توضیحات کلاس ToolTipService رو کامل بخونید متوجه میشید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
استاد طراحی فرزندان زیر را در نظر بگیرید :

XML:
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ToolTipsValueConverter="clr-namespace:ToolTipsValueConverter"
        xmlns:local="clr-namespace:WPF_Practice"
        xmlns:System="clr-namespace:System;assembly=mscorlib" x:Class="WPF_Practice.NewWindow"
        mc:Ignorable="d"
        Title="NewWindow" Height="450" Width="800" Loaded="Window_Loaded">
   

    <Grid x:Name="Grid1" Background="#FF282828">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>




        <StackPanel x:Name="StackPanel1" Grid.Row="1" Orientation="Horizontal">

            <Button ToolTipService.InitialShowDelay="5000"  ToolTipService.BetweenShowDelay="0" x:Name="MyButton1" MouseEnter="Button_MouseEnter" MouseLeave="Button_MouseLeave" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" Width="80" Height="30" Content="ToolTip Salam">
                <Button.ToolTip>
                    <ToolTip  Content="توضیحات به عنوان تولتیپ"/>
                </Button.ToolTip>
            </Button>

            <Button ToolTipService.InitialShowDelay="5000" ToolTipService.BetweenShowDelay="0" x:Name="MyButton2" MouseEnter="Button_MouseEnter" MouseLeave="Button_MouseLeave" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" Width="80" Height="30" Content="ToolTip Test">
                <Button.ToolTip>
                    <ToolTip Content="دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذ دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذ دکمه 1  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذ دکمه 2  تست میشود  لت بت دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذت ت ن لن نا ن نبت اتیغسی سشنم تکت دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذ بلزت یسلسیاک کسثفثسقغ ک ذ                              دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسی o ho o ho ho o gogo gog oاک کسثفثسقغ ک ذ"/>
                </Button.ToolTip>
            </Button>

            <ComboBox Name="ComboBox1" Width="150" Height="23">
                <System:String>salam</System:String>
                <System:String>khobi?</System:String>
                <CheckBox Name="CombxCheckBox1"/>
            </ComboBox>

            <TabControl Name="TabControl1" Width="300" Height="200" Margin="20" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <TabItem Name="TabItem1" Header="salam">
                    <Grid Name="TabItemGrid1">
                        <TextBox Name="TextBox1"/>
                        <ListBox Name="ListBox1"/>
                    </Grid>
                </TabItem>

                <TabItem Name="TabItem2" Header="khobi">
                    <ListView Name="ListView1"/>
                </TabItem>
            </TabControl>

        </StackPanel>

    </Grid>


</Window>

حالا در کد زیر :

C#:
        private void Window_Loaded(object sender, RoutedEventArgs e)

        {



            foreach (FrameworkElement visualChildrens in this.FindParentElements<FrameworkElement>(this))

            {

                if (visualChildrens != null)

                    MessageBox.Show(visualChildrens.Name);

            }



        }



        private IEnumerable<T> FindParentElements<T>(T parent) where T : DependencyObject

        {

            if (parent == null)

                yield return null;



            IEnumerable<object> childrens = LogicalTreeHelper.GetChildren(parent).Cast<object>();

            //int childrensCount = childrens.Count<object>();

            if (childrens == null /*|| childrensCount < 1*/)

                yield return null;



            foreach (object child in childrens)

            {

                if (child is T)

                {

                    yield return (T)child;

                    foreach (T childOfChild in this.FindParentElements(child as T))

                    {

                        yield return childOfChild;

                    }

                }

            }

        }

در کد بالا هیچ مشکلی نیست .
اما اگه کامنت کد سی شارپ در بالا را بردارین ، اون foreach درون متد ، اجرا نمیشه با اونکه مقدارش بزرگتر از صفر هست .
همچنین یه چیز عجیب اینکه اگه بعد از اجرای متد LogicalTreeHelper.GetChildren ، خروجیِ childrens اش را تریس کنیم ، و مقدار resoult اش را ببیینیم ، در کمال تعجب ، مقداری که قبلا داشت ، empty میشه و انگار null میشه و در کدهای بعدی ، رفتارش انگار با مقدار nullرفتار میکنه اما مقدارشو نبینیم ، مشکلی نداره .

علت این دو تا مشکل چیه؟
تشکر
 

the_king

مدیرکل انجمن
سلام
استاد طراحی فرزندان زیر را در نظر بگیرید :

XML:
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ToolTipsValueConverter="clr-namespace:ToolTipsValueConverter"
        xmlns:local="clr-namespace:WPF_Practice"
        xmlns:System="clr-namespace:System;assembly=mscorlib" x:Class="WPF_Practice.NewWindow"
        mc:Ignorable="d"
        Title="NewWindow" Height="450" Width="800" Loaded="Window_Loaded">
  

    <Grid x:Name="Grid1" Background="#FF282828">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>




        <StackPanel x:Name="StackPanel1" Grid.Row="1" Orientation="Horizontal">

            <Button ToolTipService.InitialShowDelay="5000"  ToolTipService.BetweenShowDelay="0" x:Name="MyButton1" MouseEnter="Button_MouseEnter" MouseLeave="Button_MouseLeave" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" Width="80" Height="30" Content="ToolTip Salam">
                <Button.ToolTip>
                    <ToolTip  Content="توضیحات به عنوان تولتیپ"/>
                </Button.ToolTip>
            </Button>

            <Button ToolTipService.InitialShowDelay="5000" ToolTipService.BetweenShowDelay="0" x:Name="MyButton2" MouseEnter="Button_MouseEnter" MouseLeave="Button_MouseLeave" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" Width="80" Height="30" Content="ToolTip Test">
                <Button.ToolTip>
                    <ToolTip Content="دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذ دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذ دکمه 1  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذ دکمه 2  تست میشود  لت بت دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذت ت ن لن نا ن نبت اتیغسی سشنم تکت دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسیاک کسثفثسقغ ک ذ بلزت یسلسیاک کسثفثسقغ ک ذ                              دکمه 2  تست میشود  لت بت ت ت ن لن نا ن نبت اتیغسی سشنم تکت بلزت یسلسی o ho o ho ho o gogo gog oاک کسثفثسقغ ک ذ"/>
                </Button.ToolTip>
            </Button>

            <ComboBox Name="ComboBox1" Width="150" Height="23">
                <System:String>salam</System:String>
                <System:String>khobi?</System:String>
                <CheckBox Name="CombxCheckBox1"/>
            </ComboBox>

            <TabControl Name="TabControl1" Width="300" Height="200" Margin="20" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <TabItem Name="TabItem1" Header="salam">
                    <Grid Name="TabItemGrid1">
                        <TextBox Name="TextBox1"/>
                        <ListBox Name="ListBox1"/>
                    </Grid>
                </TabItem>

                <TabItem Name="TabItem2" Header="khobi">
                    <ListView Name="ListView1"/>
                </TabItem>
            </TabControl>

        </StackPanel>

    </Grid>


</Window>

حالا در کد زیر :

C#:
        private void Window_Loaded(object sender, RoutedEventArgs e)

        {



            foreach (FrameworkElement visualChildrens in this.FindParentElements<FrameworkElement>(this))

            {

                if (visualChildrens != null)

                    MessageBox.Show(visualChildrens.Name);

            }



        }



        private IEnumerable<T> FindParentElements<T>(T parent) where T : DependencyObject

        {

            if (parent == null)

                yield return null;



            IEnumerable<object> childrens = LogicalTreeHelper.GetChildren(parent).Cast<object>();

            //int childrensCount = childrens.Count<object>();

            if (childrens == null /*|| childrensCount < 1*/)

                yield return null;



            foreach (object child in childrens)

            {

                if (child is T)

                {

                    yield return (T)child;

                    foreach (T childOfChild in this.FindParentElements(child as T))

                    {

                        yield return childOfChild;

                    }

                }

            }

        }

در کد بالا هیچ مشکلی نیست .
اما اگه کامنت کد سی شارپ در بالا را بردارین ، اون foreach درون متد ، اجرا نمیشه با اونکه مقدارش بزرگتر از صفر هست .
همچنین یه چیز عجیب اینکه اگه بعد از اجرای متد LogicalTreeHelper.GetChildren ، خروجیِ childrens اش را تریس کنیم ، و مقدار resoult اش را ببیینیم ، در کمال تعجب ، مقداری که قبلا داشت ، empty میشه و انگار null میشه و در کدهای بعدی ، رفتارش انگار با مقدار nullرفتار میکنه اما مقدارشو نبینیم ، مشکلی نداره .

علت این دو تا مشکل چیه؟
تشکر
اولا ()<childrens.Count<object رو با این فرض اجرا می کنید یا می توانید اجرا کنید که childrens ئه null نباشه، اگر null بود که Count ئه خطا میداد.
پس وقتی همچین فرضی دارید دیگه در سطر بعدی if (childrens == null معنی نداره.
ثانیا LogicalTreeHelper.GetChildren(parent) و <Cast<object به شما null نخواهند داد، اون شرط childrens == null هیچوقت برقرار نمیشه.
ثالثا شما IEnumerator رو اول در Count پیمایش کرده اید، دیگه اون IEnumerator مصرف شده، رسیده به تهش.
IEnumerator رو مستقیم نباید بکار ببرید، چون وقتی پیمایش اش رو انجام داد دیگه بر نمیگرده به شروع. اون Count موجب به پیمایش اش میشه و دیگه چیزی برای پیمایش در foreach نمیمونه. از ToArray یا ToList استفاده کنید تا به مجموعه تبدیل بشه.
 

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

بالا