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

the_king

مدیرکل انجمن
ممنون استاد .
بله میدونم .
منظورم اینه که در کد نویسی چی کار کنیم تا شکل کنترل را تغییر داده به جای دیگه (مثل windows form) ، منتقل کنیم؟

بذارید بهتر توضیح بدم :
مثلا من برای انتقال و استفاده از سی شارپ و کنترل هاش ، در زبان ها و محیط های دیگه (مثلا وقتی میخوام از توی اتوپلی ، سی شارپ و دات نت را استفاده کنم) ، در سی شارپ ، یه dll درست میکنم .
حالا مثلا وقتی بخوام button ئه شخصی سازی شده را در اتوپلی استفاده کنم ، اول میام یه کلاسی میسازم که از کلاس button ارث بری کرده (مثلا کلاسی بنام CustomButton میسازم) و بعد متد OnPaint اش را اورراید میکنم و شکل دلخواهم را رسم میکنم .
حالا این کلاس CustomButton را به اتوپلی منتقل میکنم و با فراخونی متدی از سی شارپ که درست کردم ، در بدنه ی متد اش که در سی شارپ نوشتم ، از این کلاس شی میسازم و استفاده میکنم .


حالا برای اینکه مثلا کنترلی در wpf که template ای براش توسط کدهای xaml بکار رفته شده (و تغییر شکل داده شده) را از wpf به windows form منتقل و توسط کنترل ElementHost ، از این کنترل تغییر شکل یافته استفاده کنیم ، چه مراحلی را باید طی کنیم؟
آیا باید کلاسی بنویسیم که مثلا در متد سازنده اش ، کدهای فایل xaml (که شامل template برای اون کنترل بودن) را لود کنه ؟
چون windows form که نمیتونه از کدهای xaml برای توصیف کنترل هاش استفاده کنه (یعنی کدهای xaml در wpf که برای windows form ناشناخته هست) .
کلا باید چه مراحلی را طی کنیم؟
و هم اینکه آیا برای این انتقال از wpf به windows form ، فقط باید dll بسازیم یا چون این انتقال در بین دات نت (و هر دو از زبان سی شارپ استفاده میکنن) ، بجز ساخت dll ، راه دیگه ای هم وجود داره؟
تشکر استاد . :rose:
شما هر کاری که مربوط به WPF هست رو باید در خود همون پروژه WPF ئه انجام بدهید طوری که موقع فراخوانی اون کنترل دیگه کار اضافه ای مرتبط با XAML لازم نباشه.
شما یک کتابخانه میسازید و در برنامه Windows Form تون از اون کتابخانه استفاده می کنید، هم می توانید مستقیما اون پروژه کتابخانه رو در Solution برنامه اضافه کنید و به پروژه اش رفرنس بدهید و هم می توانید اول dll رو بسازید و بعد مستقلا dll رو در پروژه تون بکار ببرید. قاعدتا مادامی که نسخه نهایی کتابخانه رو نساخته اید و در حال تکمیل ئه روش اول بهتر ئه چون بصورت خودکار dll بروز میشه.
البته الزاما لازم نیست که فایل اش حتما dll باشه ولی معمولا در رفرنس از exe استفاده نمیشه، بجز در مواردی که ترکیبی از برنامه و کتابخانه است.
یک نمونه اش رو که ساختید مییبینید که کار پیچیده ای نبوده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
شما هر کاری که مربوط به WPF هست رو باید در خود همون پروژه WPF ئه انجام بدهید طوری که موقع فراخوانی اون کنترل دیگه کار اضافه ای مرتبط با XAML لازم نباشه.
شما یک کتابخانه میسازید و در برنامه Windows Form تون از اون کتابخانه استفاده می کنید، هم می توانید مستقیما اون پروژه کتابخانه رو در Solution برنامه اضافه کنید و به پروژه اش رفرنس بدهید و هم می توانید اول dll رو بسازید و بعد مستقلا dll رو در پروژه تون بکار ببرید. قاعدتا مادامی که نسخه نهایی کتابخانه رو نساخته اید و در حال تکمیل ئه روش اول بهتر ئه چون بصورت خودکار dll بروز میشه.
البته الزاما لازم نیست که فایل اش حتما dll باشه ولی معمولا در رفرنس از exe استفاده نمیشه، بجز در مواردی که ترکیبی از برنامه و کتابخانه است.
یک نمونه اش رو که ساختید مییبینید که کار پیچیده ای نبوده.

استاد ، الان وقتی میخوایم یه کنترل (که همونطور که گفته بودم ، مثلا template روش بکار بردیم) را از wpf به win form منتقل کنیم ، مثلا باید در wpf ، بجای اینکه با کدهای xaml براش template درست کنیم ، یه کلاس جدیدی درست کنیم که از اون کنترل ارث بری کنه و اون template را در قالب کدهای سی شارپ براش پیاده سازی کنیم (بجای کدهای xaml) ؟
کلا دقیق متوجه نشدم نحوه ی پیاده سازی باید چجوری باشه تا بتونیم منتقل کنیم .
درباره ی جواب دو پست قبلی هم ممنون .
تشکر استاد .
 

the_king

مدیرکل انجمن
استاد ، الان وقتی میخوایم یه کنترل (که همونطور که گفته بودم ، مثلا template روش بکار بردیم) را از wpf به win form منتقل کنیم ، مثلا باید در wpf ، بجای اینکه با کدهای xaml براش template درست کنیم ، یه کلاس جدیدی درست کنیم که از اون کنترل ارث بری کنه و اون template را در قالب کدهای سی شارپ براش پیاده سازی کنیم (بجای کدهای xaml) ؟
کلا دقیق متوجه نشدم نحوه ی پیاده سازی باید چجوری باشه تا بتونیم منتقل کنیم .
درباره ی جواب دو پست قبلی هم ممنون .
تشکر استاد .
برای کنترل های تخصصی قطعا روش خوبیه، اما برای کار ظاهری ساده نیازی نیست اینقدر درگیر کد نویسی بشوید.
در ساده ترین حالت شما یک پروژه Windows Form دارید، داخل همون پروژه (نه یک پروژه WPF) با Project > Add New Item در دسته بندی WPF یک User Control (WPF) به پروژه Windows Forms اضافه می کنید. هر طور که دلتون خواست داخلش کد XAML و cs اش رو ویرایش می کنید و نهایتا بعد Build کردن پروژه در Toolbox اون UserControl1 یا هر اسم دیگری که داره دارید، وقتی Drag میشه و روی فرم قرار می گیره بصورت خودکار برایش Element Host ایجاد میشه.
یکم پیچیده تر اش که کنید، دیگه User Control (WPF) رو در خود این پروژه نمیسازید. بجایش یک پروژه جدید WPF به Solution برنامه اضافه می کنید و به پروژه WPF ئه رفرنس می دهید (زبانه Projects تیکش می زنید) و User Control (WPF) رو در اون پروژه WPF میسازید، همین نتیجه میشه، اما الان یک کتابخانه مستقل دارید که می توانید با سایر برنامه ها هم به اشتراکش بذارید.
خیلی روال ساده ای است.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
RenderedTargetBitmap خودش که تصویر نداره، از RenderTargetBitmap همیشه بصورت مستقیم استفاده می کنید. واسطه هم نیست که بخواهید ازش استفاده بکنید یا نکنید، هم در کد اول و هم در کد دوم تون RenderTargetBitmap دارید که برای تبدیل رندر به تصویر استفاده شده. من نمیدونم برای هر کاری چند راه هست که بخواهم نظر بدم که فقط راهش اینه یا x راه دیگه هم هست. مساله اینه که RenderedTargetBitmap برای ساختن تصویر بر اساس رندر یک شیء ئه، جایگزین مشخص دیگه ای هم نداره. اگر قراره رندر شیء ای رو به تصویر تبدیل کنید RenderedTargetBitmap برای این منظور ئه. اگر نمی خواهید رندر ای رو به تصویر تبدیل کنید RenderedTargetBitmap شاید بدردتون نخوره.

