当前位置:   article > 正文

WPF监控平台(科技大屏)[一]

WPF监控平台(科技大屏)[一]

        跟着B站的视频敲了一个略微复杂的WPF界面,链接如下.在这里我详细的写一份博客进行设计总结.

系统介绍和配置及主窗口设计_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1Wy421Y7QD?p=1&vd_source=4796b18a2e4c1ec8a310391a5644b6da

     成果展示 

    实现过程

        总体来说,我的理解都是设计框架,再具体的画里面的布局.

        界面整体背景设计

         我们不需要窗口自带的边框,所以需要隐藏,这里调用设计WindowChrome中的GlassFrameThickness 为0或者负数即可.

  1. <WindowChrome.WindowChrome>
  2. <!--隐藏边框-->
  3. <WindowChrome GlassFrameThickness="0"></WindowChrome>
  4. </WindowChrome.WindowChrome>

        界面整体颜色为渐变色,进行设计,渐变色使用画刷,这里介绍两种画刷,两种画刷的写法一致,只是颜色的方向有所差别,都是使用offset表示与开始点的距离

       1.LinearGradientBrush,这种画刷是由左上角向右下.

       2.RadialGradientBrush,这种画刷是有中心向外面渐变(此项目使用这种)

  1. <!--设计背景颜色渐变-->
  2. <Grid.Background>
  3. <RadialGradientBrush>
  4. <GradientStop Color="#ff285173" Offset="0"></GradientStop>
  5. <GradientStop Color="#ff244967" Offset="0.5"></GradientStop>
  6. <GradientStop Color="#13164B" Offset="1"></GradientStop>
  7. </RadialGradientBrush>
  8. </Grid.Background>

        运行结果:

        首页设计

         首页分为三行进行设计,标题为第一行,中间的内容为第二行,底部为第三行.

         代码先分出三行:类似于代码中Height之类的属性,可以自己试着调,让界面看起来美观即可

  1. <!--主界面分三行-->
  2. <Grid.RowDefinitions>
  3. <RowDefinition Height="50"></RowDefinition>
  4. <RowDefinition Height="auto"></RowDefinition>
  5. <RowDefinition Height="25"></RowDefinition>
  6. </Grid.RowDefinitions>
       第一行:

        第一行下面的分割线颜色设计为#5518aabd,整体分为3列,第三列再分为两行进行设计.

        第一列最左边为一个图标,直接将文件中的Image拖入即可

  1. <!--图标-->
  2. <Image Source="/Res/Img/Logo.png" Margin="10,7" />

        第二列放置一个垂直吧方向的堆面板,再用TextBlock放置文字

  1. <!--文字-->
  2. <StackPanel Orientation="Vertical" Grid.Column="1">
  3. <TextBlock Text="生产监控平台" Foreground="White" FontSize="16" VerticalAlignment="Center" Margin="0,5,0,0"></TextBlock>
  4. <TextBlock Text="阻碍你前行的,其实就是你自己!" Foreground="White" FontSize="12" Margin="0,3,0,0" ></TextBlock>
  5. </StackPanel>

        第三列整体分为两行,第一行使用对面板放置三个按钮,第二行画纹路.,下面代码中的最小化和关闭按钮我与视频中的处理方法不一样,我这里是直接设计了一个点击事件,在此界面对应的代码中直接对窗口进行控制.

  1. <!--右侧按钮和下面的图案-->
  2. <Grid Grid.Column="2">
  3. <!--分为两行-->
  4. <Grid.RowDefinitions>
  5. <RowDefinition></RowDefinition>
  6. <RowDefinition Height="15"></RowDefinition>
  7. </Grid.RowDefinitions>
  8. <!--三个图标-->
  9. <!--WindowChrome.IsHitTestVisibleInChrome="True" 一定要加,否则自定义的不会显示-->
  10. <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Background="Transparent" WindowChrome.IsHitTestVisibleInChrome="True">
  11. <Button Style="{StaticResource MinClose_BtnStyle}" Content="&#xe624;" Click="Button_Click_Min"></Button>
  12. <Button Style="{StaticResource MinClose_BtnStyle}" Content="&#xe600;"></Button>
  13. <Button Style="{StaticResource MinClose_BtnStyle}" Content="&#xe609;" Background="DarkRed" Click="Button_Click_Close"></Button>
  14. </StackPanel>
  15. <!--图案-->
  16. <Border Grid.Row="1" BorderBrush="#5518aabd" BorderThickness="0,1,0,0" >
  17. <Border.Background>
  18. <VisualBrush TileMode="FlipXY" Viewport="0,0,7,7" ViewportUnits="Absolute">
  19. <VisualBrush.Visual>
  20. <Line X1="0" Y1="10" X2="10" Y2="0" Stroke="Gray" StrokeThickness="1"></Line>
  21. </VisualBrush.Visual>
  22. </VisualBrush>
  23. </Border.Background>
  24. </Border>
  25. </Grid>

        其中,设计三个图标时引入了一个自定义的资源字典,因为不止这里会用到,故定义的全局变量.

  1. <!--关闭\最小化按钮字典-->
  2. <Style TargetType="Button" x:Key="MinClose_BtnStyle">
  3. <Setter Property="Width" Value="40"></Setter>
  4. <Setter Property="Background" Value="#11ffffff"></Setter>
  5. <Setter Property="Foreground" Value="White"></Setter>
  6. <Setter Property="FontFamily" Value="../Res/Fonts/#iconfont"></Setter>
  7. <!--模板-->
  8. <Setter Property="Template">
  9. <Setter.Value>
  10. <ControlTemplate TargetType="Button">
  11. <!--grid的背景就是按钮的背景-->
  12. <Grid Background="{TemplateBinding Background}">
  13. <Border x:Name="border">
  14. <!--用于显示控件的内容-->
  15. <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
  16. </Border>
  17. </Grid>
  18. <!--触发器-->
  19. <ControlTemplate.Triggers>
  20. <Trigger Property="IsMouseOver" Value="True">
  21. <Setter TargetName="border" Property="Background" Value="#33ffffff"></Setter>
  22. </Trigger>
  23. </ControlTemplate.Triggers>
  24. </ControlTemplate>
  25. </Setter.Value>
  26. </Setter>
  27. </Style>

        这里字典中的FontFamily是再阿里巴巴资源图标库下载的后缀为.ttf的文件,content设置为里面的代码即可显示对应的图标 

        然后需要设计 WindowChrome.IsHitTestVisibleInChrome="True"

        最后的图案是再boder中使用画笔画出

        运行的结果

         第三行

         第三行是底部,比较简单和第一行类似,因此我们先进行设计.

        底部分为两列,第一列绘制图案,第二列是相关文字

        运行的结果

        第二行

        第二行内容很多,我们自定义一个用户控件放入.

        首先要做的就是定义一个用户控件嵌入到主窗口之中,这里先新定义一个用户控件文件,再创建一个ViewModel层的文件,在里面将二者绑定起来

  1. public event PropertyChangedEventHandler PropertyChanged;
  2. #region 中间那个 用户控件
  3. private UserControl _MonitorUC;
  4. public UserControl MonitorUC
  5. {
  6. get {
  7. if(_MonitorUC == null)
  8. {
  9. _MonitorUC = new MonitorUC();
  10. }
  11. return _MonitorUC;
  12. }
  13. set {
  14. _MonitorUC = value;
  15. if (PropertyChanged != null)
  16. {
  17. PropertyChanged(this, new PropertyChangedEventArgs("MonitorUC"));
  18. }
  19. }
  20. }

             然后在主界面的 代码下实例化viewModel,设置数据上下文

  1. //实例化
  2. MainWindowVM mainWindowVM = new MainWindowVM();
  3. public MainWindow()
  4. {
  5. InitializeComponent();
  6. //设置数据上下文
  7. this.DataContext = mainWindowVM;
  8. }

        最后主界面一定要嵌入此用户控件,嵌入使用ContentControl

