先看一下效果图:
第一步:新建一个WPF应用程序,这一步的操作就这里省略了。
第二步:在刚才新建的WPF应用程序中添加一个UserControl命名为:TrafficLightControl,如下图所示
关键代码如下,可以直接拷贝到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下载地址
下载:交通红绿灯