خیلی ممنون استاد .
استاد ، کلا هدفم اینه که یه آیکون را به عنوان system tray به نمایش بذارم . با استفاده از TaskbarIcon در لینک زیر :

hardcodet.net » WPF NotifyIcon

آیکون ، همون شکلی هه که کدش را در پست 249 (صفحه ی 13) ، در قالب کنترل Canvas دادم . البته اون Canvas ، یک کنترل هه .
از طرفی ، این کلاس TaskbarIcon که در سی شارپ به عنوان system tray ازش استفاده میکنم ، فقط کلاس System.Drawing.Icon را قبول میکنه .
نمیدونم چرا پروپرتیِ IconSource اش که نوع ImageSource را قبول میکنه ، وقتی مسیر فایل png را در قالب کد زیر میدم :

کد:
BitmapImage myBitmapImage = new BitmapImage(new Uri(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\Main\Poshtibangir Tolo Normal.png"));

ارور زیر را میده :

کد:
Unsupported URI syntax. Method expects a relative URI or a pack://application:,,,/ form of absolute URI.'

اما سئوالاتم اینکه :
1) چجوری این RenderedBitmapTarget (که یک نوع ImageSource هست) را به System.Drawing.Icon تبدیل کنم؟
بر عکسِ این حالت (یعنی تبدیل Icon به یک ImageSource) با سی شارپ در اینترنت هست اما این نیست .

2) سئوال مهم اینه که راهی هست که این کنترل Canvas را بدون اینکه در کنترلی رسم کنیم (یعنی صرفا فقط در Resource قرارش بدیم و این Canvas را فرزندِ کنترلی قرار ندیم تا این Canvas ،توی اون کنترل ، رسم بشه) ، به RenderedBitmapTarget تبدیل کنیم؟
چون انگار من که با RenderedBitmapTarget کار میکنم ، فقط کنترل هایی در رسم هستند و حتی visable شون هم فعاله را میتونه به RenderedBitmapTarget تبدیل کنه .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
استاد ، کلا هدفم اینه که یه آیکون را به عنوان system tray به نمایش بذارم . با استفاده از TaskbarIcon در لینک زیر :

hardcodet.net » WPF NotifyIcon

آیکون ، همون شکلی هه که کدش را در پست 249 (صفحه ی 13) ، در قالب کنترل Canvas دادم . البته اون Canvas ، یک کنترل هه .
از طرفی ، این کلاس TaskbarIcon که در سی شارپ به عنوان system tray ازش استفاده میکنم ، فقط کلاس System.Drawing.Icon را قبول میکنه .
نمیدونم چرا پروپرتیِ IconSource اش که نوع ImageSource را قبول میکنه ، وقتی مسیر فایل png را در قالب کد زیر میدم :

کد:
BitmapImage myBitmapImage = new BitmapImage(new Uri(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\Main\Poshtibangir Tolo Normal.png"));

ارور زیر را میده :

کد:
Unsupported URI syntax. Method expects a relative URI or a pack://application:,,,/ form of absolute URI.'
ازتون مسیر نسبی یا //:pack میخواد.
Pack URIs - WPF

اما سئوالاتم اینکه :
1) چجوری این RenderedBitmapTarget (که یک نوع ImageSource هست) را به System.Drawing.Icon تبدیل کنم؟
بر عکسِ این حالت (یعنی تبدیل Icon به یک ImageSource) با سی شارپ در اینترنت هست اما این نیست .
نمیدونم RenderedBitmapTarget چیه، یک صفحه مطلب هم در موردش در اینترنت نیست، من RenderTargetBitmap رو میشناسم.
کد:
            var encoder = new BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
            var stream = new MemoryStream();
            encoder.Save(stream);
            var bitmap = new System.Drawing.Bitmap(stream);
            var icon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());

2) سئوال مهم اینه که راهی هست که این کنترل Canvas را بدون اینکه در کنترلی رسم کنیم (یعنی صرفا فقط در Resource قرارش بدیم و این Canvas را فرزندِ کنترلی قرار ندیم تا این Canvas ،توی اون کنترل ، رسم بشه) ، به RenderedBitmapTarget تبدیل کنیم؟
من چیزی در مورد RenderedBitmapTarget نمیدونم. اولین بار ئه که همچین اسمی رو میشنوم.
 

SajjadKhati

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


نمیدونم RenderedBitmapTarget چیه، یک صفحه مطلب هم در موردش در اینترنت نیست، من RenderTargetBitmap رو میشناسم.
کد:
            var encoder = new BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
            var stream = new MemoryStream();
            encoder.Save(stream);
            var bitmap = new System.Drawing.Bitmap(stream);
            var icon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());


من چیزی در مورد RenderedBitmapTarget نمیدونم. اولین بار ئه که همچین اسمی رو میشنوم.

خیلی ممنون استاد از جواب تون .
بله ، منظورم RenderTargetBitmap هست . اشتباه نوشته بودم .
حالا لطفا سئوال ۲ پست قبلی را جواب میدید؟
تشکر
 

the_king

مدیرکل انجمن
2) سئوال مهم اینه که راهی هست که این کنترل Canvas را بدون اینکه در کنترلی رسم کنیم (یعنی صرفا فقط در Resource قرارش بدیم و این Canvas را فرزندِ کنترلی قرار ندیم تا این Canvas ،توی اون کنترل ، رسم بشه) ، به RenderedBitmapTarget تبدیل کنیم؟
چون انگار من که با RenderedBitmapTarget کار میکنم ، فقط کنترل هایی در رسم هستند و حتی visable شون هم فعاله را میتونه به RenderedBitmapTarget تبدیل کنه .
RenderTargetBitmap یک Visual رو رندر می کنه که اونم خودتون با DrawingVisual می سازید، خود RenderTargetBitmap که تعیین کننده رسم داخل Visual نیست.
بنابر این اینکه در DrawingVisual چه چیزی رو رسم می کنید و نمی کنید ربطی به RenderTargetBitmap نداره.
برای RenderTargetBitmap فرقی نمی کنه که در Visual ئه Grid رسم میشه یا Canvas یا هر دو یا هیچکدام.
بنابراین لزومی نداره که برای رسم Canvas در DrawingVisual داخل کنترل خاصی قرار بگیره، چه در حال نمایش و چه مخفی.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
RenderTargetBitmap یک Visual رو رندر می کنه که اونم خودتون با DrawingVisual می سازید، خود RenderTargetBitmap که تعیین کننده رسم داخل Visual نیست.
بنابر این اینکه در DrawingVisual چه چیزی رو رسم می کنید و نمی کنید ربطی به RenderTargetBitmap نداره.
برای RenderTargetBitmap فرقی نمی کنه که در Visual ئه Grid رسم میشه یا Canvas یا هر دو یا هیچکدام.
بنابراین لزومی نداره که برای رسم Canvas در DrawingVisual داخل کنترل خاصی قرار بگیره، چه در حال نمایش و چه مخفی.

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

کد xaml برای آیکون ام که در resource ئه مربوط به یه کنترل گرید (بنام myGrid1) قرار دادم (چون در resource هست ، توی کنترلی رسم نمیشه) :