<ContentControl Grid.Row="1" Content="{Binding MonitorUC}"></ContentControl>

        运行结果:

        接着对第二行内部(自定义用户控件)进行设计,分为三行:

        第二行内部的第一行分为两列,左边的日期为一列,右边剩下的为一列

        左边第一列日期用一个水平方向的对面板里面放置一个TextBlock和一个垂直方向的堆面板,时间和日期视频里面是静态的,我这里进行动态获取,可参考这篇专栏里面的另一篇实时时间显示.

        右边分为左右两部分,用靠左和靠右实现即可,左边使用水平方向的堆面板进行排列,文字换行使用WPF里面的换行符,中间有背景的字是再border里面嵌套了一个TextBlock,之后使用ItemsControl控件循环获取显示数据.

  1. <!--资源-->
  2. <StackPanel.Resources>
  3. <!--动态数据模板-->
  4. <DataTemplate x:Key="machineCount">
  5. <!--将当前数据项(通常是一个对象)的默认属性值绑定到 TextBlock 的 Text 属性上-->
  6. <Border Width="15" Background="#3318aabd" Margin="2,0">
  7. <TextBlock Text="{Binding}" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" FontSize="16"></TextBlock>
  8. </Border>
  9. </DataTemplate>
  10. </StackPanel.Resources>

         右边的按钮也是进行了一个资源编写.这里需要注意的是属性绑定,定义的目标对象是按钮,我们要放文字和一个图标进去,文字可以直接绑定按钮的Content属性,这里的图标绑定的是按钮的Tag属性,Tag在原按钮中什么也不代表,类似于官方预留的留给我们自定义的接口.

  1. <Style TargetType="Button" x:Key="Setting_BtnStyle">
  2. <Setter Property="Foreground" Value="#aaa"></Setter>
  3. <!--模板设置触发器\渐变色-->
  4. <Setter Property="Template">
  5. <Setter.Value>
  6. <ControlTemplate TargetType="Button">
  7. <Border Background="Transparent" BorderThickness="1" x:Name="border">
  8. <!--渐变色-->
  9. <Border.BorderBrush>
  10. <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
  11. <GradientStop Color="#22ffffff" Offset="0"></GradientStop>
  12. <GradientStop Color="#77ffffff" Offset="0.5"></GradientStop>
  13. <GradientStop Color="#22ffffff" Offset="1"></GradientStop>
  14. </LinearGradientBrush>
  15. </Border.BorderBrush>
  16. <!--里面放置一个图标 一个文字 Tag类似自定义属性 Content就是对应按钮的Content-->
  17. <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
  18. <TextBlock Text="{TemplateBinding Tag}" FontFamily="../Res/Fonts/#iconfont" Margin="0,2,5,0"></TextBlock>
  19. <TextBlock Text="{TemplateBinding Content}" VerticalAlignment="Center"></TextBlock>
  20. </StackPanel>
  21. </Border>
  22. <!--触发器 放入按钮变颜色-->
  23. <ControlTemplate.Triggers>
  24. <Trigger Property="IsMouseOver" Value="True">
  25. <Setter TargetName="border" Property="Background" Value="#11ffffff"></Setter>
  26. </Trigger>
  27. </ControlTemplate.Triggers>
  28. </ControlTemplate>
  29. </Setter.Value>
  30. </Setter>
  31. </Style>

        运行结果:

        第二行的中间部分也是分为3列,三列里面每一列再分为三行,当然也已使用UniformGrid,因为每部分的大小一致

        这里我们注意到GroupBox 几乎在每个部分都出现了,所以我们可以先把他画出来.

