أهلاً بكم من جديد في السلسلة التعليمية الأولى لـSilverlight باللغة العربية، تفترض هذه المقالة و هي الأخيرة ضمن السلسلة أنك قمت بقراءة الجزئين الأول و الثاني من هذه السلسلة، و قمت بتحميل الأدوات المطلوبة و التي تحدثنا عنها في الجزء الثاني إياه، لن تشرح لك هذه المقالة كيفية إنشاء مشاريع Silverlight يدوياً من الصفر (أنشئ ملف HTML جديد و اربطه بملف سكريبت بالاسم الفلاني و اكتب به كذا ...)، بالرغم من الأهمية الكبيرة لمعرفة ذلك، لأن هذه السلسلة مجرد مقدمة تعريفية إلى Silverlight، و أما من يريد هذه التفاصيل فأنصحه بمراجعة موقع Silverlight الرسمي و سيجد فيه الكثير من الدروس بهذا التفصيل، كما لن تشرح XAML أو Microsoft Expression Blend 2 بتفصيل كبير، لا تتردد بالاتصال بي إن واجهتك أي مشكلة تتعلق بهذا و سأبذلك جهدي في مساعدتك، فلن نستطيع تغطية كل المعلومات الضخمة الخاصة بـSilverlight في هذه السلسلة للأسف. ما سنفعله الآن هو استخدام الأدوات التي قمنا بتحميلها لنختصر على أنفسنا الوقت و الجهد، في البداية سننشئ مشروع Silverlight باستخدام Microsoft Expression Blend 2 و نضيف له بعض الـGraphics الأنيقة، ثم نقوم بإضافة بعض الكود إلى المشروع الجديد الذي أنشأناه عن طريق Visual Studio 2008، أنصحك بقراءة ما كتبته في مدونتي حول إضافة Javascript IntelliSense إلى Visual Studio لأن ذلك سيوفر عليك الكثير و الكثير من المشقة في برمجة تطبيقات Silverlight 1.0.

في الحقيقة من الصعب شرح كل شيء بالتفصيل في المقالة، لذلك سأشرح الخطوات العامة، فإن لم تعرف كيفية القيام بإحدى هذه الخطوات فاسأل و سنشرح بالتفصيل.
قم بتشغيل Microsoft Expression Blend 2 و أنشئ مشروعاً جديداً بالاسم الذي تريده من النوع Silverlight 1.0 Site.
في البداية سنجد Canvas فارغ الـXAML الخاص به هو :

<Canvas
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480"
    Background="White"
    x:Name="Page"
    >

</Canvas>

سأقوم بتعديل لون الخلفية ليصبح متدرج من الأزرق الفاتح إلى الأبيض، فنجد أن الخاصية Background قد حذفت من خصائص الـCanvas و أدرج بدلاً منها وسم جديد داخل الـCanvas هو Canvas.Background :

<Canvas.Background>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FF3CCEF8" Offset="0"/>
        <GradientStop Color="#FFFFFFFF" Offset="1"/>
    </LinearGradientBrush>
</Canvas.Background>

ثم سأضيف TextBlock بلون أزرق فاتح في منتصف الصفحة :

<TextBlock Width="111" Height="20" Text="AlMashroo.com" TextWrapping="Wrap" Canvas.Top="230" Canvas.Left="264.5" x:Name="websiteURLTextBlock" Foreground="#FF00C6FF"/>

سأضيف Storyboard لأجعل النص يدور حول نفسه مع اتجاه عقارب الساعة بلا توقف، ليصبح كود الصفحة ككل :

<Canvas
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480"
    x:Name="Page"
    >

    <Canvas.Triggers>
        <EventTrigger RoutedEvent="Canvas.Loaded">
            <BeginStoryboard x:Name="xFlipTextBlockStoryboard_BeginStoryboard">
                <Storyboard x:Name="xFlipTextBlockStoryboard">
                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="websiteURLTextBlock" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" RepeatBehavior="Forever">
                        <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
                        <SplineDoubleKeyFrame KeyTime="00:00:02" Value="-1"/>
                        <SplineDoubleKeyFrame KeyTime="00:00:04" Value="1"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Canvas.Triggers>
    <Canvas.Background>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="#FF3CCEF8" Offset="0"/>
            <GradientStop Color="#FFFFFFFF" Offset="1"/>
        </LinearGradientBrush>
    </Canvas.Background>
    <TextBlock Width="111" Height="20" Text="AlMashroo.com" TextWrapping="Wrap" Canvas.Top="230" Canvas.Left="264.5" x:Name="websiteURLTextBlock" Foreground="#FF00C6FF" RenderTransformOrigin="0.5,0.5">
        <TextBlock.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="1" ScaleY="1"/>
                <SkewTransform AngleX="0" AngleY="0"/>
                <RotateTransform Angle="0"/>
                <TranslateTransform X="0" Y="0"/>
            </TransformGroup>
        </TextBlock.RenderTransform>
    </TextBlock>
