C#生产监控平台(项目笔记)

12 阅读23分钟
1.从阿里图标库引入,icon到项目

下载 图标库下载iconfont.ttf 到项目

image.png

使用: Content="" 是用icon

<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Background="Transparent" shell:WindowChrome.IsHitTestVisibleInChrome="True">
                        <Button Content="&#xe624;" Style="{StaticResource OperateBtnStyle}" Click="BtnMin"></Button>
                        <Button Content="&#xe600;" Style="{StaticResource OperateBtnStyle}"></Button>
                        <Button Content="&#xe609;" Style="{StaticResource OperateBtnStyle}" Background="DarkRed"
                             Click="BtnClose"></Button>
                    </StackPanel>

效果:

image.png

按钮资源

<!-- 资源字典:定义可重用的样式和资源 -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <!-- 定义按钮样式,通过 x:Key 指定键名,供其他控件显式调用 -->
    <Style TargetType="Button" x:Key="OperateBtnStyle">
        
        <!-- 设置按钮的固定宽度为 40 像素 -->
        <Setter Property="Width" Value="40"></Setter>
        
        <!-- 设置背景色为半透明白色(透明度约 93%) 
             格式:#AARRGGBB,AA 为透明度(11 表示 0x11≈6.7% 不透明度) -->
        <Setter Property="Background" Value="#11ffffff"></Setter>
        
        <!-- 设置前景色(字体/图标颜色)为纯白色 -->
        <Setter Property="Foreground" Value="White"></Setter>
        
        <!-- 设置字体来源:使用项目中的图标字体文件
             路径格式:../Resource/Fonts/#字体名称
             #iconfont 表示使用该字体文件中的 "iconfont" 字体家族 -->
        <Setter Property="FontFamily" Value="../Resource/Fonts/#iconfont"></Setter>
        
        <!-- 定义控件的可视化结构(模板) -->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <!-- 使用 Grid 作为根容器,背景绑定到按钮的 Background 属性 -->
                    <Grid Background="{TemplateBinding Background}">
                        
                        <!-- 添加边框元素,用于鼠标悬停时的背景变化 -->
                        <Border x:Name="border">
                            <!-- 内容呈现器:显示按钮的实际内容(如图标或文字)
                                 水平和垂直居中显示 -->
                            <ContentPresenter HorizontalAlignment="Center" 
                                            VerticalAlignment="Center"></ContentPresenter>
                        </Border>
                    </Grid>
                    
                    <!-- 定义模板触发器,根据状态改变控件外观 -->
                    <ControlTemplate.Triggers>
                        
                        <!-- 触发器:当鼠标悬停在按钮上时(IsMouseOver = True) -->
                        <Trigger Property="IsMouseOver" Value="True">
                            <!-- 修改边框的背景色为更亮一点的半透明白色(透明度约 20%) -->
                            <Setter TargetName="border" 
                                    Property="Background" 
                                    Value="#33ffffff"></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>
2.定时器来定期更新时间并触发属性变更事件。

实现方式

  1. 添加定时器 :在 MainWindowVM 和 MonitorUCVM 中都添加了 System.Timers.Timer 定时器,设置为每秒钟触发一次。
  2. 时间更新逻辑 :当定时器触发时,调用 OnPropertyChanged("TimeStr") 方法,通知 UI 界面时间属性已更新。
  3. 资源清理 :添加了析构函数,在 ViewModel 被垃圾回收时停止并释放定时器资源,避免内存泄漏。
// 添加定时器
private Timer _timer;

public MainWindowVM() {
    // 初始化定时器,每秒更新一次时间
    _timer = new Timer(1000);
    _timer.Elapsed += Timer_Elapsed;
    _timer.AutoReset = true;
    _timer.Start();
    
    // 其他初始化代码...
}

private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
    // 触发时间属性变更通知
    OnPropertyChanged("TimeStr");
}

~MainWindowVM()
{
    // 清理定时器
    if (_timer != null)
    {
        _timer.Stop();
        _timer.Dispose();
    }
}
3.使用 字体 FontFamily="../Resource/Fonts/#Digital Display"
<TextBlock Text="{Binding TimeStr}" Foreground="White" FontSize="30" VerticalAlignment="Center" FontFamily="../Resource/Fonts/#Digital Display"/>
4.循环用 ItemsControl(重点)

image.png

/// <summary>
/// 机台总数 - 私有字段,存储实际的机台数量值
/// 初始值设为 "02981" 可能是为了显示效果(保留前导零)
/// </summary>
private string _MachineCount = "02981";

/// <summary>
/// 机台总数 - 公共属性,供数据绑定使用
/// 实现了属性变更通知(INotifyPropertyChanged),当值改变时通知UI更新
/// </summary>
public string MachineCount
{
    get 
    { 
        // 获取当前的机台总数
        return _MachineCount; 
    }
    set
    {
        // 设置新的机台总数
        _MachineCount = value;
        
        // 触发属性变更通知事件
        // 检查是否有订阅事件的处理程序(避免空引用异常)
        if (PropertyChanged != null)
        {
            // 触发PropertyChanged事件,通知UI"MachineCount"属性的值已改变
            // 这样绑定到该属性的UI元素会自动更新显示
            PropertyChanged(this, new PropertyChangedEventArgs("MachineCount"));
        }
    }
}
<!-- 定义水平排列的堆栈面板,位于网格的第1列 -->
<StackPanel Grid.Column="1" 
            Orientation="Horizontal"  <!-- 水平方向排列子元素 -->
            VerticalAlignment="Center"  <!-- 垂直居中 -->
            HorizontalAlignment="Left">  <!-- 水平左对齐 -->
    
    <!-- 定义当前StackPanel内部的资源,供子元素使用 -->
    <StackPanel.Resources>
        <!-- 定义数据模板,用于显示单个数字字符,指定Key为machineCount -->
        <DataTemplate x:Key="machineCount">
            <!-- 每个数字字符的边框容器:宽度15像素,浅蓝色半透明背景,左右外边距2 -->
            <Border Width="15" Background="#3318aabd" Margin="2,0">
                <!-- 文本块:绑定到单个字符,居中显示,白色字体,字号16 -->
                <TextBlock Text="{Binding}" 
                          VerticalAlignment="Center" 
                          HorizontalAlignment="Center" 
                          Foreground="White" 
                          FontSize="16"/>
            </Border>
        </DataTemplate>
    </StackPanel.Resources>
    
    <!-- 显示"机台总数"标签,&#13;表示换行符,所以显示为"机台"在上,"总数"在下 -->
    <TextBlock Text="机台&#13;总数" 
               Foreground="#99ffffff"  <!-- 半透明白色 -->
               Margin="10,0"  <!-- 左右外边距10 -->
               VerticalAlignment="Center" 
               FontSize="10"/>  <!-- 小字号 -->
    
    <!-- 知识点:页面循环用 ItemsControl - 用于显示序列数据 -->
    <!-- 机台总数显示区域:绑定到MachineCount属性,使用上面定义的machineCount模板 -->
    <ItemsControl ItemsSource="{Binding MachineCount}" 
                  ItemTemplate="{StaticResource machineCount}">
        <!-- 指定ItemsControl内部的面板模板 -->
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <!-- 使用水平StackPanel来横向排列各个数字项 -->
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

    <!-- 生产计数标签 -->
    <TextBlock Text="生产计数" 
               Foreground="#99ffffff" 
               VerticalAlignment="Center" 
               FontSize="10" 
               Margin="20,0"></TextBlock>
    
    <!-- 生产计数显示区域:绑定到ProductCount属性,同样使用数字模板 -->
    <ItemsControl ItemsSource="{Binding ProductCount}" 
                  ItemTemplate="{StaticResource machineCount}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

    <!-- 不良计数标签 -->
    <TextBlock Text="不良计数" 
               Foreground="#99ffffff" 
               Margin="20,0" 
               VerticalAlignment="Center" 
               FontSize="10"></TextBlock>
    
    <!-- 不良计数显示区域:绑定到BadCount属性,同样使用数字模板 -->
    <ItemsControl ItemsSource="{Binding BadCount}" 
                  ItemTemplate="{StaticResource machineCount}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

