قالب سیلورلایتی را ایجاد کرده بودم و IE در حالت نمایش عادی این قالب 30 درصد CPU Usage ثابت داشت. علت را هم متوجه نمیشدم؛ چون در این حالت اصلا کدی وجود نداشت که بخواهد CPU Usage ایی را ایجاد کند. یک سری کد XAML جهت نمایش قالب در کنار هم قرار گرفته بودند و همین.
تا اینکه دیروز در وبلاگ رسمی مرتبط با کارآیی برنامههای Silverlight مطلبی منتشر شد که دقیقا مشکل طراحی قالب من هم همان بود:
خلاصه آن:اگر در حالت نمایش برنامه Silverlight شما (بدون اینکه کدی در حال اجرا باشد) به صورت ثابت CPU Usage بالایی را مشاهده میکنید، پارامتر enableRedrawRegions تگ بارگذاری افزونهی Silverlight را به true مقدار دهی کنید.
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2">
...
<param name="enableRedrawRegions" value="true"/>
...
</object>
پس از فعال سازی این گزینه، برنامه را اجرا کنید. نواحی را که مرتبا در حال ترسیم مجدد هستند، با رنگهای آبی، زرد و صورتی مشاهده خواهید کرد.
در این حالت اگر ناحیهای مرتبا در حال به روز رسانی مشاهده گردید، دقیقا همین ناحیه است که سبب CPU Usage بالا و ثابت برنامه شما شده است و باید فکری به حال آن کرد.
چه زمانی ممکن است این حالت (ترسیمهای مجدد بدون پایان) رخ دهد؟عموما این مشکل در حین استفاده ناصحیح از افکتهای پیش فرض Silverlight مانند DropShadowEffect رخ میدهد. برای مثال میخواهید قسمتی از قالب شما سایه دار باشد اما نحوهی اعمال این سایه بسیار مهم است.
<Border CornerRadius="3">
<!--High cpu usage-->
<Border.Effect>
<DropShadowEffect BlurRadius="7" Color="#FF1E2224" Opacity="3" ShadowDepth="6" Direction="200" />
</Border.Effect>
<StackPanel>
...
...
در این مثال ابتدا یک border تعریف شده و سپس سایهای به آن اعمال گردیده است. سپس داخل این Border یک StackPanel قرار گرفته است به همراه یک سری از اشیاء زیر مجموعه آن. این کار غلط است! همین مورد به ظاهر ساده 30 درصد CPU Usage ثابت را در برنامه ایجاد کرده بود.
علت چیست؟با این نحوهی تعریف اشتباه DropShadowEffect ، هر نوع تغییر بصری در مجموعهی Border و StackPanel داخل آن، سبب ترسیم مجدد کل ناحیه میگردد. این تغییر بصری حتی میتواند شامل چشمک زدن یک cursor درون یک TextBox در قسمتی از این ناحیه نیز باشد که با استفاده از ویژگی enableRedrawRegions ، این مورد را به خوبی میتوان مشاهده نمود.
راه حل این مساله کدام است؟از دو Border استفاده کنید. یک Border با ضخامت کم تنها برای نمایش سایه (که دارای هیچ نوع شیء فرزندی نیست) و Border و StackPanel قبلی هم به همان صورت ابتدایی (البته با حذف DropShadowEffect از آن) باقی بماند.