</Canvas>

واو، لاحظ كل هذا الكود الذي كتبه Blend لي و وفر علي كتابته يدوياً، لم أضطر حتى لتعديل أي شيء في XAML، ألم أقل لك سابقاً أنك لن تستطيع الاستغناء عن كل تلك الأدوات الرائعة؟
سأقوم بإضافة Storyboard أخرى لتدوير النص على المحور Y بدلاً من X، و لكن هذه المرة سأنشأه على شكل Resource و هذا يعني أن الحركة لن تبدأ تلقائياً مع بدأ البرنامج بل سنحتفظ بها لنستدعيها عن طريق الكود.
سنجد أن هناك Tag جديد ظهر تحت الـCanvas الأساسي باسم Canvas.Resources :

<Canvas.Resources>
    <Storyboard x:Name="yFlipTextBlockStoryboard">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="websiteURLTextBlock" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" RepeatBehavior="Forever">
            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
            <SplineDoubleKeyFrame KeyTime="00:00:02" Value="-1"/>
            <SplineDoubleKeyFrame KeyTime="00:00:04" Value="1"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Canvas.Resources>

و هو يحوي الحركة التي سنبدؤها عن طريق كود Javascript.
نريد الآن تعديل كود جافاسكريبت، لاحظ التكامل الكبير بين برنامجي Blend 2 و Visual Studio 2008، فسنقوم الآن بعد أن انتهينا من التصميم أن نضغط بالزر الأيمن على اسم المشروع في النافذة Project و من ثم نختار Edit in Visual Stduio لنجد VS جاهزاً لتعديل المشروع من وجهة نظره البرمجية.
سأقوم بكتابة كود بسيط جداً يتم تنفيذه عند الضغط على مربع النص، فيتحول محور الدوران من X إلى Y، أو العكس.
سأكتب هذا الكود في الـhandleLoad الموجود في السكريبت Page.xaml.js من المشروع :

rootElement.findName("websiteURLTextBlock").addEventListener("MouseLeftButtonUp", function(sender, eventArgs)
{
if (XFlip == true)
{
rootElement.findName("xFlipTextBlockStoryboard").stop();
rootElement.findName("yFlipTextBlockStoryboard").begin();
XFlip = false;
}
else
{
rootElement.findName("yFlipTextBlockStoryboard").stop();
rootElement.findName("xFlipTextBlockStoryboard").begin();
XFlip = true;
}
});

ليصبح كود الملف ككل :

if (!window.AlMashroo)
    window.AlMashroo = {};

AlMashroo.Page = function()
{
}

var XFlip;
AlMashroo.Page.prototype =
{
    handleLoad: function(control, userContext, rootElement)
    {
        this.control = control;
        XFlip  = true;
        // Sample event hookup: 
        rootElement.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this.handleMouseDown));
        rootElement.findName("websiteURLTextBlock").addEventListener("MouseLeftButtonUp", function(sender, eventArgs)
        {
        if (XFlip == true)
        {
        rootElement.findName("xFlipTextBlockStoryboard").stop();
        rootElement.findName("yFlipTextBlockStoryboard").begin();
        XFlip = false;
        }
        else
        {
        rootElement.findName("yFlipTextBlockStoryboard").stop();
        rootElement.findName("xFlipTextBlockStoryboard").begin();
        XFlip = true;
        }
        });
    },
   
    // Sample event handler
    handleMouseDown: function(sender, eventArgs)
    {
        // The following line of code shows how to find an element by name and call a method on it.
        // this.control.content.findName("Storyboard1").Begin();
    }
}

يقوم الكود الذي كتبته بإضافة حدث يتم تنفيذه عند القيام بـMouseLeftButtonUp لـwebsiteURLTextBlock، و بما أن هذا الحدث بسيط فضلت كتابة الكود الخاص به داخل سطر تعريف الحدث نفسه، يقوم الكود بفحص قيمة المتغير XFlip، فإن وجدها True يقوم الدوران حول المحور X و يحرك حول المحور Y، و إلا يوقف حركة المحور Y و يحرك حول المحور X، و في كلتا الحالتين يقوم بتغيير قيمة المتغير، يعتبر الحدث findName الذي استعملته من أهم الأحداث في Silverlight، تقوم بتمرير اسم العنصر إليه فيعيد إليك نسخة من العنصر الذي تبحث عنه.

انتهينا، شكراً لكل من تابع السلسلة و أرجو أن تكونوا استفدتم منها.