Trong phần trước, tôi đã trình bày về phần core của UserControl CarRacer. Phần này, tôi sẽ tiếp tục trình bày cách implement các hiệu ứng chuyển động của xe.

Đầu tiên tôi sẽ cài đặt hiệu ứng chuyển động của bánh xe. Ở đây tôi muốn giảm bớt số lượng code trong file code behind nên tôi sẽ cài đặt animation viết bằng mã XAML:

<UserControl.Resources> <Storyboard x:Key="WheelAnimation" RepeatBehavior="Forever"> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="RenderTransform.Angle" Storyboard.TargetName="Banh_Xe_2"> <EasingDoubleKeyFrame Value="360"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="RenderTransform.Angle" Storyboard.TargetName="Banh_Xe_1"> <EasingDoubleKeyFrame Value="360"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </UserControl.Resources> 

Chúng ta khai báo một đối tượng kiểu Storyboard trong phần Resource của UserControl và có x:Key=”WheelAnimation”. Property RepeatBehavior được set thành Forever để đảm bảo bánh xe luôn luôn quay nếu xe vẫn còn đang chạy. Storyboard này có 2 child element kiểu DoubleAnimationUsingKeyFrames, mỗi element chính là thể hiện sự chuyển động quay tròn của mỗi bánh xe với TargetProperty là giá trị Angle của RotateTransform.

Tiếp theo, ta cài đặt hiệu ứng khi xe di chuyển trong phần code behind. Phương thức Run() sẽ thực hiện nhiệm vụ làm cho xe chạy, kết thúc chuyển động của bánh xe khi xe chạm đích và raise FinishedEvent. Nội dung của phương thức này như sau:

public void Run()
{
    // calculate the time using formular t = s/v double duration = Length / Speed; 

    // Get the storyboard which handles the animation of the wheels when the car runs. Storyboard wheelAnimation = this.Resources["WheelAnimation"] as Storyboard; 

    wheelAnimation.Duration = TimeSpan.FromSeconds(duration/2);

    Storyboard carAnimation = new Storyboard();
    DoubleAnimation animation = new DoubleAnimation();
    animation.To = Length;
    animation.Duration = TimeSpan.FromSeconds(duration);
    Storyboard.SetTarget(animation, this);
    Storyboard.SetTargetProperty(animation, new PropertyPath("(Canvas.Left)"));
    carAnimation.Children.Add(animation);

    // When the animation completed, it will stop the wheelAnimation and raise the FinishedEvent carAnimation.Completed += delegate {
        wheelAnimation.Stop();
        RoutedEventArgs re = new RoutedEventArgs(FinishedEvent);
        this.RaiseEvent(re);
    };
    carAnimation.Begin();
    wheelAnimation.Begin();
}

Như vậy, toàn bộ hoạt động của CarRacer control đã được cài đặt xong. Bây giờ chúng ta chuyển sang project CarRacerDemo để chạy thử control này. Trong file MainWindow.xaml, tôi đã thay đổi một số chi tiết như giá trị Speed của xe xanh để tạo ra sự khác biệt về chuyển động giữa 2 xe. Bên cạnh đó là một phương thức sẽ được thực thi mỗi khi event Finished được gọi (chỉ đơn giản là show messagebox).

Một Button cũng được thêm vào để gọi phương thức Run() của mỗi đối tượng CarRacer. Nội dung của file MainWindow.xaml như sau:

<Window x:Class="CarRacerDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:car="clr-namespace:CarRacer;assembly=CarRacer" Title="MainWindow" Height="250" Width="525"> <Canvas> <car:CarRacer Width="100" Height="55" Speed="150" Canvas.Top="10" Canvas.Left="0" Source="pack://application:,,,/CarRacerDemo;component/Than_xe.png" x:Name="xe_xanh" Margin="0 10" Finished="car_Finished"/> <car:CarRacer Grid.Row="1" Width="100" Height="55" Canvas.Top="100" Canvas.Left="0" Source="pack://application:,,,/CarRacerDemo;component/Xe_Do.png" x:Name="xe_do" Margin="0 10" Finished="car_Finished" /> <Button Content="Run The Car" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Top" Padding="10" Click="Button_Click" Canvas.Top="170" Canvas.Left="210" /> </Canvas> </Window> 

File MainWindow.xaml.cs thêm vào 2 phương thức, 1 phương thức thực thi khi sự kiện Button.Click được gọi, phương thức còn lại là khi event CarRacer.Finished được gọi. Hai phương thức này được khai báo như sau:

private void Button_Click(object sender, RoutedEventArgs e)
{
    xe_do.Run();
    xe_xanh.Run();
}

private void car_Finished(object sender, RoutedEventArgs e)
{
    MessageBox.Show((sender as CarRacer.CarRacer).Name + " finished!");
}

Bây giờ bạn có thể chạy thử chương trình và xem thử kết quả. Bài viết này mục đích chính là để giới thiệu cách define UserControl, DependencyProperty và RoutedEvent, đồng thời cũng hướng dẫn cách sử dụng lại các UserControl trong các project khác.

Download source: http://www.mediafire.com/?6url3arsrxgaqzg