这里我们使用了Polyline画线,Ellipse画圆(点就是半径很小的圆),Path画路径,Polygon 画多边形. <ContentPresenter></ContentPresenter> 一定要加这句,才能显示重新定义的标题

  1. <UserControl.Resources>
  2. <Style TargetType="GroupBox">
  3. <Setter Property="Margin" Value="10,3"></Setter>
  4. <Setter Property="Template">
  5. <Setter.Value>
  6. <ControlTemplate TargetType="GroupBox">
  7. <Grid>
  8. <!--左上角的线条-->
  9. <Polyline Points="0 30,0 10,10 0,30 0" Stroke="#9918aabd" StrokeThickness="1" VerticalAlignment="Top" HorizontalAlignment="Left"></Polyline>
  10. <!--左上 横的点 小圆-->
  11. <Ellipse Width="4" Height="4" HorizontalAlignment="Left" Fill="#9918aabd" VerticalAlignment="Top" Margin="24,-2,0,0"></Ellipse>
  12. <!--左侧的点 小圆-->
  13. <Ellipse Width="4" Height="4" HorizontalAlignment="Left" Fill="#9918aabd" VerticalAlignment="Top" Margin="-2,24,0,0"></Ellipse>
  14. <!--Moveto-->
  15. <Path Data="M0 0,3 3,30 3,33 0,68 0,73 7,78 7,78,10M8 0,25 0" Stroke="#9918aabd" VerticalAlignment="Top" HorizontalAlignment="Right"></Path>
  16. <!--左下角的线条-->
  17. <Polyline Points="0 0,0 15,10 15" Stroke="#9918aabd" StrokeThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Left"></Polyline>
  18. <!--右下角的线-->
  19. <Polyline Points="10 0,0,10" Stroke="#9918aabd" StrokeThickness="1" HorizontalAlignment="Right" VerticalAlignment="Bottom"></Polyline>
  20. <!--右下角的三角形-->
  21. <Polygon Points="0 7,7 7,7 0" Fill="#9918aabd" HorizontalAlignment="Right" VerticalAlignment="Bottom"></Polygon>
  22. <!--上面的线-->
  23. <Border BorderThickness="0,1,0,0" BorderBrush="#9918aabd" VerticalAlignment="top" Margin="30,-0.5,78,0"></Border>
  24. <!--右边的线-->
  25. <Border BorderThickness="0,0,1,0" BorderBrush="#9918aabd" HorizontalAlignment="Right" Margin="0,10"></Border>
  26. <!--下面的线-->
  27. <Border BorderThickness="0,0,0,1" BorderBrush="#9918aabd" VerticalAlignment="Bottom" Margin="10,0"></Border>
  28. <!--左边的线-->
  29. <Border BorderThickness="1,0,0,0" BorderBrush="#9918aabd" HorizontalAlignment="Left" Margin="-0.5,15"></Border>
  30. <!--文字前的装饰-->
  31. <Path Data="M0 0,3 0,5 4,3 8,0 8,3 4" Fill="#9918aabd" Margin="10,13"></Path>
  32. <Path Data="M0 0,3 0,5 4,3 8,0 8,3 4" Fill="#5518aabd" Margin="16,13"></Path>
  33. <TextBlock Text="{TemplateBinding Header}" Foreground="White" FontWeight="Bold" Margin="25,8" HorizontalAlignment="Left" VerticalAlignment="Top"></TextBlock>
  34. <!--显示内容-->
  35. <ContentPresenter></ContentPresenter>
  36. </Grid>
  37. </ControlTemplate>
  38. </Setter.Value>
  39. </Setter>
  40. </Style>
  41. </UserControl.Resources>

        运行结果:

        

        然后进行里面具体内容的绘制,这一部分要创建一个Nodels层来管理数据,里面绘制的柱状图等需要使用到LiveCharts的插件.

        柱状图

  1. <!--定义X数据-->
  2. <lvc:CartesianChart Margin="20,35,20,5">
  3. <lvc:CartesianChart.AxisX>
  4. <lvc:Axis Labels="8:00,9:00,10:00,11:00,12:00,13:00,14:00,15:00,16:00">
  5. <lvc:Axis.Separator>
  6. <lvc:Separator Step="1" StrokeThickness="0"></lvc:Separator>
  7. </lvc:Axis.Separator>
  8. </lvc:Axis>
  9. </lvc:CartesianChart.AxisX>
  10. <!--定义Y的数据-->
  11. <lvc:CartesianChart.Series>
  12. <lvc:ColumnSeries Values="300,400,480,450,380,450,450,330,340" Title="生产计数" MaxColumnWidth="10">
  13. <!--渐变色-->
  14. <lvc:ColumnSeries.Fill>
  15. <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
  16. <GradientStop Color="#ff3fbbe6" Offset="0"></GradientStop>
  17. <GradientStop Color="#ff2bedf1" Offset="1"></GradientStop>
  18. </LinearGradientBrush>
  19. </lvc:ColumnSeries.Fill>
  20. </lvc:ColumnSeries>
  21. <lvc:ColumnSeries Values="15,55,15,40,38,45,56,42,24" Title="不良计数" MaxColumnWidth="10">
  22. <!--渐变色-->
  23. <lvc:ColumnSeries.Fill>
  24. <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
  25. <GradientStop Color="#fffb9a9a" Offset="0"></GradientStop>
  26. <GradientStop Color="#ffff5151" Offset="1"></GradientStop>
  27. </LinearGradientBrush>
  28. </lvc:ColumnSeries.Fill>
  29. </lvc:ColumnSeries>
  30. </lvc:CartesianChart.Series>
  31. <!--Y数据刻度-->
  32. <lvc:CartesianChart.AxisY>
  33. <lvc:Axis MinValue="0" MaxValue="500" >
  34. <lvc:Axis.Separator>
  35. <lvc:Separator Step="100" Stroke="#11ffffff"></lvc:Separator>
  36. </lvc:Axis.Separator>
  37. </lvc:Axis>
  38. </lvc:CartesianChart.AxisY>
  39. </lvc:CartesianChart>