</StackPanel>
5.按钮属性 效果:显示为"图标 + 配置"的按钮,图标来自字体编码

image.png

<!-- 配置按钮 - 使用触发器实现悬停效果和渐变色背景 -->
<Button Style="{StaticResource BtnStyle}"  <!-- 引用静态资源中定义的按钮样式包含触发器效果-->
        HorizontalAlignment="Right"  <!-- 水平右对齐(在父容器中) -->
        Grid.Column="1"  <!-- 位于网格的第1列 -->
        Height="35"  <!-- 按钮高度35像素 -->
        Width="80"  <!-- 按钮宽度80像素 -->
        VerticalAlignment="Center"  <!-- 垂直居中(在父容器中) -->
        Margin="20,0"  <!-- 左右外边距20像素,上下0 -->
        Content="配置"  <!-- 按钮显示的文本内容为"配置" -->
        Tag="&#xe625;"  <!-- 标签属性:存储额外数据,这里存储了一个图标字体编码(Unicode字符) 
                         这个值可以在样式或代码中用于显示图标 -->
        Command="{Binding ShowSettingaCmm,  <!-- 绑定命令:当按钮点击时执行ShowSettingaCmm命令 -->
                 RelativeSource={RelativeSource AncestorType=Window}}">  <!-- 命令来源:向上查找最近的Window对象作为相对源 -->