کد:
            <Canvas x:Key="keyCanvsaMainIcon" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"  >
                <Canvas.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform ScaleX="0.0377" ScaleY="0.0343"/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Canvas.RenderTransform>
                <Path Fill="White" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="14, 8, 0, 0" Width="719" Height="329" StrokeThickness="0" Stretch="Fill"
                  Data="M290.000,-0.000 C327.996,0.333 366.004,0.667 404.000,1.000 C421.978,0.188 452.371,3.150 471.000,7.000 C488.332,9.000 505.668,11.000 523.000,13.000 C566.238,22.506 612.860,33.116 649.000,52.000 C672.178,64.111 695.149,74.932 709.000,96.000 C721.444,114.930 724.013,207.707 711.000,229.000 C688.133,266.416 637.509,284.079 591.000,298.000 C467.983,334.820 254.204,343.675 128.000,302.000 C82.706,287.043 39.363,274.311 14.000,240.000 C2.250,224.104 -0.002,206.565 -0.000,178.000 C-0.000,157.335 -0.000,136.665 -0.000,116.000 C27.301,49.409 103.047,30.427 176.000,13.000 C200.664,9.667 225.336,6.333 250.000,3.000 C263.209,0.163 279.738,5.568 290.000,-0.000 Z" >
                </Path>
                <Path Fill="White" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10, 340, 0, 0" Width="301" Height="275" StrokeThickness="0" Stretch="Fill"
                  Data="M259,615c-73.482,1.454-148.315-28.83-196-58-19.832-12.132-38.429-28.945-47-52-7.728-20.788-7.031-119.923,0-141,3.295-9.877,5.8-21.349,16-24,42.163,57.289,177.51,93.874,280,94v3C283.4,463.912,259.286,557.01,259,615Z" >
                </Path>
                <Path Fill="White" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="12, 626, 0, 0" Width="392" Height="282" StrokeThickness="0" Stretch="Fill"
                  Data="M12,655h3c0.547-10.964,7.318-27.036,17-29,28.669,41.637,97.658,63.437,155,78,19.97,5.072,42.706,4.476,63,9l19,1c4.71,3.683,4.968,18.787,7,25l19,47c23.676,45.86,63.262,97.775,109,121v1H333c-9.8-5.158-26.2.634-38-2-23.5-5.246-50.4-2.524-74-8l-59-11c-44.157-12.182-84.1-27.707-116-52-16.412-12.5-24.04-32.85-34-52V655Z">
                </Path>
                <Path Fill="White" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="349, 438, 0, 0" Width="380" Height="410" StrokeThickness="0" Stretch="Fill"
                  Data="M349,502c39.135,0,84.257-6.261,108-23,11.381-8.024,32.47-38.133,44-41,6.278,5.6,15.142,7.943,23,12,20.15,10.4,38.259,20.269,64,26,23.647,5.265,46.048-3.941,68-4l58,148c11.57,27.754,23.1,70.8,10,107-9.65,26.663-29.467,44.246-45,65-10.469,13.989-21.788,27.228-32,41-4.25,5.732-6.267,13.751-15,15-11.783-7.3-29.024-7.5-43-12-36.762-11.843-83.916-18.873-115-38-30.164-18.561-55.626-46.794-70-81-14.914-35.49-19.646-81.552-31-120-5.949-20.147-9.828-41.039-16-62C354,524.808,349.725,513.947,349,502Zm49,32c2.509,22.819,13.228,50.775,20,72,16.42,51.464,20.627,111.8,59,141,20.386,15.51,42.86,20.921,71,30l53,17c4.353,1.413,16.1,5.121,18,4,11.346-8.022,20.624-23.847,29-35,19.5-25.968,59.5-51.969,47-105-6.574-27.886-18.617-53.122-29-78-7.288-17.464-13.155-35.265-20-52-3.922-9.588-2.105-21.918-16-22-6.8,4-26.778,2.708-35,1-19.573-4.066-33.4-5.219-49-12-11.313-4.919-21.848-14.468-35-17C488.891,510.183,450.781,532.762,398,534Z">
                </Path>
                <Path Fill="#FF00DC00" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="289, 362, 0, 0" Width="550" Height="561" StrokeThickness="0" Stretch="Fill"
                  Data="M492,363c100.8-2.089,148.743,30.839,204,73,12.014,9.167,43.931,39.174,49,53h-1c-10.312-14.959-25.59-29.982-40-41-9.538-7.293-18.013-16.957-28-24-45.917-32.382-130.778-66.717-206-43-19.2,6.054-38.12,13.174-54,23-45.866,28.38-77.1,74.61-94,132l-7,44v24c-0.007,39.264,6.7,71.062,18,99,37.621,93.041,91.3,156.473,184,194,17.539,7.1,41.29,10.551,59,14,22.07,4.3,51.389.594,69-4,61.974-16.169,109.037-46.519,135-98h2v3c-9.1,10.24-14.769,24.139-23,35-23.355,30.814-61.8,56.515-103,69-63.009,19.094-127.552,4.34-176-17-88.5-38.981-145.025-112.065-176-209-12.869-40.273-20.585-98.9-8-147,4.454-17.021,9.274-34.5,16-50A219.8,219.8,0,0,1,426,379c13.394-5.825,29.122-9.293,44-13ZM804,586c9.217,8.761,11.882,27.368,17,40,15.205,37.528,28.553,98.393,10,142-8.965,21.071-27.361,37.315-48,47v-3c12.764-14.363,14.223-43.19,19-65,2.145-9.792,2.029-25.235-1-30,1,42.444-13.232,72.2-29,98l-1-1c-9.7-7.234-14.883-22.132-20-34-3.871-8.979-8.155-19.326-11-30-17.231-64.65,42.915-91.534,59-130C803,610.438,803.927,598.874,804,586ZM655,693h2c1.572,18.69,15.173,33.922,27,43,19.932,15.3,43.623,38.684,52,65,5.132,16.123,2.329,59.571-9,66-13.341-19.927-31.139-35.988-38-63h-1v2l7,20c6.491,14.961,16.429,28.161,25,41h-3c-7.174-6.037-17.509-8.5-25-14-20.279-14.875-32.947-40.926-40-69q-1-12.5-2-25c-1.29-6.528-2.612-19.9-1-28Q652,712,655,693Z">
                </Path>
            </Canvas>

و در رویداد Load ئه ویندوز برای کدهای سی شارپ :

کد:
            Canvas canvasMainIcon = (Canvas)this.myGrid1.TryFindResource("keyCanvsaMainIcon");

            VisualBrush visualBrush = new VisualBrush(canvasMainIcon);
            DrawingVisual controlVisual = new DrawingVisual();
            DrawingContext drawingContext = controlVisual.RenderOpen();
            drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(0, 0),new Size(16, 16)));
            drawingContext.Close();

            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(controlVisual);
            this.Icon = bitmapImage;

اما آیکون رسم نمیشه . چرا و چی کار باید کرد تا رسم بشه؟
البته وقتی اون آیکون (همون Canvas ئه که نام کلیدش keyCanvsaMainIcon هست) ، وقتی در resource نبود و درون کنترلی رسم اش میکردم ، این کد کار میکرد .
در کد بالا هم اون شی canvasMainIcon را به تنهایی درون کنترلی وارد و رسم کنیم ، مشکلی نداره و رسم میشه . اما کد بالا کار نمیکنه .

همچنین اینکه استاد میشه کاری کرد که کد زیر :

