WPF+MVVM案例实战(四)- 自定义GroupBox边框样式实现

文章目录

  • 1、项目准备
  • 2、功能实现
    • 1、EnviromentModel.cs 代码
    • 2、GroubBoxViewModel.cs 代码实现
    • 3、ViewModelLocator.cs 依赖注入
    • 4、GroubBoxWindow.xaml 样式布局
    • 5、数据绑定
  • 3、效果展示
  • 4、资源获取


1、项目准备

打开项目 Wpf_Examples,新建 GroubBoxWindow.xaml 界面、GroubBoxViewModel.cs 和 EnviromentModel.cs 文件。如下所示:
在这里插入图片描述
没有这个项目的小伙伴可以看文章 WPF+MVVM案例实战(三)- 动态数字卡片效果实现 ,这里面详细说明了项目创建过程。

2、功能实现

1、EnviromentModel.cs 代码

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wpf_Examples.Models
{
    public class EnviromentModel:ObservableObject
    {
        /// <summary>
        /// 环境指标项名称
        /// </summary>
        private string _EnItemName;
        public string EnItemName
        {

            get => _EnItemName;
            set
            {
               SetProperty(ref _EnItemName, value);
            }
        }
        /// <summary>
        /// 环境指标项值
        /// </summary>
        private int _EnItemValue;
        public int EnItemValue
        {
            get => _EnItemValue;
            set
            {
                SetProperty(ref _EnItemValue, value);
            }
        }
    }
}

2、GroubBoxViewModel.cs 代码实现

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
using Wpf_Examples.Models;

namespace Wpf_Examples.ViewModels
{
    public class GroubBoxViewModel:ObservableObject
    {
        #region 监控数据
        public ObservableCollection<EnviromentModel> EnviromentList { get; set; }

        #endregion

        public GroubBoxViewModel()
        {

            #region 数据初始化
            EnviromentList = new ObservableCollection<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 = 44 });
            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
            CreateTimer(); //创建定时器动态改变数据
        }


        private void CreateTimer()
        {
            #region 每秒定时器服务
            DispatcherTimer cpuTimer = new DispatcherTimer
            {
                Interval = new TimeSpan(0, 0, 0, 3, 0)
            };
            cpuTimer.Tick += DispatcherTimer_Tick;
            cpuTimer.Start();
            #endregion
        }

        private void DispatcherTimer_Tick(object sender, EventArgs e)
        {
            Random random = new Random();
            foreach (var item in EnviromentList)
            {
                item.EnItemValue = random.Next(10,100);
            }        
        }
    }
}

3、ViewModelLocator.cs 依赖注入

using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace Wpf_Examples.ViewModels
{
    public class ViewModelLocator
    {
        public IServiceProvider Services { get; }
        public ViewModelLocator()
        {
            Services = ConfigureServices();
        }
        private static IServiceProvider ConfigureServices()
        {
            var services = new ServiceCollection();

            //这里实现所有viewModel的容器注入
            services.AddSingleton<MainViewModel>();
            services.AddScoped<LEDStatusViewModel>();
            services.AddScoped<ImageButtonViewModel>();
            services.AddScoped<DataCardViewModel>();
            services.AddScoped<GroubBoxViewModel>();
            //添加其他 viewModel

            return services.BuildServiceProvider();
        }

        public MainViewModel Main => Services.GetService<MainViewModel>();
        public LEDStatusViewModel LedStatus => Services.GetService<LEDStatusViewModel>();
        public ImageButtonViewModel ImageButton => Services.GetService<ImageButtonViewModel>();
        public DataCardViewModel DataCard => Services.GetService<DataCardViewModel>();
        public GroubBoxViewModel GroupBox => Services.GetService<GroubBoxViewModel>();
        
    }
}

4、GroubBoxWindow.xaml 样式布局

