65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF LED自定义控件(后台代码实现)

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.69/5 (11投票s)

2018年8月22日

CPOL

3分钟阅读

viewsIcon

19793

downloadIcon

8

代码背后实现的LED(例如,交通灯)控件。可自定义颜色、透明度和尺寸。

 

Multiple LED controls

引言

我们需要一个用于WPF窗口基础架构库的控件,以可视方式显示应用程序中不同组件的状态。我脑海中冒出的最明显的东西是一个交通信号灯,默认情况下,它向我显示三个LED(绿色、橙色、红色),指示组件的状态(正常、警告、错误),其中只有一个LED可以处于活动状态。

为了让最终用户满意,我们希望使它们具有动画效果。 为了我自己,我想使它们具有动画效果、可配置、不使用图像且不使用资源。因此,我创建了一个LED控件,其中包含在代码背后实现的控件创建和动画功能。

Using the Code

为了良好的实践,我创建了两个程序集。 一个程序集模拟包含“LedControl”的公共基础架构库,另一个程序集在WPF应用程序中显示该控件。 我通常使用Prism进行组合模式、注入、MVVM等,但为了使此示例简单,我在MainWindow程序集的MVVM文件夹中创建了两个类,并在MainWindow XAML代码中直接分配了ViewModel。 这不是一个好习惯,但我想保持示例简单。 LED控件是在考虑特定合同的情况下创建的,因此仅在该合同中进行了测试。

控件属性

该控件具有以下可配置的依赖项属性

List<Color> Leds

用于以定义的颜色显示LED的颜色列表。 默认为绿色、橙色和红色。
下面的图像显示了默认LED的开/关模式。

绿色 橙色 红色
Green Green Red

double OffOpacity

LED颜色在关闭模式下的不透明度。 默认为0.4。

int ActiveLed

LED的活动索引。 例如,0=没有活动,1=LED列表中第一个LED处于活动状态,2=第二个,等等。

Orientation LedOrientation

LED的方向。 水平或垂直。 默认为水平。

方向的重要性在于,当方向为水平时,应在自定义控件上定义高度;如果方向为垂直,则应定义宽度。 这用于控制LED的大小。
如果不是,请设置自定义控件将使用可用的大小。

该控件使用一个StackPanel,其中包含一个Ellipse(LED)控件列表。 椭圆的笔刷用于显示LED的颜色并模拟开/关行为。

LED的加载发生在控件加载后,以便我们知道框架元素的大小。 加载事件在构造函数中注册

        public LedControl()
        {
            Loaded += LoadLeds;
        }

控件的创建发生在LoadLeds方法中,该方法在控件加载后或Leds属性更改后调用。

        private void LoadLeds(object sender, RoutedEventArgs e)
        {
            FrameworkElement parent = Parent as FrameworkElement;
            StackPanel panel = new StackPanel();
            Content = panel;
            panel.Orientation = LedOrientation;
            panel.Children.Clear();
            ellipses.Clear();
            double size;

            if (LedOrientation == Orientation.Horizontal)
            {
                size = Height;
            }
            else
            {
                size = Width;
            }
            // Give it some size if forgotten to define width or height in combination with orientation
            if ((size.Equals(double.NaN)) && (parent != null) && (Leds.Count != 0))
            {
                if (parent.ActualWidth != double.NaN)
                {
                    size = parent.ActualWidth / Leds.Count;
                }
                else if (parent.ActualHeight != double.NaN)
                {
                    size = parent.ActualHeight / Leds.Count;
                }
            }
            // Create LED for each defined color in Leds
            foreach (Color color in Leds)
            {
                Ellipse ellipse = new Ellipse();
                ellipse.Height = size > 4 ? size - 4 : size;
                ellipse.Width = size > 4 ? size - 4 : size;
                ellipse.Margin = new Thickness(2);
                ellipse.Style = null;
                // Border for led
                RadialGradientBrush srgb = new RadialGradientBrush(new GradientStopCollection
                {
                    new GradientStop(Color.FromArgb(255, 211, 211, 211), 0.8d),
                    new GradientStop(Color.FromArgb(255, 169, 169, 169), 0.9d),
                    new GradientStop(Color.FromArgb(255, 150, 150, 150), 0.95d),
                });

                if (size <= 50)
                {
                    ellipse.StrokeThickness = 5;
                }
                else if (size <= 100)
                {
                    ellipse.StrokeThickness = 10;
                }
                else
                {
                    ellipse.StrokeThickness = 20;
                }

                srgb.GradientOrigin = new System.Windows.Point(0.5d, 0.5d);
                srgb.Center = new System.Windows.Point(0.5d, 0.5d);
                srgb.RadiusX = 0.5d;
                srgb.RadiusY = 0.5d;
                ellipse.Stroke = srgb;
                // Color of led
                RadialGradientBrush rgb = new RadialGradientBrush(new GradientStopCollection
                {
                    new GradientStop(Color.FromArgb(150, color.R, color.G, color.B), 0.1d),
                    new GradientStop(Color.FromArgb(200, color.R, color.G, color.B), 0.4d),
                    new GradientStop(Color.FromArgb(255, color.R, color.G, color.B), 1.0d),
                });

                rgb.GradientOrigin = new System.Windows.Point(0.5d, 0.5d);
                rgb.Center = new System.Windows.Point(0.5d, 0.5d);
                rgb.RadiusX = 0.5d;
                rgb.RadiusY = 0.5d;
                // ellipse.Fill is used as animation target
                ellipse.Fill = rgb;
                ellipse.Fill.Opacity = OffOpacity;
                panel.Children.Add(ellipse);
                ellipses.Add(ellipse);
            }

            LedOn();
        }

两种方法 LedOn()

        private void LedOn()
        {
            DoubleAnimation animation = new DoubleAnimation();
            animation.From = OffOpacity;
            animation.To = 1.0d;
            animation.Duration = new Duration(TimeSpan.FromSeconds(1));
            animation.AutoReverse = false;

            for (int i = 0; i < ellipses.Count; i++)
            {
                if ((ActiveLed - 1 == i) && (ellipses[i].Fill.Opacity < 1.0))
                {
                    ellipses[i].Fill.BeginAnimation(Brush.OpacityProperty, animation);
                }
            }
        }

LedOff()

        private void LedOff()
        {
            DoubleAnimation animation = new DoubleAnimation();
            animation.From = 1.0d;
            animation.To = OffOpacity;
            animation.Duration = new Duration(TimeSpan.FromSeconds(1));
            animation.AutoReverse = false;

            for (int i = 0; i < ellipses.Count; i++)
            {
                if ((ActiveLed - 1 != i) && (ellipses[i].Fill.Opacity > OffOpacity))
                {
                    ellipses[i].Fill.BeginAnimation(Brush.OpacityProperty, animation);
                }
            }
        }

通过更改椭圆笔刷上的不透明度,在ActiveLed更改后运行动画。 检查ActiveLed和当前Opacity是为了确保我们不会同时打开和关闭同一个LED。

如何使用控件

MainWindowxaml中,您可以找到一些有关如何使用控件和测试您自己创建的内容的示例。 一些如下所示

    <controls:LedControl ActiveLed="{Binding ActiveLedItem1}" 
    LedOrientation="Vertical" Width="50" />
    
    <controls:LedControl ActiveLed="{Binding ActiveLedItem1}" 
    Height="125" />
    
    <controls:LedControl ActiveLed="{Binding ActiveLedItem1}" 
    LedOrientation="Vertical" Width="50" Leds="{Binding Colors}" />

历史

  • 2018年8月22日:首次发布
© . All rights reserved.