کد:
            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(canvasMainIcon );
            this.Icon = bitmapImage;

برای اون شی canvasMainIcon که در resource هست ، میشه کاری کنیم که با کد بالا کار کنه؟ یعنی بصورت مستقیم ، اون شی canvasMainIcon را توی RenderTargetBitmap رسم و بعد استفاده کنیم و دیگه از کلاس DrawingVisual استفاده نکنیم؟
اگه میشه ، چجوری میشه و اگه نمیشه چرا نمیشه؟ اگه نشه ، بخاطر اینکه شی canvasMainIcon رسم نیست ، نمیشه؟
تشکر استاد :rose:
 

the_king

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

کد xaml برای آیکون ام که در resource ئه مربوط به یه کنترل گرید (بنام myGrid1) قرار دادم (چون در resource هست ، توی کنترلی رسم نمیشه) :

کد:
            <Canvas x:Key="keyCanvsaMainIcon" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 0, 0, 0"  >
                <Canvas.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform ScaleX="0.0377" ScaleY="0.0343"/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Canvas.RenderTransform>
                <Path Fill="White" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="14, 8, 0, 0" Width="719" Height="329" StrokeThickness="0" Stretch="Fill"
                  Data="M290.000,-0.000 C327.996,0.333 366.004,0.667 404.000,1.000 C421.978,0.188 452.371,3.150 471.000,7.000 C488.332,9.000 505.668,11.000 523.000,13.000 C566.238,22.506 612.860,33.116 649.000,52.000 C672.178,64.111 695.149,74.932 709.000,96.000 C721.444,114.930 724.013,207.707 711.000,229.000 C688.133,266.416 637.509,284.079 591.000,298.000 C467.983,334.820 254.204,343.675 128.000,302.000 C82.706,287.043 39.363,274.311 14.000,240.000 C2.250,224.104 -0.002,206.565 -0.000,178.000 C-0.000,157.335 -0.000,136.665 -0.000,116.000 C27.301,49.409 103.047,30.427 176.000,13.000 C200.664,9.667 225.336,6.333 250.000,3.000 C263.209,0.163 279.738,5.568 290.000,-0.000 Z" >
                </Path>
                <Path Fill="White" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10, 340, 0, 0" Width="301" Height="275" StrokeThickness="0" Stretch="Fill"
                  Data="M259,615c-73.482,1.454-148.315-28.83-196-58-19.832-12.132-38.429-28.945-47-52-7.728-20.788-7.031-119.923,0-141,3.295-9.877,5.8-21.349,16-24,42.163,57.289,177.51,93.874,280,94v3C283.4,463.912,259.286,557.01,259,615Z" >
                </Path>
                <Path Fill="White" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="12, 626, 0, 0" Width="392" Height="282" StrokeThickness="0" Stretch="Fill"
                  Data="M12,655h3c0.547-10.964,7.318-27.036,17-29,28.669,41.637,97.658,63.437,155,78,19.97,5.072,42.706,4.476,63,9l19,1c4.71,3.683,4.968,18.787,7,25l19,47c23.676,45.86,63.262,97.775,109,121v1H333c-9.8-5.158-26.2.634-38-2-23.5-5.246-50.4-2.524-74-8l-59-11c-44.157-12.182-84.1-27.707-116-52-16.412-12.5-24.04-32.85-34-52V655Z">
                </Path>
                <Path Fill="White" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="349, 438, 0, 0" Width="380" Height="410" StrokeThickness="0" Stretch="Fill"
                  Data="M349,502c39.135,0,84.257-6.261,108-23,11.381-8.024,32.47-38.133,44-41,6.278,5.6,15.142,7.943,23,12,20.15,10.4,38.259,20.269,64,26,23.647,5.265,46.048-3.941,68-4l58,148c11.57,27.754,23.1,70.8,10,107-9.65,26.663-29.467,44.246-45,65-10.469,13.989-21.788,27.228-32,41-4.25,5.732-6.267,13.751-15,15-11.783-7.3-29.024-7.5-43-12-36.762-11.843-83.916-18.873-115-38-30.164-18.561-55.626-46.794-70-81-14.914-35.49-19.646-81.552-31-120-5.949-20.147-9.828-41.039-16-62C354,524.808,349.725,513.947,349,502Zm49,32c2.509,22.819,13.228,50.775,20,72,16.42,51.464,20.627,111.8,59,141,20.386,15.51,42.86,20.921,71,30l53,17c4.353,1.413,16.1,5.121,18,4,11.346-8.022,20.624-23.847,29-35,19.5-25.968,59.5-51.969,47-105-6.574-27.886-18.617-53.122-29-78-7.288-17.464-13.155-35.265-20-52-3.922-9.588-2.105-21.918-16-22-6.8,4-26.778,2.708-35,1-19.573-4.066-33.4-5.219-49-12-11.313-4.919-21.848-14.468-35-17C488.891,510.183,450.781,532.762,398,534Z">
                </Path>
                <Path Fill="#FF00DC00" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="289, 362, 0, 0" Width="550" Height="561" StrokeThickness="0" Stretch="Fill"
                  Data="M492,363c100.8-2.089,148.743,30.839,204,73,12.014,9.167,43.931,39.174,49,53h-1c-10.312-14.959-25.59-29.982-40-41-9.538-7.293-18.013-16.957-28-24-45.917-32.382-130.778-66.717-206-43-19.2,6.054-38.12,13.174-54,23-45.866,28.38-77.1,74.61-94,132l-7,44v24c-0.007,39.264,6.7,71.062,18,99,37.621,93.041,91.3,156.473,184,194,17.539,7.1,41.29,10.551,59,14,22.07,4.3,51.389.594,69-4,61.974-16.169,109.037-46.519,135-98h2v3c-9.1,10.24-14.769,24.139-23,35-23.355,30.814-61.8,56.515-103,69-63.009,19.094-127.552,4.34-176-17-88.5-38.981-145.025-112.065-176-209-12.869-40.273-20.585-98.9-8-147,4.454-17.021,9.274-34.5,16-50A219.8,219.8,0,0,1,426,379c13.394-5.825,29.122-9.293,44-13ZM804,586c9.217,8.761,11.882,27.368,17,40,15.205,37.528,28.553,98.393,10,142-8.965,21.071-27.361,37.315-48,47v-3c12.764-14.363,14.223-43.19,19-65,2.145-9.792,2.029-25.235-1-30,1,42.444-13.232,72.2-29,98l-1-1c-9.7-7.234-14.883-22.132-20-34-3.871-8.979-8.155-19.326-11-30-17.231-64.65,42.915-91.534,59-130C803,610.438,803.927,598.874,804,586ZM655,693h2c1.572,18.69,15.173,33.922,27,43,19.932,15.3,43.623,38.684,52,65,5.132,16.123,2.329,59.571-9,66-13.341-19.927-31.139-35.988-38-63h-1v2l7,20c6.491,14.961,16.429,28.161,25,41h-3c-7.174-6.037-17.509-8.5-25-14-20.279-14.875-32.947-40.926-40-69q-1-12.5-2-25c-1.29-6.528-2.612-19.9-1-28Q652,712,655,693Z">
                </Path>
            </Canvas>

و در رویداد Load ئه ویندوز برای کدهای سی شارپ :

کد:
            Canvas canvasMainIcon = (Canvas)this.myGrid1.TryFindResource("keyCanvsaMainIcon");

            VisualBrush visualBrush = new VisualBrush(canvasMainIcon);
            DrawingVisual controlVisual = new DrawingVisual();
            DrawingContext drawingContext = controlVisual.RenderOpen();
            drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(0, 0),new Size(16, 16)));
            drawingContext.Close();

            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(controlVisual);
            this.Icon = bitmapImage;

