通过WPF模拟交通红绿灯(图文教程)

先看一下效果图:

第一步:新建一个WPF应用程序,这一步的操作就这里省略了。

第二步:在刚才新建的WPF应用程序中添加一个UserControl命名为:TrafficLightControl,如下图所示

2011-03-08_145530

关键代码如下,可以直接拷贝到VS2010即可:

   1:  <UserControl x:Class="WPF绑定转换器.TrafficLightControl"
   2:               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:               xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
   5:               xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   6:               xmlns:myConverter="clr-namespace:WPF绑定转换器"
   7:                Width="120" Height="350">
   8:      <UserControl.Resources>
   9:          <myConverter:ColorConverter x:Key="colorConverter" />
  10:      </UserControl.Resources>
  11:      <Grid>
  12:          <Border Background="Black" CornerRadius="10" BorderBrush="Gray" BorderThickness="2">
  13:              <StackPanel VerticalAlignment="Center">
  14:                  <StackPanel.Resources>
  15:                      <Style TargetType="{x:Type Ellipse}">
  16:                          <Setter Property="Width" Value="100"></Setter>
  17:                          <Setter Property="Height" Value="100"></Setter>
  18:                          <Setter Property="Fill" Value="LightGray"></Setter>
  19:                          <Setter Property="Stroke" Value="Gray"></Setter>
  20:                          <Setter Property="StrokeThickness" Value="2"></Setter>
  21:                          <Setter Property="Margin" Value="4"></Setter>
  22:                      </Style>
  23:                  </StackPanel.Resources>
  24:                  <Ellipse Fill="{Binding State,Converter={StaticResource colorConverter},
                                      ConverterParameter=RED}"/>

25: <Ellipse Fill="{Binding State,Converter={StaticResource colorConverter},

ConverterParameter=YELLOW}"/>

  26:                  <Ellipse Fill="{Binding State,Converter={StaticResource colorConverter},
                                      ConverterParameter=GREEN}"/>
  27:              </StackPanel>
  28:          </Border>
  29:      </Grid>
  30:  </UserControl>

代码解释:为了模拟红绿灯,代码24,25,26行分别创建了3个椭圆,分别设置椭圆的Fill属性,每个椭圆的Fill属性通过绑定的一个状态枚举State{GREEN,YELLOW,RED},Fill属性值实际是一个Brush实例,由于这里用到了枚举值,所以这里同时又创建了一个Converter,在第6行是具体引入这个转换器的方法,下面贴出这个转换器的代码:

   1:      [ValueConversion(typeof(TrafficLight.States), typeof(Brush))]
   2:      public class ColorConverter : IValueConverter
   3:      {
   4:          public enum Lights
   5:          {
   6:              GREEN,
   7:              YELLOW,
   8:              RED
   9:          }
  10:          public object Convert(object value, Type targetType, object parameter, 
                                     System.Globalization.CultureInfo culture)
  11:          {
  12:              TrafficLight.States state = (TrafficLight.States)value;
  13:              Lights light = (Lights)Enum.Parse(typeof(Lights), (string)parameter);
  14:              switch (state)
  15:              {
  16:                  case TrafficLight.States.GREEN:
  17:                      if (light == Lights.GREEN)
  18:                      {
  19:                          return new SolidColorBrush(Colors.Green);
  20:                      }
  21:                      break;
  22:                  case TrafficLight.States.YELLOW:
  23:                      if (light == Lights.YELLOW)
  24:                      {
  25:                          return new SolidColorBrush(Colors.Yellow);
  26:                      }
  27:                      break;
  28:                  case TrafficLight.States.RED:
  29:                      if (light == Lights.RED)
  30:                      {
  31:                          return new SolidColorBrush(Colors.Red);
  32:                      }
  33:                      break;
  34:              }
  35:              return new SolidColorBrush(Colors.LightGray);
  36:          }
  37:   
  38:          public object ConvertBack(object value, Type targetType, object parameter, 
                                         System.Globalization.CultureInfo culture)
  39:          {
  40:              return null;
  41:          }
  42:      }

代码解释:由于上面创建椭圆的Fill属性值就是一个Color实例,所以这里的转换器实现的基本功能就是,根据传来的枚举状态值(GREEN,RED,YELLOW),返回相应的色彩画刷(new SolidColorBrush(Colors.颜色)),实现了转换器之后,下面继续实现状态枚举State,代码如下:

   1:  public class TrafficLight : INotifyPropertyChanged
   2:      {
   3:          public event PropertyChangedEventHandler PropertyChanged;
   4:   
   5:          private States _state;
   6:   
   7:          public enum States
   8:          {
   9:              GREEN,
  10:              YELLOW,
  11:              RED
  12:          }
  13:   
  14:          public States State
  15:          {
  16:              get
  17:              {
  18:                  return _state;
  19:              }
  20:              set
  21:              {
  22:                  if (value != _state)
  23:                  {
  24:                      _state = value;
  25:                      if (PropertyChanged != null)
  26:                      {
  27:                          PropertyChanged(this,new PropertyChangedEventArgs("State"));
  28:                      }
  29:                  }
  30:              }
  31:          }
  32:      }