饼形图

  1. <!--饼形图-->
  2. <!--定义数据标签样式-->
  3. <lvc:PieChart InnerRadius="45" Margin="0,40,0,20">
  4. <lvc:PieChart.Resources>
  5. <Style TargetType="lvc:PieSeries">
  6. <Setter Property="DataLabelsTemplate">
  7. <Setter.Value>
  8. <DataTemplate>
  9. <StackPanel Orientation="Horizontal">
  10. <TextBlock Text="{Binding Point.SeriesView.Title}" Margin="0,0,5,0" Foreground="#44ffffff"></TextBlock>
  11. <TextBlock Text="{Binding Point.SeriesView.Values[0]}" Foreground="#44ffffff"></TextBlock>
  12. </StackPanel>
  13. </DataTemplate>
  14. </Setter.Value>
  15. </Setter>
  16. </Style>
  17. </lvc:PieChart.Resources>
  18. <!--定义饼形图数据-->
  19. <lvc:PieChart.Series>
  20. <lvc:PieSeries Values="20" Title="压差" StrokeThickness="0" DataLabels="True" LabelPosition="OutsideSlice"></lvc:PieSeries>
  21. <lvc:PieSeries Values="40" Title="振动" StrokeThickness="0" DataLabels="True" LabelPosition="OutsideSlice"></lvc:PieSeries>
  22. <lvc:PieSeries Values="10" Title="设备温度" StrokeThickness="0" DataLabels="True" LabelPosition="OutsideSlice"></lvc:PieSeries>
  23. <lvc:PieSeries Values="30" Title="光照" StrokeThickness="0" DataLabels="True" LabelPosition="OutsideSlice"></lvc:PieSeries>
  24. </lvc:PieChart.Series>
  25. </lvc:PieChart>