اما آیکون رسم نمیشه . چرا و چی کار باید کرد تا رسم بشه؟
رسم میشه، اتفاقا خیلی هم خوب کار می کنه، به قول انگلیسی ها Work like a charm. اما چیزی نمی بینید چون ابعاد Canvas تون هیچی ئه، شما یک Canvas بدون توصیف ابعاد دارید که لااقل داخل شیء دیگری که ابعاد داره هم قرارش ندادید تا متناسب با اون ابعاد بگیره و طبعا در ابعاد نامشخص چیزی نیست که ببینید. می توانید از Arrange استفاده کنید و بهش ابعاد بدهید.
کد:
            Canvas canvasMainIcon = (Canvas)this.myGrid1.TryFindResource("keyCanvsaMainIcon");

            canvasMainIcon.Arrange(new Rect(0, 0, 32, 32));

            VisualBrush visualBrush = new VisualBrush(canvasMainIcon);
            DrawingVisual controlVisual = new DrawingVisual();
            DrawingContext drawingContext = controlVisual.RenderOpen();
            drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(0, 0), new Size(32, 32)));
            drawingContext.Close();

            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(controlVisual);
            this.Icon = bitmapImage;
البته وقتی اون آیکون (همون Canvas ئه که نام کلیدش keyCanvsaMainIcon هست) ، وقتی در resource نبود و درون کنترلی رسم اش میکردم ، این کد کار میکرد .
در کد بالا هم اون شی canvasMainIcon را به تنهایی درون کنترلی وارد و رسم کنیم ، مشکلی نداره و رسم میشه . اما کد بالا کار نمیکنه .

همچنین اینکه استاد میشه کاری کرد که کد زیر :

کد:
            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(canvasMainIcon );
            this.Icon = bitmapImage;

برای اون شی canvasMainIcon که در resource هست ، میشه کاری کنیم که با کد بالا کار کنه؟ یعنی بصورت مستقیم ، اون شی canvasMainIcon را توی RenderTargetBitmap رسم و بعد استفاده کنیم و دیگه از کلاس DrawingVisual استفاده نکنیم؟
اگه میشه ، چجوری میشه و اگه نمیشه چرا نمیشه؟ اگه نشه ، بخاطر اینکه شی canvasMainIcon رسم نیست ، نمیشه؟
تشکر استاد :rose:
اینجوری میشه :
کد:
            Canvas canvasMainIcon = (Canvas)this.myGrid1.TryFindResource("keyCanvsaMainIcon");
            canvasMainIcon.Arrange(new Rect(0, 0, 32, 32));
            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(canvasMainIcon);
            this.Icon = bitmapImage;
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
رسم میشه، اتفاقا خیلی هم خوب کار می کنه، به قول انگلیسی ها Work like a charm. اما چیزی نمی بینید چون ابعاد Canvas تون هیچی ئه، شما یک Canvas بدون توصیف ابعاد دارید که لااقل داخل شیء دیگری که ابعاد داره هم قرارش ندادید تا متناسب با اون ابعاد بگیره و طبعا در ابعاد نامشخص چیزی نیست که ببینید. می توانید از Arrange استفاده کنید و بهش ابعاد بدهید.
کد:
            Canvas canvasMainIcon = (Canvas)this.myGrid1.TryFindResource("keyCanvsaMainIcon");

            canvasMainIcon.Arrange(new Rect(0, 0, 32, 32));

            VisualBrush visualBrush = new VisualBrush(canvasMainIcon);
            DrawingVisual controlVisual = new DrawingVisual();
            DrawingContext drawingContext = controlVisual.RenderOpen();
            drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(0, 0), new Size(32, 32)));
            drawingContext.Close();

            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(controlVisual);
            this.Icon = bitmapImage;

اینجوری میشه :
کد:
            Canvas canvasMainIcon = (Canvas)this.myGrid1.TryFindResource("keyCanvsaMainIcon");
            canvasMainIcon.Arrange(new Rect(0, 0, 32, 32));
            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(canvasMainIcon);
            this.Icon = bitmapImage;


خیلی ممنون استاد . :rose:
من width و height هم در کد xaml برای اون Canvas تعریف کردم اما بدون اون تنظیم کردن متد Arrange ، درست نشد . کلا بدون استفاده از متد Arrange نمیشه ازش استفاده کرد (در کدهای xaml اش ابعاد را نمیشه مشخص کرد؟)

بعد اینکه در کد زیر :

کد:
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Canvas canvasMainIcon = (Canvas)this.myGrid1.TryFindResource("keyCanvsaMainIcon");
            canvasMainIcon.Arrange(new Rect(0, 0, 32, 32));

            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(canvasMainIcon);
            this.Icon = bitmapImage;

            Hardcodet.Wpf.TaskbarNotification.TaskbarIcon myTaskbarIcon = new Hardcodet.Wpf.TaskbarNotification.TaskbarIcon();
            myTaskbarIcon.IconSource = bitmapImage;
        }

در خط آخر ، مثل دفعه ی قبل ارور زیر را میده :
کد:
'Invalid URI: The format of the URI could not be determined.'

که قبلا برای اون ارور گفته بودید که از Pack Uris باید استفاده کنیم .
خوب اون رو که مسیر فایل را میدادیم و بجاش از قواعدی که در اون لینکی که تعیین کرد ، استفاده میکردیم اما در اینجا ، شی bitmapImage که براش مسیر فایل را مشخص نمیکنیم . پس چجوری باید از اون pack uris در اینجا استفاده کرد؟
خیلی ممنون استاد .
 

the_king

مدیرکل انجمن
خیلی ممنون استاد . :rose:
من width و height هم در کد xaml برای اون Canvas تعریف کردم اما بدون اون تنظیم کردن متد Arrange ، درست نشد . کلا بدون استفاده از متد Arrange نمیشه ازش استفاده کرد (در کدهای xaml اش ابعاد را نمیشه مشخص کرد؟)
نمیدونم، اما چون Canvas رو بدون کد #C بکار نمی برید و RenderTargetBitmap رو با یکسری کد #C دارید، وجود Arrange تغییری در شرایط نمیده. شما از var استفاده نمی کنید که مبادا کدتون ساده تر و خلاصه تر بشه، بعد به فکر حذف یک سطر کد هستید؟ اگر برای استفاده از Canvas هیچگونه کد #C ای بکار نمی بردید، عدم استفاده از Arrange توجیه داشت چون بخاطرش باید کد #C ای هم اضافه میشد، اما در شرایطی که همین الان هم کد #C دارید، یک سطر بیشتر یا کمتر فرقی نمی کنه.

بعد اینکه در کد زیر :

کد:
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Canvas canvasMainIcon = (Canvas)this.myGrid1.TryFindResource("keyCanvsaMainIcon");
            canvasMainIcon.Arrange(new Rect(0, 0, 32, 32));

            RenderTargetBitmap bitmapImage = new RenderTargetBitmap(32, 32, 96, 96, PixelFormats.Pbgra32);
            bitmapImage.Render(canvasMainIcon);
            this.Icon = bitmapImage;

            Hardcodet.Wpf.TaskbarNotification.TaskbarIcon myTaskbarIcon = new Hardcodet.Wpf.TaskbarNotification.TaskbarIcon();
            myTaskbarIcon.IconSource = bitmapImage;
        }

در خط آخر ، مثل دفعه ی قبل ارور زیر را میده :
کد:
'Invalid URI: The format of the URI could not be determined.'