<Window x:Class="Wpf_Examples.Views.GroubBoxWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Wpf_Examples.Views"
        DataContext="{Binding Source={StaticResource Locator},Path=GroupBox}"
        mc:Ignorable="d"
        Title="GroubBoxWindow" Height="450" Width="800" Background="#2B2B2B">
    <Window.Resources>
        <Style TargetType="GroupBox">
            <Setter Property="Margin" Value="10,3"></Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GroupBox">
                        <Grid>
                            <!--左上角的线条-->
                            <Polyline Points="0 30,0 10,10 0,30 0" Stroke="#9918aabd" StrokeThickness="1" VerticalAlignment="Top" HorizontalAlignment="Left"></Polyline>
                            <!--左上 横的点  小圆-->
                            <Ellipse Width="4" Height="4" HorizontalAlignment="Left" Fill="#9918aabd" VerticalAlignment="Top" Margin="24,-2,0,0"></Ellipse>
                            <!--左侧的点  小圆-->
                            <Ellipse Width="4" Height="4" HorizontalAlignment="Left" Fill="#9918aabd" VerticalAlignment="Top" Margin="-2,24,0,0"></Ellipse>
                            <!--Moveto-->
                            <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>
                            <!--右边的线-->
                            <Border BorderThickness="0,0,1,0" BorderBrush="#9918aabd"  HorizontalAlignment="Right" Margin="0,10"></Border>

                            <!--下面的线-->
                            <Border BorderThickness="0,0,0,1" BorderBrush="#9918aabd" VerticalAlignment="Bottom" Margin="10,0"></Border>

                            <!--左边的线-->
                            <Border BorderThickness="1,0,0,0" BorderBrush="#9918aabd"  HorizontalAlignment="Left" Margin="-0.5,15"></Border>

                            <!--文字前的装饰-->
                            <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" Margin="16,13"></Path>
                            <TextBlock Text="{TemplateBinding Header}" Foreground="White" FontWeight="Bold" Margin="25,8" HorizontalAlignment="Left" VerticalAlignment="Top"></TextBlock>
                            <!--显示内容-->
                            <ContentPresenter></ContentPresenter>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <GroupBox Header="监控指标" Margin="20">
            <ItemsControl ItemsSource="{Binding EnviromentList}" VerticalAlignment="Center">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <UniformGrid Columns="4"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" Margin="0 5">
                            <TextBlock Text="{Binding EnItemValue}" FontSize="16" Foreground="#ff2bedf1" Margin="0 5"/>
                            <TextBlock Text="{Binding EnItemName}" FontSize="10" Foreground="White" Margin="0 5"/>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </GroupBox>
    </Grid>
</Window>

5、数据绑定

 DataContext="{Binding Source={StaticResource Locator},Path=GroupBox}"

3、效果展示

在这里插入图片描述

4、资源获取

CSDN 下载链接:WPF+MVVM案例实战(四)- 自定义GroupBox边框样式实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/900778.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

龙蟠科技业绩压力显著:资产负债率持续攀升,产能利用率也不乐观

《港湾商业观察》施子夫 黄懿 去年十月至今两度递表后&#xff0c;10月17日&#xff0c;江苏龙蟠科技股份有限公司(以下简称&#xff0c;龙蟠科技&#xff1b;603906.SH&#xff0c;02465.HK)通过港交所主板上市聆讯。 很快&#xff0c;龙蟠科技发布公告称&#xff0c;公司全…

基于STM32的Android控制智能家政机器人

基于STM32的Android控制智能家政机器人 基于STM32的Android控制智能家政机器人一、项目背景与意义二、系统设计方案三、硬件电路设计四、软件设计与实现4.1 Android端软件设计4.2 机器人端软件设计 五、系统调试与测试六、结论与展望七、附录 基于STM32的Android控制智能家政机…

信息安全工程师(55)网络安全漏洞概述

一、定义 网络安全漏洞&#xff0c;又称为脆弱性&#xff0c;是网络安全信息系统中与安全策略相冲突的缺陷&#xff0c;这种缺陷也称为安全隐患。漏洞可能导致机密性受损、完整性破坏、可用性降低、抗抵赖性缺失、可控性下降、真实性不保等问题。 二、分类 网络安全漏洞可以根据…

HDU Sum

题目大意&#xff1a;给你一个数字 n &#xff0c;n 个数字能分成多少组分类情况。 思路&#xff1a;这题要用插空法&#xff0c;一共 n 个数字&#xff0c;所以一共有 n - 1 个空可以插入&#xff0c;所以这道题目的答案就是&#xff0c;由二项式定理易得这个式子的和为 。但是…

Web应用框架-Django应用基础

1. 认识Django Django是一个用Python编写的开源高级Web框架&#xff0c; 旨在快速开发可维护和可扩展的Web应用程序。 使用Django框架的开发步骤&#xff1a; 1.选择合适的版本 2.安装及配置 3.生成项目结构 4.内容开发 5.迭代、上线、维护 Django官网&#xff1a; Djang…

UE4_Niagara基础实例—10、位置事件

效果&#xff1a; 若要为烟花火箭创建尾迹效果&#xff0c;则可将 生成位置事件&#xff08;Generate Location Event&#xff09; 模块放置到火箭发射器的粒子更新&#xff08;Particle Update&#xff09;组中。然后&#xff0c;尾迹发射器可使用位置数据生成跟随火箭的粒子…

离散制造和流程制造分别是什么?它们有什么区别?

为何有的企业生产过程看似一气呵成&#xff0c;而有的则是由多个环节组合而成&#xff1f;其实这就涉及到了制造业的两种常见生产模式。 流程制造离散制造 那么&#xff0c;在生产管理方面&#xff0c;离散制造和流程制造分别有什么特点、区别呢&#xff1f; 今天&#xff0…

C++游戏开发教程:从入门到进阶

C游戏开发教程&#xff1a;从入门到进阶 前言 在游戏开发的世界里&#xff0c;C以其高效的性能和灵活的特性&#xff0c;成为了众多游戏开发者的首选语言。在本教程中&#xff0c;我们将带您从基础知识入手&#xff0c;逐步深入到实际的游戏开发项目中。无论您是初学者还是有…

