2025年5月21日 星期三 乙巳(蛇)年 二月廿三 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > .net

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

时间:05-30来源:作者:点击数:50

先看一下效果图:

第一步:新建一个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),返回相应的色彩画刷(newSolidColorBrush(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下载地址

下载:交通红绿灯

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门