که قبلا برای اون ارور گفته بودید که از Pack Uris باید استفاده کنیم .
خوب اون رو که مسیر فایل را میدادیم و بجاش از قواعدی که در اون لینکی که تعیین کرد ، استفاده میکردیم اما در اینجا ، شی bitmapImage که براش مسیر فایل را مشخص نمیکنیم . پس چجوری باید از اون pack uris در اینجا استفاده کرد؟
خیلی ممنون استاد .
خطای عمومی نیست، خطای مربوط به سازگاری با اون کمپوننت ئه، من از ساختار Hardcodet.Wpf.TaskbarNotification.TaskbarIcon اطلاعی ندارم، اما احتمال داره که بخاطر کدی باشه که برای تبدیل تصویر به آیکون نوشته اند و با RenderTargetBitmap سازگاری نداره، لابد باید خودتون به آیکون تبدیلش کنید و مستقیما به myTaskbarIcon.Icon مقدار بدهید.
 

SajjadKhati

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

the_king

مدیرکل انجمن
خیلی ممنون استاد .
استاد ، دقت تایمر wpf با winform فرق داره یا همونه؟
دقت DispatcherTimer در حد همون Timer ئه اما قابلیت های بیشتری داره، حداقل اینکه میزان اولویت بروز رخداد اش قابل تنظیم ئه.

می توانید در مثال پیوستی بررسی اش کنید. TimerVsDispatcherTimer.zip
 

پیوست ها

  • TimerVsDispatcherTimer.zip
    675.2 کیلوبایت · بازدیدها: 7

SajjadKhati

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

XML:
            <Color x:Key="AccentColor"  A="255" R="20" G="200" B="250"/>
            <SolidColorBrush x:Key="AccentBrush" Color="{Binding Source={StaticResource AccentColor} }"/>

و یه دکمه (که در Resource نیست) :

XML:
 <Button HorizontalAlignment="Left" VerticalAlignment="Top" Margin="300,250,0,0" Content="Button" Height="25" Width="100" Background="{DynamicResource AccentBrush}" Click="Button_Click_4"/>

و در رویداد :

C#:
        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
               this.myGrid1.Resources["AccentColor"] = new Color { A = 255, R = 70, G = 70, B = 70 };
        }


چرا وقتی مقدار AccentColor را تغییر میدیم ، با اونکه Color ئه SolidColorBrush ، به AccentColor بایند شده ، رنگ و براشِ Background ئه اون دکمه ، تغییری نمیکنه؟
 

the_king

مدیرکل انجمن
ممنون استاد .
استاد ، در کد زیر که در Resource ئه grid تعریف شد :

XML:
            <Color x:Key="AccentColor"  A="255" R="20" G="200" B="250"/>
            <SolidColorBrush x:Key="AccentBrush" Color="{Binding Source={StaticResource AccentColor} }"/>

و یه دکمه (که در Resource نیست) :

XML:
 <Button HorizontalAlignment="Left" VerticalAlignment="Top" Margin="300,250,0,0" Content="Button" Height="25" Width="100" Background="{DynamicResource AccentBrush}" Click="Button_Click_4"/>

و در رویداد :

C#:
        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
               this.myGrid1.Resources["AccentColor"] = new Color { A = 255, R = 70, G = 70, B = 70 };
        }


چرا وقتی مقدار AccentColor را تغییر میدیم ، با اونکه Color ئه SolidColorBrush ، به AccentColor بایند شده ، رنگ و براشِ Background ئه اون دکمه ، تغییری نمیکنه؟
شما AccentColor رو تغییر می دهید، اما AccentBrush که صرفا موقع فراخوانی مقدار دهی شده، چطور باید متوجه تغییر مقدار AccentColor بشه؟ AccentColor که بهش سیگنال نمیفرسته که تغییری رخ داد. از اسمش مشخص ئه، Static Resource ئه، ایستا است، پویا نیست. تغییرات زمان اجرا در اتصال به StaticResource تاثیر نمیذاره. اگر قرار بر این بوده که مقدار AccentColor و AccentBrush در زمان اجرا تغییر کنه، پس جاش در بین Resource ها نیست، برایش DependencyProperty و Property تعریف کنید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
شما AccentColor رو تغییر می دهید، اما AccentBrush که صرفا موقع فراخوانی مقدار دهی شده، چطور باید متوجه تغییر مقدار AccentColor بشه؟ AccentColor که بهش سیگنال نمیفرسته که تغییری رخ داد. از اسمش مشخص ئه، Static Resource ئه، ایستا است، پویا نیست. تغییرات زمان اجرا در اتصال به StaticResource تاثیر نمیذاره. اگر قرار بر این بوده که مقدار AccentColor و AccentBrush در زمان اجرا تغییر کنه، پس جاش در بین Resource ها نیست، برایش DependencyProperty و Property تعریف کنید.

خیلی ممنون استاد .
بله قضیه ی StaticResource را حدودا میدونم . ولی فکر میکردم بخاطر binding کردن ، زمانی که مقداری تغییر میکنه ، target object ، از اون تغییر مقدار source object ، مطلع بشه .
پس چطور وقتی source object را یک پروپرتی ای از یک کنترل (کلا پروپرتی و کنترلی که بجز در resource تعریف شده باشه) در نظر میگیریم ، این اطلاع از تغییر مقدار ، صورت میپذیره اما اینجا نه؟

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

استاد ، میخوام برای نرم افزارم ، یه تم و اسکاین تعریف کنم .
یعنی مثلا یه combobox که دو گزینه داره . گزینه ی اول ، تم سیاه و گزینه ی دوم هم تم روشن .
میخوام دو تا resource تعریف کنم که یکی برای تم سیاه باشه و یکی هم برای تم روشن .
این دو تا resource ، از قبل (بصورت همین فایل resource) ، کاملا آماده هستند . یعنی قرار نیست زمان اجرا ، تم ای اضافه یا تغییر کنه (یعنی نیازی به DynamicResource نیست) .

حالا ، میخوام وقتی کاربر (در اون کمبوباکس) ، گزینه ی تم سیاه را انتخاب کرد ، فقط هر style ای که برای همه ی کنترل ها در اون resource ئه مربوط به تم سیاه تعریف شد ، بکار برده بشه (یعنی نیاز نیست همون زمان ، اطلاعات resource مربوط به تم روشن ، هم لود بشه) .

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

x:type Button

با این روش حل میشه؟
اما چرا در resource هایی که برای کنترل ها تعریف میکنیم (مثلا مقادیر و تگ هایی که در Grid.Resource تعریف میکنیم) ، لازم نیست حتما کلیدی بدیم اما در resource هایی که در فایل مجزا تعریف میکنیم ، باید حتما کلیدی بدیم؟

و بعد اینکه چون هر دوی این resource ها (که مربوط به دو تم هست) ، از یک تمپلیت برای کنترل هاشون استفاده میکنن ، بنابراین میخوام template ها را در فایل resource جداگانه ای تعریف کنم تا بصورت مشترک بتونن ازش استفاده کنن .

خوب ، حالا مشکل اصلی اینجاست که میخوام در اون دو resource (که مربوط به دو تم بودن) ، فقط رنگ های مولفه ها و کنترل هایی که در این template ها تعریف شدن را تغییر بدم . مثلا یه template برای textbox بصورت زیر ، تعریف میکنم :