代码解释:状态枚举的定义非常简单,这里不做解释了,拷贝代码只可。

第三步:实现了第二步操作,第三步主要工作是,在项目里添加一个WPF窗口来容纳第二步创建的用户控件(TrafficLightControl)

1、页面代码,Xaml代码如下:

   1:  <Window x:Class="WPF绑定转换器.MainWindow"
   2:          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:          xmlns:my="clr-namespace:WPF绑定转换器"
   5:          Title="MainWindow" Height="512" Width="400" Name="mainWnd" AllowsTransparency="True"
   6:           WindowStyle="None" WindowStartupLocation="CenterScreen" 
                             MouseLeftButtonDown="mainWnd_MouseLeftButtonDown">
   7:  <Window.Resources>
   8:      <my:TrafficLight State="Red" x:Key="myTrafficLight"/>
   9:      <Style BasedOn="{x:Null}" TargetType="{x:Type Button}">
  10:         <Setter Property="Template">
  11:              <Setter.Value>
  12:                  <ControlTemplate TargetType="{x:Type Button}">
  13: <Grid x:Name="buttonClose">
  14:                         <Ellipse Stroke="{x:Null}" StrokeThickness="1" x:Name="btnEllipse" >
  15:                            <Ellipse.Fill>
  16:                               <RadialGradientBrush>
  17:                                  <GradientStop Color="#BFABA7A4" Offset="0.777"/>
  18:                                  <GradientStop Color="#FF897F77" Offset="1"/>
  19:                               </RadialGradientBrush>
  20:                            </Ellipse.Fill>
  21:                         </Ellipse>
  22:   
  23:
  24:   <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                   HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
          VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
  25:</Grid>
  26:                          <ControlTemplate.Triggers>
  27:                              <Trigger Property="IsFocused" Value="True"/>
  28:                              <Trigger Property="IsDefaulted" Value="True"/>
  29:                              <Trigger Property="IsMouseOver" Value="True">
  30:                              <Setter Property="Fill" Value="#FF5D4E3E" TargetName="btnEllipse"/>
  31:                              </Trigger>
  32:                              <Trigger Property="IsPressed" Value="True"/>
  33:                              <Trigger Property="IsEnabled" Value="False"/>
  34:                          </ControlTemplate.Triggers>
  35:                      </ControlTemplate>
  36:                  </Setter.Value>
  37:              </Setter>
  38:          </Style>
  39:      </Window.Resources>
  40:   
  41:      <Border BorderBrush="LightGray" BorderThickness="5">
  42:          <Grid Background="AliceBlue">
  43:              <Grid.RowDefinitions>
  44:                  <RowDefinition Height="30"></RowDefinition>
  45:                  <RowDefinition Height="30"></RowDefinition>
  46:                  <RowDefinition Height="360"></RowDefinition>
  47:                  <RowDefinition Height="*"></RowDefinition>
  48:              </Grid.RowDefinitions>
  49:              <Grid Grid.Row="0">
  50:                  <Grid.ColumnDefinitions>
  51:                      <ColumnDefinition Width="260"></ColumnDefinition>
  52:                      <ColumnDefinition Width="100"></ColumnDefinition>
  53:                      <ColumnDefinition Width="*"></ColumnDefinition>
  54:                  </Grid.ColumnDefinitions>

55: <TextBlock Grid.Column="0" HorizontalAlignment="Right"

VerticalAlignment="Center" FontFamily="Arial" FontSize="20" Text="模拟红绿灯实验">

</TextBlock>

  56:                  <Button Name="btnClose" Grid.Column="1" HorizontalAlignment="Right" 
        VerticalAlignment="Center" Content="X" Width="16" Height="16" Click="btnClose_Click"></Button>
  57:              </Grid>
  58:              <Grid Grid.Row="1">
  59:                  <Grid.ColumnDefinitions>
  60:                      <ColumnDefinition Width="200"></ColumnDefinition>
  61:                      <ColumnDefinition Width="*"></ColumnDefinition>
  62:                  </Grid.ColumnDefinitions>

63: <Ellipse Name="flagEllipse" HorizontalAlignment="Right"