二百七十、Kettle——ClickHouse中增量导入清洗数据错误表

一、目的 比如原始数据100条&#xff0c;清洗后&#xff0c;90条正确数据在DWD层清洗表&#xff0c;10条错误数据在DWD层清洗数据错误表&#xff0c;所以清洗数据错误表任务一定要放在清洗表任务之后。 更关键的是&#xff0c;Hive中原本的SQL语句&#xff0c;放在ClickHouse…

深入理解Android WebView的加载流程与事件回调

在Android开发中&#xff0c;WebView用于显示网页和执行JavaScript。理解其加载流程和事件回调对于开发一个功能丰富且用户友好的基于Web的应用至关重要。本文将详细介绍 WebView 加载一个URL时的整个流程和相关的事件回调&#xff0c;帮助开发者更好地掌握其使用方法和处理可能…

数据库、数据仓库、数据湖和数据中台有什么区别

很多企业在面对数据存储和管理时不知道如何选择合适的方式&#xff0c;数据库、数据仓库、数据湖和数据中台&#xff0c;这些方式都是什么&#xff1f;有什么样的区别&#xff1f;企业根据其业务类型该选择哪一种&#xff1f;本文就针对这些问题&#xff0c;来探讨下这些方式都…

基于Netty构建WebSocket服务并实现项目群组聊天和实时消息通知推送

文章目录 前言需求分析技术预研Web端方案服务端技术 技术方案设计思路功能实现添加依赖自定义NettyServer自定义webSocketHandler使用NettyServer向在线用户发送消息 需要完善的地方 前言 我们的项目有个基于项目的在线文档编制模块&#xff0c;可以邀请多人项目组成员在线协同…

2024mathorcup大数据竞赛B题【电商品类货量预测及品类分仓规划】思路详解

问题 1&#xff1a;建立货量预测模型&#xff0c;对该仓储网络 350 个品类未来 3 个月&#xff08;7-9月&#xff09;每个月的库存量及销量进行预测&#xff0c;其中库存量根据历史每月数据预测月均库存量即可&#xff0c;填写表 1 的预测结果并放在正文中&#xff0c;并将完整…

Discuz发布原创AI帖子内容生成:起尔 | AI原创帖子内容生成插件开发定制

Discuz发布原创AI帖子内容生成&#xff1a;起尔 | AI原创帖子内容生成插件开发定制 在当今互联网快速发展的时代&#xff0c;内容创作成为了网站运营、社交媒体管理和个人博客维护不可或缺的一部分。然而&#xff0c;高质量内容的创作往往耗时耗力&#xff0c;特别是对于需要频…

实现prometheus+grafana的监控部署

直接贴部署用的文件信息了 kubectl label node xxx monitoringtrue 创建命名空间 kubectl create ns monitoring 部署operator kubectl apply -f operator-rbac.yml kubectl apply -f operator-dp.yml kubectl apply -f operator-crd.yml # 定义node-export kubectl app…

Qt 支持打包成安卓

1. 打开维护Qt&#xff0c;双击MaintenanceTool.exe 2.登陆进去,默认是添加或移除组件&#xff0c;点击下一步&#xff0c; 勾选Android, 点击下一步 3.更新安装中 4.进度100%&#xff0c;完成安装&#xff0c;重启。 5.打开 Qt Creator&#xff0c;编辑-》Preferences... 6.进…

self-supervised learning(BERT和GPT)

1芝麻街与NLP模型 我們接下來要講的主題呢叫做Self-Supervised Learning&#xff0c;在講self-supervised learning之前呢&#xff0c;就不能不介紹一下芝麻街&#xff0c;為什麼呢因為不知道為什麼self-supervised learning的模型都是以芝麻街的人物命名。 因為Bert是一個非常…

maven下载依赖报错Blocked mirror for repositories

原因&#xff1a;Maven版本过高 解决办法 setting文件添加 或者降低maven版本 <mirrors><mirror><id>maven-default-http-blocker</id><mirrorOf>external:dummy:*</mirrorOf><name>Pseudo repository to mirror external reposit…

表格切割效果,“两个”表格实现列对应、变化一致

如何让两个表格的部分列对应且缩放一致 先看效果 使用一个原生table的即可实现 “两个”表格的视觉效果让“两个”表格的对应列缩放保持一致 废话不多说&#xff0c;直接上代码 html: <html><div><table><caption class"table-name">表格…

模拟信号采集显示器+GPS同步信号发生器制作全过程(焊接、问题、代码、电路)

1、制作最小系统板 在制作最小系统板的时候&#xff0c;要用USB转TTL给板子供电&#xff0c;留了一个电源输入的四个接口&#xff0c;同时又用排针引出来VCC和GND用于后续其他外设的电源供应&#xff0c;电源配有电源指示灯和保护电容&#xff0c; 当时在焊接的时候把接口处的…