XML:
            <ControlTemplate x:Key="checkBoxCustTemplate" TargetType="{x:Type CheckBox}">
                <!--برای این ، به پروپرتیِ Background شی Grid مقدار میدیم تا null نباشه وگرنه مشکل Hit Test بوجود میاد و در پشت زمینه ی خالیِ Border اگه کلیک شه ، تیک ای زده نمیشه-->
                <Grid Background="Transparent">

                    <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">
                        <Path x:Name="tickPath"  Stroke="{TemplateBinding BorderBrush}" StrokeThickness="1" Fill="{TemplateBinding BorderBrush}" StrokeStartLineCap="Triangle" StrokeEndLineCap="Triangle" Data="M1,7 Q3,7 5,9 Q8,4 12,2 M1,7 Q3.2,7.2 5,11 Q8.2,4.2 12,2"/>
                    </Border>

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

                </Grid>

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

میخوام فرضا برای پروپرتیِ Background مربوط به شی Border در کد بالا ، تغییر رنگ صورت بگیره . وقتی که تم سیاه انتخاب هست ، در اون resource ئه مربوط به تم سیاه ، که رنگ تیره تر ست شده ، اون رنگ به عنوان مقدار در پروپرتیِ Background مربوط به شی Border ست بشه و وقتی که تم روشن انتخاب شد ، در اون resource ئه مربوط به تم روشن ، که رنگ روشن تر ست شده ، اون رنگ به عنوان مقدار در پروپرتیِ Background مربوط به شی Border ست بشه .

یه مشکل اینه که چجوری از دورن resource های مربوط به اون دو تا تم ، به Resource ئه مربوط به template که کد بالا در اون تعریف شد ، و همچنین به شیِ Border در کد بالا (فرضا که براش ، نام هم انتخاب کرده باشیم) ، دسترسی پیدا کنم تا بگم پروپرتیِ Background ات را تغییر مقدار بده؟

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

the_king

مدیرکل انجمن
خیلی ممنون استاد .
بله قضیه ی StaticResource را حدودا میدونم . ولی فکر میکردم بخاطر binding کردن ، زمانی که مقداری تغییر میکنه ، target object ، از اون تغییر مقدار source object ، مطلع بشه.
پس چطور وقتی source object را یک پروپرتی ای از یک کنترل (کلا پروپرتی و کنترلی که بجز در resource تعریف شده باشه) در نظر میگیریم ، این اطلاع از تغییر مقدار ، صورت میپذیره اما اینجا نه؟
شما فکر می کنید زمانی که مقدار مدخل تغییر کرد target object باید از چه طریقی از تغییر مطلع بشه؟ موقع تغییر مقدار مدخل چه رخدادی اتفاق می افته که بخواد به جایی تغییر رو اطلاع بده؟ ResourceDictionary برای اینکار رخداد داره؟ اون AccentColor مشخصه ای داره که در set اش target object رو با خبر کنه؟ بالاخره یک کدی با تغییر مقدار مدخل باید اجرا بشه تا به موردی اطلاع بده، در کجا همچین کدی اجرا بشه؟


استاد ، میخوام برای نرم افزارم ، یه تم و اسکاین تعریف کنم .
یعنی مثلا یه combobox که دو گزینه داره . گزینه ی اول ، تم سیاه و گزینه ی دوم هم تم روشن .
میخوام دو تا resource تعریف کنم که یکی برای تم سیاه باشه و یکی هم برای تم روشن .
این دو تا resource ، از قبل (بصورت همین فایل resource) ، کاملا آماده هستند . یعنی قرار نیست زمان اجرا ، تم ای اضافه یا تغییر کنه (یعنی نیازی به DynamicResource نیست) .

حالا ، میخوام وقتی کاربر (در اون کمبوباکس) ، گزینه ی تم سیاه را انتخاب کرد ، فقط هر style ای که برای همه ی کنترل ها در اون resource ئه مربوط به تم سیاه تعریف شد ، بکار برده بشه (یعنی نیاز نیست همون زمان ، اطلاعات resource مربوط به تم روشن ، هم لود بشه) .

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

x:type Button

با این روش حل میشه؟


اما چرا در resource هایی که برای کنترل ها تعریف میکنیم (مثلا مقادیر و تگ هایی که در Grid.Resource تعریف میکنیم) ، لازم نیست حتما کلیدی بدیم اما در resource هایی که در فایل مجزا تعریف میکنیم ، باید حتما کلیدی بدیم؟

و بعد اینکه چون هر دوی این resource ها (که مربوط به دو تم هست) ، از یک تمپلیت برای کنترل هاشون استفاده میکنن ، بنابراین میخوام template ها را در فایل resource جداگانه ای تعریف کنم تا بصورت مشترک بتونن ازش استفاده کنن .

خوب ، حالا مشکل اصلی اینجاست که میخوام در اون دو resource (که مربوط به دو تم بودن) ، فقط رنگ های مولفه ها و کنترل هایی که در این template ها تعریف شدن را تغییر بدم . مثلا یه template برای textbox بصورت زیر ، تعریف میکنم :

XML:
            <ControlTemplate x:Key="checkBoxCustTemplate" TargetType="{x:Type CheckBox}">
                <!--برای این ، به پروپرتیِ Background شی Grid مقدار میدیم تا null نباشه وگرنه مشکل Hit Test بوجود میاد و در پشت زمینه ی خالیِ Border اگه کلیک شه ، تیک ای زده نمیشه-->
                <Grid Background="Transparent">

                    <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">
                        <Path x:Name="tickPath"  Stroke="{TemplateBinding BorderBrush}" StrokeThickness="1" Fill="{TemplateBinding BorderBrush}" StrokeStartLineCap="Triangle" StrokeEndLineCap="Triangle" Data="M1,7 Q3,7 5,9 Q8,4 12,2 M1,7 Q3.2,7.2 5,11 Q8.2,4.2 12,2"/>
                    </Border>

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

                </Grid>

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

میخوام فرضا برای پروپرتیِ Background مربوط به شی Border در کد بالا ، تغییر رنگ صورت بگیره . وقتی که تم سیاه انتخاب هست ، در اون resource ئه مربوط به تم سیاه ، که رنگ تیره تر ست شده ، اون رنگ به عنوان مقدار در پروپرتیِ Background مربوط به شی Border ست بشه و وقتی که تم روشن انتخاب شد ، در اون resource ئه مربوط به تم روشن ، که رنگ روشن تر ست شده ، اون رنگ به عنوان مقدار در پروپرتیِ Background مربوط به شی Border ست بشه .

یه مشکل اینه که چجوری از دورن resource های مربوط به اون دو تا تم ، به Resource ئه مربوط به template که کد بالا در اون تعریف شد ، و همچنین به شیِ Border در کد بالا (فرضا که براش ، نام هم انتخاب کرده باشیم) ، دسترسی پیدا کنم تا بگم پروپرتیِ Background ات را تغییر مقدار بده؟

و کلا روش پیاده سازی این قضیه ، چجوری میشه استاد؟
فرض کنید که در ResourceDictionary دو تا مجموعه Style ساخته ایم، RedStyle و BlueStyle که هر کدوم برای ظاهر چندین نوع کنترل توصیف دارند :
XML:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp1">
    <Style x:Key="RedStyle">
        <Style.Resources>
            <Style TargetType="ComboBox">
                <Setter Property="Background" Value="Red"/>
            </Style>
            <Style TargetType="Button">
                <Setter Property="Background" Value="Red"/>
            </Style>
        </Style.Resources>
    </Style>
    <Style x:Key="BlueStyle">
        <Style.Resources>
            <Style TargetType="ComboBox">
                <Setter Property="Background" Value="Blue"/>
            </Style>
            <Style TargetType="Button">
                <Setter Property="Background" Value="Blue"/>
            </Style>
        </Style.Resources>
    </Style>