VerticalAlignment="Center" Grid.Column="0" Fill="Red" Width="18" Height="18"></Ellipse>

  64:                  <Label Name="lblMessage" HorizontalAlignment="Left" VerticalAlignment="Center" 
                        Grid.Column="1" Height="27"></Label>
  65:              </Grid>
  66:              my:TrafficLightControl Grid.Row="2" DataContext="{StaticResource myTrafficLight}"/>
  67:      <StackPanel Orientation="Horizontal" Grid.Row="3" HorizontalAlignment="Center" Height="30">
  68:      <Button Content="开始模拟" Width="100" Margin="2" Click="ButtonClicked" Name="btnStart"/>
  69:      <Button Content="停止模拟" Width="100" Margin="2" Click="ButtonClicked" Name="btnStop"/>
  70:      </StackPanel>
  71:      </Grid>
  72:      </Border>
  73:  </Window>

2、后台代码,cs代码:

   1:   /// <summary>
   2:      /// Interaction logic for MainWindow.xaml
   3:      /// </summary>
   4:      public partial class MainWindow : Window
   5:      {
   6:          BackgroundWorker _backgroundWorker = new BackgroundWorker();
   7:          DispatcherTimer dispatcherTimer = new DispatcherTimer();
   8:          public MainWindow()
   9:          {
  10:              InitializeComponent();
  11:              _backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
  12:              _backgroundWorker.RunWorkerCompleted += 
                   new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
  13:   
  14:              dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
  15:              dispatcherTimer.Interval = TimeSpan.FromMilliseconds(200);
  16:          }
  17:   
  18:          void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  19:          {
  20:              if (e.Cancelled)
  21:              {
  22:                  lblMessage.Content = "终止";
  23:              }
  24:              else if (e.Error != null)
  25:              {
  26:                  lblMessage.Content = "异常";
  27:              }
  28:              else
  29:              {
  30:                  lblMessage.Content = "运行";
  31:              }
  32:          }
  33:   
  34:          void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
  35:          {
  36:              TrafficLight tLight = (TrafficLight)this.FindResource("myTrafficLight");
  37:              if (tLight.State == TrafficLight.States.GREEN)
  38:              {
  39:                  tLight.State = TrafficLight.States.RED;
  40:                  Thread.Sleep(TimeSpan.FromSeconds(5));
  41:              }
  42:              else if (tLight.State == TrafficLight.States.RED)
  43:              {
  44:                  tLight.State = TrafficLight.States.YELLOW;
  45:                  Thread.Sleep(TimeSpan.FromSeconds(2));
  46:              }
  47:              else if (tLight.State == TrafficLight.States.YELLOW)
  48:              {
  49:                  tLight.State = TrafficLight.States.GREEN;
  50:                  Thread.Sleep(TimeSpan.FromSeconds(5));
  51:              }
  52:          }
  53:   
  54:          void dispatcherTimer_Tick(object sender, EventArgs e)
  55:          {
  56:              if (!_backgroundWorker.IsBusy)
  57:              {
  58:                  _backgroundWorker.RunWorkerAsync();
  59:              }
  60:          }
  61:   
  62:          private void ButtonClicked(object sender, RoutedEventArgs e)
  63:          {
  64:              if (sender == btnStart)
  65:              {
  66:                  dispatcherTimer.Start();
  67:                  flagEllipse.Fill = Brushes.Red;
  68:                  DoubleAnimation da = 
                       new DoubleAnimation(1, 0, new Duration(TimeSpan.FromSeconds(0.2)));
  69:                  da.AutoReverse = true;
  70:                  da.RepeatBehavior = RepeatBehavior.Forever;
  71:                  flagEllipse.BeginAnimation(Ellipse.OpacityProperty, da);
  72:              }
  73:              else if (sender == btnStop)
  74:              {
  75:                  dispatcherTimer.Stop();
  76:                  lblMessage.Content = "中止";
  77:                  flagEllipse.Fill = Brushes.Black;
  78:              }
  79:          }
  80:   
  81:          private void mainWnd_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  82:          {
  83:              this.DragMove();
  84:          }
  85:   
  86:          private void btnClose_Click(object sender, RoutedEventArgs e)
  87:          {
  88:              this.Close();
  89:          }
  90:      }

代码解释:拷贝相应代码即可,为了解决界面更新容易假死的情况,这里利用了异步多线程模型BackgroundWorker,对BackgroundWorker模型用法不清楚的可以BaiDu一下,到处都是。

总结:事实上为了模拟红绿灯效果,并不是一步到位的,比如我开始是利用三个按钮(红灯、黄灯、绿灯),并添加相应的Click事件在运行时改变State属性值,之后改成通过DispatcherTimer 调度时钟,自动开启BackgroundWorker异步模型,并每隔一段时间查询模型运行状态,也就是模拟红红绿灯的运行状态。

第四步:一下Demo下载地址

下载:交通红绿灯

posted @ 2011-03-08 16:14  小麻雀  阅读(8372)  评论(2编辑  收藏  举报