雷达:在界面中定义名字,在后台进行绘制

  1. <!--画布-->
  2. <Canvas x:Name="mainCanvas"></Canvas>
  3. <!--4规则多边形-->
  4. <Polygon x:Name="P1" Stroke="#22ffffff" StrokeThickness="1"></Polygon>
  5. <Polygon x:Name="P2" Stroke="#22ffffff" StrokeThickness="1"></Polygon>
  6. <Polygon x:Name="P3" Stroke="#22ffffff" StrokeThickness="1"></Polygon>
  7. <Polygon x:Name="P4" Stroke="#22ffffff" StrokeThickness="1"></Polygon>
  8. <!--数据多边形-->
  9. <Polygon x:Name="P5" Stroke="Orange" Fill="#550091F0" StrokeThickness="1" ></Polygon>
  1. /// <summary>
  2. /// RaderUC.xaml 的交互逻辑
  3. /// </summary>
  4. public partial class RaderUC : UserControl
  5. {
  6. public RaderUC()
  7. {
  8. InitializeComponent();
  9. SizeChanged += OnSizeChanged;//Alt+Enter
  10. }
  11. /// <summary>
  12. /// 窗体大小发生变化 重新画图
  13. /// </summary>
  14. /// <param name="sender"></param>
  15. /// <param name="e"></param>
  16. private void OnSizeChanged(object sender, SizeChangedEventArgs e)
  17. {
  18. Drag();
  19. }
  20. /// <summary>
  21. /// 数据源。支持数据绑定 依赖属性
  22. /// </summary>
  23. public List<RaderModel> ItemSource
  24. {
  25. get { return (List<RaderModel>)GetValue(ItemSourceProperty); }
  26. set { SetValue(ItemSourceProperty, value); }
  27. }
  28. // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
  29. public static readonly DependencyProperty ItemSourceProperty =
  30. DependencyProperty.Register("ItemSource", typeof(List<RaderModel>), typeof(RaderUC));
  31. /// <summary>
  32. /// 画图方法
  33. /// </summary>
  34. public void Drag()
  35. {
  36. //判断是否有数据
  37. if (ItemSource == null || ItemSource.Count == 0)
  38. {
  39. return;
  40. }
  41. //清楚之前画的
  42. mainCanvas.Children.Clear();
  43. P1.Points.Clear();
  44. P2.Points.Clear();
  45. P3.Points.Clear();
  46. P4.Points.Clear();
  47. P5.Points.Clear();
  48. //调整大小(正方形)
  49. double size = Math.Min(RenderSize.Width, RenderSize.Height);
  50. LayGrid.Height = size;
  51. LayGrid.Width = size;
  52. //半径
  53. double raduis = size / 2;
  54. //步子跨度
  55. double step = 360.0 / ItemSource.Count;
  56. for (int i = 0; i < ItemSource.Count; i++)
  57. {
  58. double x = (raduis - 20) * Math.Cos((step * i - 90) * Math.PI / 180);//x偏移量
  59. double y = (raduis - 20) * Math.Sin((step * i - 90) * Math.PI / 180);//y偏移量
  60. //X Y坐标
  61. P1.Points.Add(new Point(raduis + x, raduis + y));
  62. P2.Points.Add(new Point(raduis + x * 0.75, raduis + y * 0.75));
  63. P3.Points.Add(new Point(raduis + x * 0.5, raduis + y * 0.5));
  64. P4.Points.Add(new Point(raduis + x * 0.25, raduis + y * 0.25));
  65. //数据多边形
  66. P5.Points.Add(new Point(raduis + x * ItemSource[i].Value * 0.01, raduis + y * ItemSource[i].Value * 0.01));
  67. //文字处理
  68. TextBlock txt = new TextBlock();
  69. txt.Width = 60;
  70. txt.FontSize = 10;
  71. txt.TextAlignment = TextAlignment.Center;
  72. txt.Text = ItemSource[i].ItemName;
  73. txt.Foreground = new SolidColorBrush(Color.FromArgb(100, 255, 255, 255));
  74. txt.SetValue(Canvas.LeftProperty, raduis + (raduis - 10) * Math.Cos((step * i - 90) * Math.PI / 180) - 30);//设置左边间距
  75. txt.SetValue(Canvas.TopProperty, raduis + (raduis - 10) * Math.Sin((step * i - 90) * Math.PI / 180) - 7);//设置上边间距
  76. mainCanvas.Children.Add(txt);
  77. }
  78. }
  79. }

        运行结果:

        最后一个部分 整体分为两行两列设计,获取数据方法和上面类似;样式这些可以自己慢慢条.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/257919
推荐阅读
相关标签
  

闽ICP备14008679号