</ResourceDictionary>

و برای پنجره مون هم RedStyle رو به عنوان پیشفرض انتخاب کرده ایم :
XML:
        Title="MainWindow" Height="450" Width="800" Style="{DynamicResource ResourceKey=RedStyle}">
    <Window.Resources>
        <ResourceDictionary Source="Dictionary1.xaml" />
    </Window.Resources>
می توانیم BlueStyle رو در زمان اجرا انتخاب کنیم :
C#:
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Style = (Style)FindResource("BlueStyle");
        }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
شما فکر می کنید زمانی که مقدار مدخل تغییر کرد target object باید از چه طریقی از تغییر مطلع بشه؟ موقع تغییر مقدار مدخل چه رخدادی اتفاق می افته که بخواد به جایی تغییر رو اطلاع بده؟ ResourceDictionary برای اینکار رخداد داره؟ اون AccentColor مشخصه ای داره که در set اش target object رو با خبر کنه؟ بالاخره یک کدی با تغییر مقدار مدخل باید اجرا بشه تا به موردی اطلاع بده، در کجا همچین کدی اجرا بشه؟



فرض کنید که در ResourceDictionary دو تا مجموعه Style ساخته ایم، RedStyle و BlueStyle که هر کدوم برای ظاهر چندین نوع کنترل توصیف دارند :
XML:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp1">
    <Style x:Key="RedStyle">
        <Style.Resources>
            <Style TargetType="ComboBox">
                <Setter Property="Background" Value="Red"/>
            </Style>
            <Style TargetType="Button">
                <Setter Property="Background" Value="Red"/>
            </Style>
        </Style.Resources>
    </Style>
    <Style x:Key="BlueStyle">
        <Style.Resources>
            <Style TargetType="ComboBox">
                <Setter Property="Background" Value="Blue"/>
            </Style>
            <Style TargetType="Button">
                <Setter Property="Background" Value="Blue"/>
            </Style>
        </Style.Resources>
    </Style>
</ResourceDictionary>

و برای پنجره مون هم RedStyle رو به عنوان پیشفرض انتخاب کرده ایم :
XML:
        Title="MainWindow" Height="450" Width="800" Style="{DynamicResource ResourceKey=RedStyle}">
    <Window.Resources>
        <ResourceDictionary Source="Dictionary1.xaml" />
    </Window.Resources>
می توانیم BlueStyle رو در زمان اجرا انتخاب کنیم :
C#:
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Style = (Style)FindResource("BlueStyle");
        }

خیلی ممنون استاد . :rose:
یعنی وقتی style ای را برای پنجره ی اصلی مون ست کنیم ، اتوماتیک برای همه ی پنجره ها و کنترل های فرزندش که در resource براشون style تعریف کرده بودیم ، استایل های اون کنترل ها هم ست میشن؟
اگه آره ، قضیه اش چجوری هه . یعنی چرا این جوری هه؟

چون فرضا در این مثالی که زدید ، حتی برای پنجره ی اصلی هم style ای تعریف نکر ید .


بعد اینکه اگه بصورت DynamicResource متصل نکنیم در مثال تون ، بهتر نیست؟
چون مقدار Resource که در زمان اجرا ، تغییری نکرد .
ممنون استاد .
 

the_king

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

چون فرضا در این مثالی که زدید ، حتی برای پنجره ی اصلی هم style ای تعریف نکر ید .
نکردم؟ اون "Style="{DynamicResource ResourceKey=RedStyle} پس Style کدوم المنت ئه؟ "Title="MainWindow عنوان پنجره اصلی نیست؟

بعد اینکه اگه بصورت DynamicResource متصل نکنیم در مثال تون ، بهتر نیست؟
چون مقدار Resource که در زمان اجرا ، تغییری نکرد .
بهتر به این معنی است که از DynamicResource استفاده نکردن مزیتی داشته باشه. از DynamicResource استفاده نکنید چه مزیتی بدست میاد؟
از DynamicResource استفاده می کنم تا موقعی Style مشخص بشه که Dictionary1 به Resources های پنجره اضافه شده و دسترسی به RedStyle هست.
اگر از StaticResource استفاده کنم بهتر نیست چون موقع فراخوانی المنت پنجره قبل از اینکه ResourceDictionary پردازش بشه Style میخواد تعیین بشه و هنوز Dictionary1 فراخوانی نشده که RedStyle ای موجود باشه.
 

SajjadKhati

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


نکردم؟ اون "Style="{DynamicResource ResourceKey=RedStyle} پس Style کدوم المنت ئه؟ "Title="MainWindow عنوان پنجره اصلی نیست؟


بهتر به این معنی است که از DynamicResource استفاده نکردن مزیتی داشته باشه. از DynamicResource استفاده نکنید چه مزیتی بدست میاد؟
از DynamicResource استفاده می کنم تا موقعی Style مشخص بشه که Dictionary1 به Resources های پنجره اضافه شده و دسترسی به RedStyle هست.
اگر از StaticResource استفاده کنم بهتر نیست چون موقع فراخوانی المنت پنجره قبل از اینکه ResourceDictionary پردازش بشه Style میخواد تعیین بشه و هنوز Dictionary1 فراخوانی نشده که RedStyle ای موجود باشه.


خیلی ممنون استاد
الان یه همچین چیزی توی resource نوشتم :

XML:
            <Style x:Key="DarkStyle">
                <Style.Resources>
                    <Style TargetType="CheckBox">
                        <Setter Property="Template" Value="{DynamicResource checkBoxCustTemplate}"/>
                    </Style>
                </Style.Resources>
            </Style>

            <Style x:Key="LightStyle">
                <Style.Resources>
                    <Style TargetType="CheckBox">
                        <Setter Property="Template" Value="{DynamicResource checkBoxCustTemplate}"/>
                    </Style>
                </Style.Resources>
            </Style>

            <ControlTemplate x:Key="checkBoxCustTemplate" TargetType="{x:Type CheckBox}">
                <!--برای این ، به پروپرتیِ Background شی Grid مقدار میدیم تا null نباشه وگرنه مشکل Hit Test بوجود میاد و در پشت زمینه ی خالیِ Border اگه کلیک شه ، تیک ای زده نمیشه-->
                <Grid Background="Transparent">

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

                    <Border Name="checkBorder" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top"  Width="16" Height="16" CornerRadius="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1">
                        <Path x:Name="tickPath"  Stroke="{TemplateBinding BorderBrush}" StrokeThickness="1" Fill="{TemplateBinding BorderBrush}" StrokeStartLineCap="Triangle" StrokeEndLineCap="Triangle" Data="M1,7 Q3,7 5,9 Q8,4 12,2 M1,7 Q3.2,7.2 5,11 Q8.2,4.2 12,2"/>
                    </Border>

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

                </Grid>

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

اما مشکل بزرگم اینه که همونطور که قبلا توضیح دادم ، نمیدونم چجوری از قسمت Style هایی که تعریف کردم (همون DarkStyle و LightStyle) ، به اون Border ای (بنام checkBorder) که در اون template تعریف کردم (از درون اون Style ها) دسترسی داشته باشم تا Background ئه مربوط به اون Border را در DarkStyle ، مقدار سیاه بدم و همچنین Background ئه مربوط به اون Border را در LightStyle، مقدار روشن تر بدم؟

این قضیه را چجوری باید درست کنم و کد را به چه صورتی باید بنویسم؟
 

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

بالا