</Button>
<!-- 资源字典:定义可重用的样式和资源 -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <!-- 定义按钮样式,通过 x:Key="BtnStyle" 供其他控件显式调用 -->
    <Style TargetType="Button" x:Key="BtnStyle">
        
        <!-- 设置按钮前景色(文字颜色)为浅灰色 (#AAAAAA) -->
        <Setter Property="Foreground" Value="#aaa"></Setter>
        
        <!-- 定义按钮的可视化结构模板 -->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    
                    <!-- 边框元素:作为按钮的主体容器 -->
                    <Border BorderThickness="1"  <!-- 边框厚度为1像素 -->
                            Background="Transparent"  <!-- 默认背景透明 -->
                            x:Name="border">  <!-- 命名以便在触发器中引用 -->
                        
                        <!-- 定义边框的渐变色画笔 -->
                        <Border.BorderBrush>
                            <!-- 线性渐变画笔:从左到右的渐变效果 -->
                            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                                <!-- 渐变起点:22%透明度的白色 -->
                                <GradientStop Color="#22ffffff" Offset="0"></GradientStop>
                                <!-- 渐变中点:77%透明度的白色(更亮) -->
                                <GradientStop Color="#77ffffff" Offset="0.5"></GradientStop>
                                <!-- 渐变终点:22%透明度的白色 -->
                                <GradientStop Color="#22ffffff" Offset="1"></GradientStop>
                            </LinearGradientBrush>
                        </Border.BorderBrush>
                        
                        <!-- 堆栈面板:水平排列按钮内容 -->
                        <StackPanel Orientation="Horizontal"  <!-- 水平方向排列 -->
                                    HorizontalAlignment="Center"  <!-- 水平居中 -->
                                    VerticalAlignment="Center">  <!-- 垂直居中 -->
                            
                            <!-- 图标文本块:绑定到按钮的Tag属性,用于显示图标字体 -->
                            <TextBlock Text="{TemplateBinding Tag}"  <!-- 绑定Tag属性值 -->
                                      FontFamily="../Resource/Fonts/#iconfont"  <!-- 使用图标字体文件 -->
                                      Margin="0,2,5,0"></TextBlock>  <!-- 上边距2,右边距5 -->
                            
                            <!-- 内容文本块:绑定到按钮的Content属性,显示普通文本 -->
                            <TextBlock Text="{TemplateBinding Content}"  <!-- 绑定Content属性值 -->
                                      VerticalAlignment="Center"></TextBlock>  <!-- 垂直居中 -->
                        </StackPanel>
                    </Border>
                    
                    <!-- 定义模板触发器,根据按钮状态改变外观 -->
                    <ControlTemplate.Triggers>
                        
                        <!-- 触发器:鼠标悬停在按钮上时 -->
                        <Trigger Property="IsMouseOver" Value="True">
                            <!-- 设置边框的背景为半透明白色(约6.7%不透明度) -->
                            <Setter TargetName="border" 
                                    Property="Background" 
                                    Value="#11ffffff"></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
</ResourceDictionary>

样式特性说明:

1. 视觉效果

  • 边框渐变:左右两侧较淡(#22ffffff),中间较亮(#77ffffff),形成光泽感
  • 背景透明:默认背景透明,仅显示边框
  • 悬停效果:鼠标悬停时出现半透明背景(#11ffffff),提供交互反馈

2. 内容结构

  • 图标 + 文本组合:通过两个TextBlock实现

    • 左侧:图标字体(绑定到Tag属性)
    • 右侧:文字标签(绑定到Content属性)
  • 水平居中排列:图标和文字整体在按钮内居中

3. 使用方式示例

<Button Style="{StaticResource BtnStyle}" 
        Content="配置" 
        Tag="&#xe625;" 
        Command="{Binding ConfigCommand}"/>
6.用线条绘制边框(重点)

image.png

    <!-- 定义 GroupBox 的全局样式,将应用于当前 UserControl 中所有的 GroupBox 控件 -->
    <Style TargetType="GroupBox">
        
        <!-- 设置 GroupBox 的外边距:左右10像素,上下3像素 -->
        <Setter Property="Margin" Value="10,3"></Setter>
        
        <!-- 重写 GroupBox 的控件模板,实现自定义外观 -->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="GroupBox">
                    
                    <!-- 使用 Grid 作为根容器,便于多个图形元素的叠加 -->
                    <Grid>
                        
                        <!-- ========== 知识点:形状(Shape) ========== -->
                        
                        <!-- 左上角的L形拐角线条 -->
                        <Polyline Points="0 30,0 10,10 0,30 0" 
                                  Stroke="#9918aabd"  <!-- 半透明蓝色 (#18aabd, 透明度60%) -->
                                  StrokeThickness="1" 
                                  VerticalAlignment="Top" 
                                  HorizontalAlignment="Left"></Polyline>
                        
                        <!-- 左上角横线上的装饰点 - 小圆 -->
                        <Ellipse Width="4" Height="4" 
                                 HorizontalAlignment="Left" 
                                 Fill="#9918aabd"  <!-- 与线条相同的颜色 -->
                                 VerticalAlignment="Top" 
                                 Margin="24,-2,0,0"></Ellipse>  <!-- 向右偏移24,向上偏移2 -->
                        
                        <!-- 左侧竖线上的装饰点 - 小圆 -->
                        <Ellipse Width="4" Height="4" 
                                 HorizontalAlignment="Left" 
                                 Fill="#9918aabd" 
                                 VerticalAlignment="Top" 
                                 Margin="-2,24,0,0"></Ellipse>  <!-- 向左偏移2,向下偏移24 -->

                        <!-- 顶部右上角的路径装饰(Moveto表示路径起点) 
                             M0 0: 起点(0,0)
                             3 3: 画到(3,3)
                             30 3: 画到(30,3)
                             33 0: 画到(33,0)
                             68 0: 画到(68,0)
                             73 7: 画到(73,7)
                             78 7: 画到(78,7)
                             78,10: 画到(78,10)
                             M8 0,25 0: 另一条路径从(8,0)到(25,0) -->
                        <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>

                        <!-- 左下角的水平短线条 -->
                        <Polyline Points="0 0,0 15,10 15" 
                                  Stroke="#9918aabd" 
                                  StrokeThickness="1" 
                                  VerticalAlignment="Bottom"  <!-- 底部对齐 -->
                                  HorizontalAlignment="Left"></Polyline>  <!-- 左对齐 -->

                        <!-- 右下角的折线(小拐角) -->
                        <Polyline Points="10 0,0,10" 
                                  Stroke="#9918aabd" 
                                  StrokeThickness="1" 
                                  HorizontalAlignment="Right"  <!-- 右对齐 -->
                                  VerticalAlignment="Bottom"></Polyline>  <!-- 底部对齐 -->

                        <!-- 右下角的实心三角形装饰 -->
                        <Polygon Points="0 7,7 7,7 0" 
                                 Fill="#9918aabd" 
                                 HorizontalAlignment="Right" 
                                 VerticalAlignment="Bottom"></Polygon>

                        <!-- 顶部的横线边框(从左上装饰延伸到右上装饰) -->
                        <Border BorderThickness="0,1,0,0"  <!-- 仅显示顶部边框 -->
                                BorderBrush="#9918aabd" 
                                VerticalAlignment="Top" 
                                Margin="30,-0.5,78,0"></Border>  <!-- 左边距30,右边距78,向上微调0.5 -->

                        <!-- 右侧的竖线边框 -->
                        <Border BorderThickness="0,0,1,0"  <!-- 仅显示右侧边框 -->
                                BorderBrush="#9918aabd" 
                                HorizontalAlignment="Right" 
                                Margin="0,10"></Border>  <!-- 上下边距10 -->

                        <!-- 底部的横线边框 -->
                        <Border BorderThickness="0,0,0,1"  <!-- 仅显示底部边框 -->
                                BorderBrush="#9918aabd" 
                                VerticalAlignment="Bottom" 
                                Margin="10,0"></Border>  <!-- 左右边距10 -->

                        <!-- 左侧的竖线边框 -->
                        <Border BorderThickness="1,0,0,0"  <!-- 仅显示左侧边框 -->
                                BorderBrush="#9918aabd" 
                                HorizontalAlignment="Left" 
                                Margin="-0.5,15"></Border>  <!-- 向左微调0.5,上下边距15 -->

                        <!-- 标题前的第一个装饰图标(六边形/菱形) -->
                        <Path Data="M0 0,3 0,5 4,3 8,0 8,3 4"  <!-- 绘制六边形路径 -->
                              Fill="#9918aabd"  <!-- 半透明蓝色 -->
                              Margin="10,13"></Path>  <!-- 位置偏移 -->
                        
                        <!-- 标题前的第二个装饰图标(相同形状,较浅的透明度,产生叠影效果) -->
                        <Path Data="M0 0,3 0,5 4,3 8,0 8,3 4" 
                              Fill="#5518aabd"  <!-- 透明度约33%,更淡 -->
                              Margin="16,13"></Path>  <!-- 向右偏移更多,与第一个错开 -->
                        
                        <!-- 标题文本:绑定到 GroupBox 的 Header 属性 -->
                        <TextBlock Text="{TemplateBinding Header}" 
                                   Foreground="White" 
                                   FontWeight="Bold" 
                                   Margin="25,8"  <!-- 左边距25,上边距8 -->
                                   HorizontalAlignment="Left" 
                                   VerticalAlignment="Top"></TextBlock>
                        
                        <!-- 内容呈现器:显示 GroupBox 内部的实际内容 -->
                        <ContentPresenter></ContentPresenter>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>
<!-- 环境信息分组框 -->
<GroupBox Header="环境">  <!-- 分组框标题为"环境",使用上面定义的科技感GroupBox样式 -->
    
    <!-- ItemsControl:用于循环显示环境参数列表 -->
    <ItemsControl ItemsSource="{Binding EnviromentList}"  <!-- 绑定到ViewModel中的环境数据集合 -->
                  VerticalContentAlignment="Center"  <!-- 内容垂直居中 -->
                  Margin="0,10">  <!-- 上下外边距10像素 -->
        
        <!-- 定义ItemsControl内部的面板布局 -->
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <!-- UniformGrid:均匀网格布局,所有单元格大小一致 -->
                <UniformGrid Columns="4"></UniformGrid>  <!-- 固定为4列,行数自动适应 -->
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        
        <!-- 定义每个数据项的显示模板 -->
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!-- 垂直堆栈面板:每个环境参数的容器 -->
                <StackPanel HorizontalAlignment="Center"  <!-- 水平居中 -->
                            VerticalAlignment="Center"    <!-- 垂直居中 -->
                            Margin="0,5">                 <!-- 上下边距5像素 -->
                    
                    <!-- 环境参数值:大号字体显示 -->
                    <TextBlock Text="{Binding EnItemValue}"  <!-- 绑定到数据项的数值属性 -->
                               FontSize="16"                  <!-- 字号16,突出显示 -->
                               Foreground="#ff2bedf1"         <!-- 亮青色 (#2bedf1) -->
                               Margin="0,5"/>                 <!-- 上下边距5像素 -->
                    
                    <!-- 环境参数名称:小号字体显示 -->
                    <TextBlock Text="{Binding EnItemName}"  <!-- 绑定到数据项的名称属性 -->
                               FontSize="10"                  <!-- 字号10,辅助信息 -->
                               Foreground="#aaffffff"         <!-- 半透明白色 (约67%不透明度) -->
                               Margin="0,5"/>                 <!-- 上下边距5像素 -->
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</GroupBox>

1. 数据结构

假设 EnviromentList 集合中包含多个环境参数对象,每个对象有:

namespace ProductMonitor.Models
{
    // 环境信息
    public class EnviromentModel
    {
        // 环境名称
        public string EnItemName { get; set; }

        // 环境项的值
        public int EnItemValue { get; set; }
    }
}
// 私有字段:存储环境监控数据列表
private List<EnviromentModel> _EnviromentList;

/// <summary>
/// 环境监控数据集合
/// 绑定到UI上的ItemsControl,用于显示温度、湿度、气压等环境参数
/// </summary>
public List<EnviromentModel> EnviromentList
{
    get 
    { 
        // 返回当前的环境数据列表
        return _EnviromentList; 
    }
    set
    {
        // 设置新的环境数据列表
        _EnviromentList = value;
        
        // 触发属性变更通知事件
        // 检查是否有订阅事件的处理程序(避免空引用异常)
        if (PropertyChanged != null)
        {
            // 触发PropertyChanged事件,通知UI"EnviromentList"属性的值已改变
            // 这样绑定到该属性的UI元素(如ItemsControl)会自动刷新显示
            PropertyChanged(this, new PropertyChangedEventArgs("EnviromentList"));
        }
    }
}
 #region 初始化环境监控数据
            EnviromentList = new List<EnviromentModel>();

            EnviromentList.Add(new EnviromentModel { EnItemName = "光照(Lux)", EnItemValue = 123 });
            EnviromentList.Add(new EnviromentModel { EnItemName = "噪音(db)", EnItemValue = 55 });
            EnviromentList.Add(new EnviromentModel { EnItemName = "温度(℃)", EnItemValue = 80 });
            EnviromentList.Add(new EnviromentModel { EnItemName = "湿度(%)", EnItemValue = 43 });
            EnviromentList.Add(new EnviromentModel { EnItemName = "PM2.5(m³)", EnItemValue = 20 });
            EnviromentList.Add(new EnviromentModel { EnItemName = "硫化氢(PPM)", EnItemValue = 15 });
            EnviromentList.Add(new EnviromentModel { EnItemName = "氮气(PPM)", EnItemValue = 18 });
            #endregion
7.引用/使用数据可视化 LiveCharts LiveCharts.Wpf

image.png

<!-- 产能分组框:显示生产数据的柱状图 -->
<GroupBox Header="产能">
    <!-- 使用Grid容器,方便图表和图例的叠加布局 -->
    <Grid>
        
        <!-- ========== LiveCharts 柱状图 ========== -->
        <!-- 引入lvc命名空间(xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf")的图表控件 -->
        <lvc:CartesianChart Margin="20,35,20,5">  <!-- 上边距35为图例留出空间,左右边距20 -->
            
            <!-- ===== X轴定义(时间轴) ===== -->
            <lvc:CartesianChart.AxisX>
                <lvc:Axis Labels="8:00,9:00,10:00,11:00,12:00,13:00,14:00,15:00,16:00">  <!-- 9个时间点标签 -->
                    <lvc:Axis.Separator>
                        <!-- 分隔线设置:Step="1"表示每个标签之间显示分隔线,StrokeThickness="0"隐藏线条 -->
                        <lvc:Separator Step="1" StrokeThickness="0"/>
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisX>

            <!-- ===== 数据系列定义(Y轴数据) ===== -->
            <lvc:CartesianChart.Series>
                
                <!-- 生产计数柱状图系列(蓝色系) -->
                <lvc:ColumnSeries Values="300,400,480,450,380,450,450,330,340"  <!-- 9个时间点的生产数量 -->
                                  Title="生产计数"    <!-- 系列名称,用于图例绑定 -->
                                  MaxColumnWidth="10"> <!-- 柱状图最大宽度10像素,防止柱子过宽 -->
                    
                    <!-- 生产计数的渐变色填充:从上到下渐变 -->
                    <lvc:ColumnSeries.Fill>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">  <!-- 垂直渐变(从上到下) -->
                            <GradientStop Color="#ff3fbbe6" Offset="0"></GradientStop>   <!-- 起点:亮蓝色(完全不透明) -->
                            <GradientStop Color="#ff2bedf1" Offset="1"></GradientStop>   <!-- 终点:青色(完全不透明) -->
                        </LinearGradientBrush>
                    </lvc:ColumnSeries.Fill>
                </lvc:ColumnSeries>

                <!-- 不良计数柱状图系列(红色系) -->
                <lvc:ColumnSeries Values="15,55,15,40,38,45,56,42,24"  <!-- 9个时间点的不良品数量 -->
                                  Title="不良计数"    <!-- 系列名称 -->
                                  MaxColumnWidth="10"> <!-- 相同宽度,保持视觉一致 -->
                    
                    <!-- 不良计数的渐变色填充 -->
                    <lvc:ColumnSeries.Fill>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">  <!-- 垂直渐变 -->
                            <GradientStop Color="#fffb9a9a" Offset="0"></GradientStop>   <!-- 起点:浅红色 -->
                            <GradientStop Color="#ffff5151" Offset="1"></GradientStop>   <!-- 终点:亮红色 -->
                        </LinearGradientBrush>
                    </lvc:ColumnSeries.Fill>
                </lvc:ColumnSeries>
            </lvc:CartesianChart.Series>

            <!-- ===== Y轴定义(数值轴) ===== -->
            <lvc:CartesianChart.AxisY>
                <lvc:Axis MinValue="0" MaxValue="500" >  <!-- Y轴范围:0-500,适应生产计数最大值480 -->
                    <lvc:Axis.Separator>
                        <!-- Y轴分隔线:每隔100显示一条水平线,半透明白色 -->
                        <lvc:Separator Step="100" Stroke="#11ffffff"></lvc:Separator>  <!-- 约6.7%不透明度 -->
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisY>
        </lvc:CartesianChart>

        <!-- ===== 图例(右上角) ===== -->
        <StackPanel Orientation="Horizontal"  <!-- 水平排列 -->
                    HorizontalAlignment="Right"  <!-- 右对齐 -->
                    VerticalAlignment="Top"      <!-- 顶部对齐 -->
                    Margin="10">                  <!-- 边距10像素 -->
            
            <!-- 生产计数图例项 -->
            <Border Height="6" Width="6"         <!-- 小色块6x6像素 -->
                    Background="#ff2bedf1"        <!-- 与生产计数渐变的终点色一致 -->
                    Margin="5,0"></Border>        <!-- 右边距5 -->
            <TextBlock Text="生产计数"            <!-- 图例文字 -->
                       FontSize="10" 
                       Foreground="#44ffffff"></TextBlock>  <!-- 半透明白色(约27%不透明度) -->

            <!-- 不良计数图例项 -->
            <Border Height="6" Width="6" 
                    Background="#ffff5151"        <!-- 与不良计数渐变的终点色一致 -->
                    Margin="5,0"></Border>
            <TextBlock Text="不良计数" 
                       FontSize="10" 
                       Foreground="#44ffffff"></TextBlock>
        </StackPanel>

    </Grid>
</GroupBox>

image.png

<!-- 质量分组框:显示各机台的不良率趋势 -->
<GroupBox Header="质量">
    <!-- 使用Grid容器,便于后续可能添加其他元素(如图例、标注等) -->
    <Grid>
        
        <!-- ========== LiveCharts 折线图 ========== -->
        <!-- 引入lvc命名空间的图表控件,边距设置为上35为标题留出空间 -->
        <lvc:CartesianChart Margin="20,35,20,5">  <!-- 左边距20,上边距35,右边距20,下边距5 -->
            
            <!-- ===== X轴定义(机台编号) ===== -->
            <lvc:CartesianChart.AxisX>
                <!-- Labels属性设置X轴标签:1#到6#,代表6个不同的机台/工位 -->
                <lvc:Axis Labels="1#,2#,3#,4#,5#,6#">
                    <lvc:Axis.Separator>
                        <!-- 分隔线设置:Step="1"表示在每个标签之间显示分隔线 -->
                        <!-- StrokeThickness="0"隐藏分隔线,保持图表简洁 -->
                        <lvc:Separator Step="1" StrokeThickness="0"></lvc:Separator>
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisX>

            <!-- ===== 数据系列定义(不良率数据) ===== -->
            <lvc:CartesianChart.Series>
                
                <!-- 折线图系列:显示各机台的不良品数量/不良率 -->
                <lvc:LineSeries Values="8,2,7,6,4,14"  <!-- 6个机台对应的不良数据 -->
                                PointGeometrySize="0"   <!-- 数据点大小为0,即不显示数据点标记 -->
                                Stroke="#ff2bedf1">     <!-- 折线颜色:亮青色(完全不透明) -->
                    
                    <!-- 折线图下方区域填充(渐变色) -->
                    <lvc:LineSeries.Fill>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">  <!-- 垂直渐变(从上到下) -->
                            <!-- 起点:半透明青色(约33%不透明度) -->
                            <GradientStop Color="#552bedf1" Offset="0"></GradientStop>
                            <!-- 终点:完全透明,形成从有到无的渐变效果 -->
                            <GradientStop Color="Transparent" Offset="1"></GradientStop>
                        </LinearGradientBrush>
                    </lvc:LineSeries.Fill>
                </lvc:LineSeries>
            </lvc:CartesianChart.Series>

            <!-- ===== Y轴定义(不良数值范围) ===== -->
            <lvc:CartesianChart.AxisY>
                <!-- Y轴范围:最小值0,最大值15,适应数据最大值14 -->
                <lvc:Axis MinValue="0" MaxValue="15" >
                    <lvc:Axis.Separator>
                        <!-- Y轴分隔线:每隔5显示一条水平网格线 -->
                        <lvc:Separator Step="5" Stroke="#11ffffff"></lvc:Separator>  <!-- 半透明白色(约6.7%不透明度) -->
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisY>
        </lvc:CartesianChart>
    </Grid>
</GroupBox>

image.png

<!-- 第三行:数据异常报警比例分组框 -->
<GroupBox Grid.Row="2"           <!-- 位于网格的第3行行索引为2-->
          Header="数据异常报警比例"  <!-- 分组框标题 -->
          Margin="0,5">           <!-- 上下外边距5像素 -->
    
    <!-- ========== 饼形图:显示各类异常报警的占比 ========== -->
    <!-- 使用LiveCharts的PieChart控件,InnerRadius="45"创建环形图效果(类似甜甜圈图) -->
    <lvc:PieChart InnerRadius="45"  <!-- 内圆半径45值越大环越粗45表示中等粗细的环形 -->
                  Margin="0,40,0,20">  <!-- 上边距40为标题留空间,下边距20 -->
        
        <!-- ===== 定义饼图系列的数据标签样式(全局应用) ===== -->
        <lvc:PieChart.Resources>
            <!-- 针对所有PieSeries设置统一的样式 -->
            <Style TargetType="lvc:PieSeries">
                <!-- 设置数据标签的模板(决定标签显示的内容和格式) -->
                <Setter Property="DataLabelsTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <!-- 水平排列的堆栈面板:显示"类别名称 + 数值" -->
                            <StackPanel Orientation="Horizontal">
                                <!-- 绑定到当前数据点的系列标题(如"压差"、"振动"等) -->
                                <TextBlock Text="{Binding Point.SeriesView.Title}" 
                                          Margin="0,0,5,0"  <!-- 右边距5像素 -->
                                          Foreground="#44ffffff"></TextBlock>  <!-- 半透明白色(约27%不透明度) -->
                                
                                <!-- 绑定到当前数据点的数值(第一个值,饼图通常只有一个值) -->
                                <TextBlock Text="{Binding Point.SeriesView.Values[0]}" 
                                          Foreground="#44ffffff"></TextBlock>  <!-- 同样半透明白色 -->
                            </StackPanel>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </lvc:PieChart.Resources>
        
        <!-- ===== 定义饼图数据系列(4个异常类别) ===== -->
        <lvc:PieChart.Series>
            
            <!-- 压差异常:占比20%(数值20) -->
            <lvc:PieSeries Values="20"           <!-- 数据值决定扇形大小 -->
                          Title="压差"            <!-- 系列标题,显示在标签和图例中 -->
                          StrokeThickness="0"    <!-- 边框厚度为0,不显示扇形之间的分隔线 -->
                          DataLabels="True"      <!-- 显示数据标签 -->
                          LabelPosition="OutsideSlice"></lvc:PieSeries>  <!-- 标签显示在扇形外部 -->
            
            <!-- 振动异常:占比40%(最大占比) -->
            <lvc:PieSeries Values="40" 
                          Title="振动" 
                          StrokeThickness="0" 
                          DataLabels="True" 
                          LabelPosition="OutsideSlice"></lvc:PieSeries>
            
            <!-- 设备温度异常:占比10%(最小占比) -->
            <lvc:PieSeries Values="10" 
                          Title="设备温度" 
                          StrokeThickness="0" 
                          DataLabels="True" 
                          LabelPosition="OutsideSlice"></lvc:PieSeries>
            
            <!-- 光照异常:占比30% -->
            <lvc:PieSeries Values="30" 
                          Title="光照" 
                          StrokeThickness="0" 
                          DataLabels="True" 
                          LabelPosition="OutsideSlice"></lvc:PieSeries>
        </lvc:PieChart.Series>
    </lvc:PieChart>
</GroupBox>

视觉设计特点:

  1. 环形图(甜甜圈图)

    • InnerRadius="45":创建环形效果,中间空心
    • 比普通饼图更现代,可以在中心添加额外信息(如总数)
  2. 标签设计

    • 标签位置:扇形外部(LabelPosition="OutsideSlice"),避免遮挡
    • 标签内容:显示"类别名称 + 数值"
    • 标签样式:半透明文字,不喧宾夺主
  3. 简洁边框

    • StrokeThickness="0":取消扇形之间的分隔线,使颜色过渡更自然
8.数据循环显示

image.png

<!-- 位于网格的第2行(行索引为1)的报警记录区域 -->
<Grid Grid.Row="1">
    <!-- 定义Grid的行布局:两行 -->
    <Grid.RowDefinitions>
        <RowDefinition Height="30"></RowDefinition>  <!-- 第一行固定高度30像素,用于显示标题 -->
        <RowDefinition></RowDefinition>               <!-- 第二行自适应填充剩余空间,用于显示报警列表 -->
    </Grid.RowDefinitions>
    
    <!-- ===== 第一行:标题栏 ===== -->
    <StackPanel Orientation="Horizontal"  <!-- 水平排列 -->
                VerticalAlignment="Center"  <!-- 垂直居中 -->
                HorizontalAlignment="Left">  <!-- 水平左对齐 -->
        
        <!-- 报警图标:使用图标字体显示报警符号 -->
        <TextBlock Text="&#xe68d;"  <!-- 图标字体编码对应一个报警/铃铛图标 -->
                   FontFamily="../Resource/Fonts/#iconfont"  <!-- 引用图标字体文件 -->
                   Foreground="#99ffffff"  <!-- 半透明白色(约60%不透明度) -->
                   Margin="5,0"></TextBlock>  <!-- 左右边距5像素 -->
        
        <!-- 标题文字:"报警记录" -->
        <TextBlock Text="报警记录" 
                   Foreground="#99ffffff"></TextBlock>  <!-- 相同半透明白色 -->
    </StackPanel>
    
    <!-- ===== 第二行:报警列表 ===== -->
    <!-- 使用ItemsControl循环显示报警记录,绑定到AlarmList集合 -->
    <ItemsControl Grid.Row="1"  <!-- 位于Grid的第二行 -->
                  ItemsSource="{Binding AlarmList}"  <!-- 绑定到ViewModel中的报警数据集合 -->
                  Margin="5,0">  <!-- 左右边距5像素 -->
        
        <!-- 定义每条报警记录的显示模板 -->
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!-- 每条报警记录使用Grid布局,固定高度23像素 -->
                <Grid Height="23">
                    <!-- 定义5列表格 -->
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="20"></ColumnDefinition>   <!-- 第1列:红点报警图标,宽度20 -->
                        <ColumnDefinition Width="30"></ColumnDefinition>   <!-- 第2列:报警编号,宽度30 -->
                        <ColumnDefinition Width="150"></ColumnDefinition>  <!-- 第3列:报警信息,宽度150 -->
                        <ColumnDefinition></ColumnDefinition>              <!-- 第4列:报警时间,自适应宽度 -->
                        <ColumnDefinition></ColumnDefinition>              <!-- 第5列:报警时长,自适应宽度 -->
                    </Grid.ColumnDefinitions>
                    
                    <!-- 知识点:红点报警 - 用红色圆点表示报警状态 -->
                    <Border Background="IndianRed"  <!-- 印第安红色背景 -->
                            Height="6" Width="6"     <!-- 6x6像素的正方形 -->
                            CornerRadius="3"         <!-- 圆角半径3,形成正圆形 -->
                            VerticalAlignment="Center" 
                            HorizontalAlignment="Center"></Border>  <!-- 居中显示 -->
                    
                    <!-- 报警编号:绑定到Num属性 -->
                    <TextBlock Text="{Binding Num}" 
                               Grid.Column="1" 
                               VerticalAlignment="Center" 
                               HorizontalAlignment="Center" 
                               Foreground="#992bedf1"></TextBlock>  <!-- 半透明青色(约60%不透明度) -->
                    
                    <!-- 报警信息内容:绑定到Msg属性 -->
                    <TextBlock Text="{Binding Msg}" 
                               Grid.Column="2" 
                               VerticalAlignment="Center"  
                               Foreground="#992bedf1"></TextBlock>
                    
                    <!-- 报警发生时间:绑定到Time属性 -->
                    <TextBlock Text="{Binding Time}" 
                               Grid.Column="3" 
                               VerticalAlignment="Center"  
                               Foreground="#992bedf1"></TextBlock>
                    
                    <!-- 报警持续时间:绑定到Duration属性,并格式化显示 -->
                    <TextBlock Text="{Binding Duration,StringFormat=时长{0}秒}"  <!-- 格式化为"时长X秒" -->
                               Grid.Column="4" 
                               VerticalAlignment="Center" 
                               HorizontalAlignment="Center" 
                               Foreground="#992bedf1"></TextBlock>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

数据结构说明:

1. AlarmList 集合中的数据模型

namespace ProductMonitor.Models
{
    /// <summary>
    /// 报警数据模型
    /// </summary>
    internal class AlarmModel
    {
        /// <summary>
        /// 编号
        /// </summary>
        public string Num { get; set; }

        /// <summary>
        /// 报警信息
        /// </summary>
        public string Msg { get; set; }

        /// <summary>
        /// 报警时间
        /// </summary>
        public string Time { get; set; }

        /// <summary>
        /// 报警时长 单位:秒
        /// </summary>
        public int Duration { get; set; }
    }
}
 #region 报警属性

        /// <summary>
        /// 报警集合
        /// </summary>
        private List<AlarmModel> _AlarmList;

        /// <summary>
        /// 报警集合
        /// </summary>
        public List<AlarmModel> AlarmList
        {
            get { return _AlarmList; }
            set
            {
                _AlarmList = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("AlarmList"));
                }
            }
        }
        #endregion
 #region 初始化报警列表

            AlarmList = new List<AlarmModel>();
            AlarmList.Add(new AlarmModel { Num = "01", Msg = "设备温度过高", Time = "2023-11-23 18:34:56", Duration = 7 });
            AlarmList.Add(new AlarmModel { Num = "02", Msg = "车间温度过高", Time = "2023-12-08 20:40:59", Duration = 10 });
            AlarmList.Add(new AlarmModel { Num = "03", Msg = "设备转速过快", Time = "2024-01-05 12:24:34", Duration = 12 });
            AlarmList.Add(new AlarmModel { Num = "04", Msg = "设备气压偏低", Time = "2024-02-04 19:58:00", Duration = 90 });
            #endregion
9.缺岗进度条:宽度绑定到ShowWidth属性,动态显示缺岗比例

image.png

<!-- 人力分组框:显示在职人数和缺岗统计   -->
<GroupBox Header="人力">
    <!-- 使用Grid作为主容器,分为两列布局 -->
    <Grid>
        <!-- 定义两列:左侧列自适应,右侧列宽度为左侧的1.8倍 -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>           <!-- 第1列:自适应宽度,显示在职人数 -->
            <ColumnDefinition Width="1.8*"></ColumnDefinition> <!-- 第2列:宽度为第1列的1.8倍,显示缺岗统计 -->
        </Grid.ColumnDefinitions>
        
        <!-- ===== 左侧:在职人数统计 ===== -->
        <StackPanel VerticalAlignment="Center"  <!-- 垂直居中 -->
                    Margin="0,20,0,0">          <!-- 上边距20像素 -->
            
            <!-- 在职人数大号数字 -->
            <TextBlock Text="870" 
                       HorizontalAlignment="Center" 
                       Foreground="#99ffffff"  <!-- 半透明白色约60%不透明度-->
                       FontSize="25"></TextBlock>  <!-- 大字号突出显示 -->
            
            <!-- 状态说明文字 -->
            <TextBlock Text="在职在岗" 
                       HorizontalAlignment="Center" 
                       Foreground="#55ffffff"  <!-- 更透明的白色约33%不透明度-->
                       FontSize="12"></TextBlock>  <!-- 小字号辅助信息 -->
        </StackPanel>

        <!-- ===== 右侧:缺岗统计列表 ===== -->
        <Grid Grid.Column="1">  <!-- 位于第2列 -->
            <!-- 定义两行布局 -->
            <Grid.RowDefinitions>
                <RowDefinition Height="30"></RowDefinition>  <!-- 第一行固定高度30,显示标题 -->
                <RowDefinition></RowDefinition>               <!-- 第二行自适应,显示缺岗人员列表 -->
            </Grid.RowDefinitions>
            
            <!-- 缺岗统计标题 -->
            <TextBlock Text="缺岗统计" 
                       VerticalAlignment="Center" 
                       Foreground="#18aabd"></TextBlock>  <!-- 亮蓝色,与主题色一致 -->
            
            <!-- 缺岗人员列表:绑定到StuffOutWorkList集合 -->
            <ItemsControl Grid.Row="1" 
                          ItemsSource="{Binding StuffOutWorkList}">
                
                <!-- 定义每条缺岗记录的显示模板 -->
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <!-- 每条记录使用Grid布局,固定高度20像素 -->
                        <Grid Height="20" Width="auto">
                            <!-- 定义4列表格 -->
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="10"></ColumnDefinition>  <!-- 第1列:状态圆点,宽度10 -->
                                <ColumnDefinition Width="50"></ColumnDefinition>  <!-- 第2列:姓名,宽度50 -->
                                <ColumnDefinition Width="40"></ColumnDefinition>  <!-- 第3列:职位,宽度40 -->
                                <ColumnDefinition></ColumnDefinition>              <!-- 第4列:缺岗进度条,自适应 -->
                            </Grid.ColumnDefinitions>
                            
                            <!-- 缺岗状态圆点(橙色表示缺岗) -->
                            <Border Width="5" Height="5" 
                                    CornerRadius="5"  <!-- 圆角半径5形成正圆 -->
                                    Background="Orange"></Border>  <!-- 橙色背景 -->

                            <!-- 缺岗人员姓名 -->
                            <TextBlock Text="{Binding StuffName}" 
                                       Grid.Column="1" 
                                       Foreground="#99ffffff" 
                                       HorizontalAlignment="Center" 
                                       VerticalAlignment="Center"></TextBlock>

                            <!-- 缺岗人员职位 -->
                            <TextBlock Text="{Binding Position}" 
                                       Grid.Column="2" 
                                       Foreground="#99ffffff" 
                                       HorizontalAlignment="Center" 
                                       VerticalAlignment="Center"></TextBlock>

                            <!-- 缺岗统计进度条区域 -->
                            <StackPanel Grid.Column="3" 
                                        Orientation="Horizontal">  <!-- 水平排列 -->
                                
                                <!-- 缺岗进度条:宽度绑定到ShowWidth属性,动态显示缺岗比例 -->
                                <Border Background="#aa2bedf1"  <!-- 半透明青色约67%不透明度-->
                                        Height="3"               <!-- 高度3像素的细条 -->
                                        Width="{Binding ShowWidth}"  <!-- 宽度绑定到数据模型 -->
                                        Margin="5,0"></Border>   <!-- 左右边距5像素 -->
                                
                                <!-- 缺岗次数/天数 -->
                                <TextBlock Text="{Binding OutWorkCount}" 
                                           FontSize="9" 
                                           Foreground="#99ffffff" 
                                           VerticalAlignment="Center"></TextBlock>
                            </StackPanel>
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Grid>
    </Grid>
</GroupBox>

数据结构说明:

1. StuffOutWorkList 集合中的数据模型

/// <summary>
    /// 缺岗数据模型
    /// </summary>
    internal class StuffOutWorkModel
    {
        /// <summary>
        /// 员工姓名 
        /// </summary>
        public string StuffName { get; set; }

        /// <summary>
        /// 职位
        /// </summary>
        public string Position { get; set; }

        /// <summary>
        /// 缺岗次数
        /// </summary>
        public int OutWorkCount { get; set; }

        /// <summary>
        /// 界面显示宽度
        /// </summary>
        public int ShowWidth
        {
            get
            {
                return OutWorkCount * 70 / 100;
            }
        }
    }
#region 缺岗员工属性

        /// <summary>
        /// 缺岗员工
        /// </summary>
        private List<StuffOutWorkModel> _StuffOutWorkList;

        /// <summary>
        /// 缺岗员工
        /// </summary>
        public List<StuffOutWorkModel> StuffOutWorkList
        {
            get { return _StuffOutWorkList; }
            set
            {
                _StuffOutWorkList = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("StuffOutWorkList"));
                }
            }
        }
        #endregion
        
        #region 初始化人员缺岗信息
            StuffOutWorkList = new List<StuffOutWorkModel>();
            StuffOutWorkList.Add(new StuffOutWorkModel { StuffName = "张晓婷", Position = "技术员", OutWorkCount = 123 });
            StuffOutWorkList.Add(new StuffOutWorkModel { StuffName = "李晓", Position = "操作员", OutWorkCount = 23 });
            StuffOutWorkList.Add(new StuffOutWorkModel { StuffName = "王克俭", Position = "技术员", OutWorkCount = 134 });
            StuffOutWorkList.Add(new StuffOutWorkModel { StuffName = "陈家栋", Position = "统计员", OutWorkCount = 143 });
            StuffOutWorkList.Add(new StuffOutWorkModel { StuffName = "杨过", Position = "技术员", OutWorkCount = 12 });

            #endregion

image.png

<UserControl.Resources>
    <!-- 定义 RadioButton 的全局样式,将应用于当前 UserControl 中所有的 RadioButton 控件 -->
    <Style TargetType="RadioButton">
        
        <!-- 基础属性设置 -->
        <Setter Property="Height" Value="22"></Setter>              <!-- 按钮高度22像素 -->
        <Setter Property="Width" Value="50"></Setter>               <!-- 按钮宽度50像素,统一大小 -->
        <Setter Property="Background" Value="#ddd"></Setter>        <!-- 默认背景色:浅灰色 (#DDDDDD) -->
        <Setter Property="Foreground" Value="#888"></Setter>        <!-- 默认前景色(文字颜色):深灰色 (#888888) -->
        <Setter Property="FontSize" Value="11"></Setter>            <!-- 字体大小:11像素 -->
        <Setter Property="BorderBrush" Value="#33ffffff"></Setter>  <!-- 边框颜色:半透明白色(约20%不透明度) -->
        
        <!-- 自定义控件模板:完全重写 RadioButton 的可视化外观 -->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="RadioButton">
                    <!-- 使用 Border 作为按钮容器 -->
                    <Border Background="{TemplateBinding Background}">  <!-- 背景绑定到 Background 属性 -->
                        <!-- 内容呈现器:显示 RadioButton 的 Content 内容(如"全部"、"作业"等文字) -->
                        <ContentPresenter HorizontalAlignment="Center"  <!-- 水平居中 -->
                                        VerticalAlignment="Center"></ContentPresenter>  <!-- 垂直居中 -->
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        
        <!-- 样式触发器:根据状态改变外观 -->
        <Style.Triggers>
            <!-- 触发器:当 RadioButton 被选中时(IsChecked = True) -->
            <Trigger Property="IsChecked" Value="True">
                <!-- 设置背景色为橙色,醒目提示选中状态 -->
                <Setter Property="Background" Value="Orange"></Setter>
                <!-- 设置前景色(文字颜色)为白色,提高对比度 -->
                <Setter Property="Foreground" Value="White"></Setter>
            </Trigger>
            <!-- 注意:这里没有定义鼠标悬停等交互状态的触发器 -->
        </Style.Triggers>
    </Style>
</UserControl.Resources>
<!-- 机台状态筛选栏:水平排列的堆栈面板,位于界面右侧 -->
<StackPanel HorizontalAlignment="Right"      <!-- 水平右对齐在父容器中-->
            Orientation="Horizontal"         <!-- 水平方向排列子元素 -->
            VerticalAlignment="Center"       <!-- 垂直居中 -->
            Margin="20,0">                   <!-- 左右外边距20像素,上下0 -->
    
    <!-- 状态筛选标签 -->
    <TextBlock Text="机台状态"                <!-- 显示文字:"机台状态" -->
               Foreground="White"             <!-- 白色文字 -->
               VerticalAlignment="Center">    <!-- 垂直居中 -->
    </TextBlock>
    
    <!-- 单选按钮组:用于筛选不同状态的机台 -->
    <!-- IsChecked="True" 表示默认选中"全部"选项 -->
    <RadioButton Content="全部"                <!-- 显示文字:"全部" -->
                 IsChecked="True">            <!-- 默认选中状态 -->
    </RadioButton>
    
    <!-- 作业状态:显示正在作业的机台 -->
    <RadioButton Content="作业"></RadioButton>
    
    <!-- 等待状态:显示等待中的机台 -->
    <RadioButton Content="等待"></RadioButton>
    
    <!-- 故障状态:显示发生故障的机台 -->
    <RadioButton Content="故障"></RadioButton>
    
    <!-- 停机状态:显示已停机的机台 -->
    <RadioButton Content="停机"></RadioButton>
    
</StackPanel>

样式效果说明:

1. 默认状态(未选中)

  • 背景色:浅灰色 (#ddd)
  • 文字颜色:深灰色 (#888)
  • 尺寸:50×22 像素的统一大小
  • 边框:半透明白色边框 (#33ffffff)

2. 选中状态

  • 背景色:橙色 (Orange)
  • 文字颜色:白色 (White)
  • 其他属性:保持不变