【C#】学习WPF的生产管理平台回顾与总结

目的

花了一周时间跟着B站的教学视频学习了如何用WPF制作一个生产管理平台上位机软件,学习完了,在此总结涉及到的相关知识.

MVVM工程模板

在这里插入图片描述

文件夹描述
Assets工程相关的资源文件(字体/图片…)
Base放实现上位机所需要的自定义控件/Models(模型)的定义/实现MVVM需要的操作组件
ViewModels放的就是上位机所需要的Model(模型)相关的初始化和声明
Views放的是上位机界面(也就是用户看到的皮)的实现(XAML/C#)实现

如何寻找图标这种资源

原来我以为的图标资源只有ico,png这种,但是教程告诉我,还可以通过字体实现,它提供了一个找图标的网站,阿里巴巴图标库,在里面注册好,便可以将希望使用的图标打包成一个字体文件,通过特殊的字体代码来调用,而且图标是可以放大不失真的,这就很方便了。
在这里插入图片描述

如何使用字体文件中的图标资源

例如某个TextBlock,希望使用某个字体图标,使用字体代码设置好内容,还需要设置FontFamily
并且要将字体文件设置为资源

<TextBlock Foreground="#55FFFFFF" Text="&#xe61c;" FontFamily="../Assets/Fonts/#iconfont" FontSize="30"></TextBlock>

在这里插入图片描述

如何将原生的窗口标题栏隐藏,并自己重新绘制按钮

首先在窗体xaml设置

    <!--设置边框,让边框不显示,仅剩下按钮-->
    <WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="-1"></WindowChrome>
    </WindowChrome.WindowChrome>

如果还需要窗体居中,可以设置

WindowStartupLocation="CenterScreen"

之后,摆好Grid,在右上角的位置放一个透明的border把原来的按钮那部分区域遮挡住,之后再在透明的border上放好需要的按钮

                    <!--这个boarder的作用是用来遮挡原来的按钮-->
                    <Border HorizontalAlignment="Right" WindowChrome.IsHitTestVisibleInChrome="True" Background="Transparent" Width="200">
                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
                            <Button Content="&#xe629;" Style="{StaticResource ControlButtonStyle}" />
                            <Button Content="&#xe65b;" Style="{StaticResource ControlButtonStyle}"/>
                            <Button Content="&#xe624;" Style="{StaticResource ControlButtonStyle}" Background="DarkRed" Click="Button_Click"/>
                        </StackPanel>
                    </Border>

分割线的绘制

在这里插入图片描述
就是这种似乎是一条条斜线绘制出来的分割线,教程里使用的visualbrush画出来的
用一个border承载这个分割线

                <!--处理分割线,用visualbrush刷线-->
                <Border Margin="0,0,0,0">
                    <Border.Background>
                        <!--处理填充的模式-->
                        <VisualBrush TileMode="Tile" Viewport="0,0,5,5" ViewportUnits="Absolute">
                            <VisualBrush.Visual>
                                <Grid Width="20" Height="20">
                                    <Line X1="0" Y1="10" X2="10" Y2="0" Stroke="Gray" StrokeThickness="1"/>
                                </Grid>
                            </VisualBrush.Visual>
                        </VisualBrush>
                    </Border.Background>
                </Border>

为按钮添加样式模板并实现触发器功能,滑过按钮,触发阴影效果

例如定义一个button的模板

        <Style TargetType="Button" x:Key="ControlButtonStyle">
            <Setter Property="Width" Value="40"/>
            <Setter Property="Background" Value="#11FFFFFF"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="FontFamily" Value="Assets/Fonts/#iconfont"/>
            <Setter Property="FontSize" Value="20"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <!--这里的controlTemplate中的绑定Background,在控件那里,设置了这个模板,在外部设置的值会影响
                        到里面所绑定的属性(Background),模板中的设置同样也会影响到外部控件的值-->
                        <Grid Background="{TemplateBinding Background}">
                            <!--这里再做一个效果,就是鼠标放上去,颜色不一样-->
                            <Border Name="root">
                                <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
                            </Border>

                        </Grid>
                        <!--触发器,IsMouseOver事件 放上去颜色会不一样-->
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="root" Property="Background" Value="#33FFFFFF"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

界面xaml中只要设置了这个style的就可以使用定义好的样式了

<Button Content="&#xe629;" Style="{StaticResource ControlButtonStyle}" />

如何设置Grid的背景色为中间淡,边缘深的那种

        <Grid.Background>
            <!--背景,中间淡,边缘深-->
            <RadialGradientBrush>
                <GradientStop Color="#FF1EC0E9" Offset="0"/>
                <GradientStop Color="#FF1EC0E9" Offset="0.3"/>
                <GradientStop Color="#FF1EC0E9" Offset="1"/>
            </RadialGradientBrush>
        </Grid.Background>

指定当前元素和绑定源的位置关系

通过RelativeSource 和 AncestorType来告诉编译器要去哪里找绑定资源
例如下面的例子是让TextBlock的文字绑定窗口的标题,让绑定源去窗体找

                    <!--指当前元素和绑定源的位置关系。
                    AncestorType指定绑定源为某个父元素-->
                    <TextBlock 
                        Foreground="White" 
                        Text="{Binding Title,RelativeSource={RelativeSource AncestorType=Window}}">
                    </TextBlock>

或者通过希望绑定的元素的名字来告诉编译器去哪里找

                    <TextBlock 
                        Foreground="White" 
                        Text="{Binding Title,ElementName=Window}">
                    </TextBlock>

或者希望绑定自身的其他属性的值

<TextBox Text="{Binding Path=Background, Mode=TwoWay,RelativeSource={RelativeSource Self}}"  />  

绑定文字的时候希望做些格式处理

StringFormat这个属性可以对绑定的属性做些格式上的处理

 <TextBlock FontSize="10" Text="{Binding Len,StringFormat=时长{0}秒}"  Grid.Column="5" VerticalAlignment="Center" Foreground="White" HorizontalAlignment="Center"/>

Model/ViewModel/View的互通

教程中介绍了

  1. 继承INotifyPropertyChanged实现的通知接口类,实现了一个设置属性的泛型接口SetProperty
  2. 继承ICommand实现的动作执行类,实现了对触发动作和其传递参数的封装

继承INotifyPropertyChanged实现的通知接口类

    /// <summary>
    /// 通知接口类
    /// </summary>
    internal class NotifyBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        /// <summary>
        /// 设置属性,并且触发事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="field"></param>
        /// <param name="value"></param>
        /// <param name="propName"></param>
        public void SetProperty<T>(ref T field,T value, [CallerMemberName] string propName="")
        {
            field = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }
    }

用法是在希望实现这种通知式传递数据的Model中对应的属性的set方法中调用SetProperty

        private string _badCount;
        public string BadCount
        {
            get { return _badCount; }
            set { SetProperty(ref _badCount, value); }
        }

继承ICommand实现的动作执行类

    public class Command : ICommand
    {
        public event EventHandler? CanExecuteChanged;

        public bool CanExecute(object? parameter)
        {
            return true;
        }

        public void Execute(object? parameter)
        { 
             DoExexcute?.Invoke(parameter);   
        }

        //使用委托传递外部希望执行的动作
        public Action<object> DoExexcute { get; set; }
        public Command(Action<object> action)
        {
            DoExexcute = action;
        }
    }

用法是定义对应的Command类变量属性字段

public Command DetailCommand { get; set; }

//然后初始化它,传递需要执行的回调和参数
 DetailCommand = new Command(DoDetailCommand);

之后对应要使用的xaml使用command属性设置好对应的Command名字

                            <!--这里使用command绑定一个Base中的类,注意要使用相对范围才找得到-->
                            <Button Grid.Row="0" 
                                    Margin="10,-20,-17,0" 
                                    HorizontalAlignment="Right"
                                    VerticalAlignment="Center"
                                    Content="[ 详情 ]" 
                                    Style="{StaticResource DetailButton}"
                                    BorderThickness="0" Width="80" Height="30" FontSize="15"
                                    Command="{Binding DetailCommand,RelativeSource={RelativeSource AncestorType=Window}}" 
                                    CommandParameter="{Binding}"
                                    >
                            </Button>

Itemcontrol集合的使用

                    <ItemsControl ItemsSource="{Binding Enviroment}" Margin="5">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <!--数据集合划分为4列-->
                                <UniformGrid Columns="4"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>

                        <!--数据集合绑定数据源的元素-->
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
                                    <TextBlock Margin="0,10,0,0" Text="{Binding Value}" FontSize="15" Foreground="GhostWhite" HorizontalAlignment="Center" FontWeight="Bold"/>
                                    <TextBlock Text="{Binding Header}" FontSize="10" Foreground="FloralWhite" HorizontalAlignment="Center"/>
                                </StackPanel>
                                
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>

首先定义ItemsControl,需要指定需要绑定的数据源,也就是ItemsSource
ItemsControl.ItemsPanel这个是集合的载体(我是这样理解的),如果不修改,那么这个载体就是默认的载体
ItemsControl.ItemTemplate和DataTemplate是这个是集合的模板,也就是希望生成的每一个集合的样子,内部包含的控件,数据绑定等等
当然这个ItemTemplate可以在外部写,写成资源,给其他需要的itemcontrol用
外部写个资源

                <StackPanel.Resources>
                    <DataTemplate x:Key="dataTemp">
                        <Border Width="15" Background="#99FFFFFF" Margin="2,0">
                            <TextBlock Text="{Binding}" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" FontSize="15" FontWeight="Bold"/>
                        </Border>
                    </DataTemplate>
                </StackPanel.Resources>

其他itemcontrol调用一下

                <ItemsControl ItemsSource="{Binding BadCount}"  ItemTemplate="{StaticResource dataTemp}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel Orientation="Horizontal">
                            </VirtualizingStackPanel>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>

                </ItemsControl>

自定义GroupBox模板,实现漂亮的控件框

在这里插入图片描述

        <Style TargetType="GroupBox">
            <Setter Property="Margin" Value="10,5"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GroupBox">
                        <!--GroupBox的边框-->
                        <!--用折线,园,边框画出复杂的边框-->
                        <Grid>
                            <Polyline Points="0 30,0 10,10 0,30 0" Stroke="White" StrokeThickness="1" VerticalAlignment="Top" HorizontalAlignment="Left"/>
                            <Ellipse Width="4" Height="4" VerticalAlignment="Top" HorizontalAlignment="Left" Fill="White" Margin="27,-2,0,0"/>
                            <Ellipse Width="4" Height="4" VerticalAlignment="Top" HorizontalAlignment="Left" Fill="White" Margin="-2,27,0,0"/>
                            <Path Data="M0 0,3 3,30 3,33 0,68 0,73 7,78 7,78 10M8 0,25 0" Stroke="White" StrokeThickness="1" VerticalAlignment="Top" HorizontalAlignment="Right"/>
                            <Polyline Points="0,0 0,15 10,15" Stroke="White" StrokeThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
                            <Polyline Points="10,0 0,10" Stroke="White" StrokeThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
                            <Polygon Points="0,7 7 7 7 0" Fill="White" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
                            <Border BorderBrush="White" BorderThickness="0,1,0,0" VerticalAlignment="Top" Margin="30,-0.5,78,0"/>
                            <Border BorderBrush="White" BorderThickness="0,0,1,0" HorizontalAlignment="Right" Margin="0,10"/>
                            <Border BorderBrush="White" BorderThickness="0,1,0,0" VerticalAlignment="Bottom" Margin="10,0"/>
                            <Border BorderBrush="White" BorderThickness="0,0,1,0" HorizontalAlignment="Left" Margin="-0.5,15"/>
                            <!--自动绑定Header属性-->
                            <TextBlock Text="{TemplateBinding Header}" Foreground="White" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5"/>
                            <!--还需要放置其用于放置内容的区域controlpresenter-->
                            <ContentPresenter>
                                
                            </ContentPresenter>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

livechart图标库的使用

这个直接搜其他人的教程算了,这个都可以单独写一篇了
确实很不错,做出来的效果
顺带一提,这个图例的小方块使用border做的

                    <StackPanel Margin="0,5,15,0" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Right">
                            <Border Width="5" Height="5" Background="Red" Margin="5,0"></Border>
                            <TextBlock Text="不良计数" Foreground="Red" FontSize="15"></TextBlock>
                            <Border Width="5" Height="5" Background="Green" Margin="5,0"></Border>
                            <TextBlock Text="生产计数" Foreground="Green" FontSize="15"></TextBlock>
                        </StackPanel>

在这里插入图片描述

                        <lvc:CartesianChart Margin="5,30,0,0">
                        <lvc:CartesianChart.Series>
                            <lvc:ColumnSeries 
                                Values="300,400,500,345,200,250,400,500"
                                MaxColumnWidth="10"
                                Title="生产计数"
                                >
                                <lvc:ColumnSeries.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Color="GreenYellow" Offset="0.5"/>
                                        <GradientStop Color="LawnGreen" Offset="0.1"/>
                                    </LinearGradientBrush>
                                </lvc:ColumnSeries.Fill>
                            </lvc:ColumnSeries>

                            <lvc:ColumnSeries Values="150,200,80,506,708,203,155,123"
                             MaxColumnWidth="10"
                             Title="不良计数" >
                                <lvc:ColumnSeries.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Color="OrangeRed" Offset="0.5"/>
                                        <GradientStop Color="IndianRed" Offset="0.1"/>
                                    </LinearGradientBrush>
                                </lvc:ColumnSeries.Fill>
                            </lvc:ColumnSeries>
                        </lvc:CartesianChart.Series>

                        <lvc:CartesianChart.AxisX >
                            <lvc:Axis Labels="1:00,2:00,3:00,4:00,5:00,6:00,7:00,8:00" Foreground="White">
                                <lvc:Axis.Separator>
                                    <lvc:Separator Step="1" StrokeThickness="0"/>
                                </lvc:Axis.Separator>
                            </lvc:Axis>
                        </lvc:CartesianChart.AxisX>

                        <lvc:CartesianChart.AxisY>
                            <lvc:Axis MinValue="0" MaxValue="1000" Foreground="White">
                                <lvc:Axis.Separator>
                                    <lvc:Separator Step="200" StrokeThickness="0.5" Stroke="White"/>
                                </lvc:Axis.Separator>
                            </lvc:Axis>
                        </lvc:CartesianChart.AxisY>

                    </lvc:CartesianChart>

标签式的单选按钮组

在这里插入图片描述
也是用样式做的

        <!--单选框的样式-->
        <Style TargetType="RadioButton">
            <Setter Property="Width" Value="50"/>
            <Setter Property="Foreground" Value="#ddd"/>
            <Setter Property="Height" Value="22"/>
            <Setter Property="Background" Value="#eee"/>
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="RadioButton">
                        <Border Background="{TemplateBinding Background}">
                            <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
                
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsChecked" Value="True">
                    <Setter Property="Background" Value="Orange"/>
                    <Setter Property="Foreground" Value="White"/>
                </Trigger>
            </Style.Triggers>
        </Style>

不同窗体之间的切换

这种切换是整个切换,不是弹出另一个窗体的那种
做的时候得有个树状结构的思想
从主窗口,切换到下属的窗体,然后再切回来
例如要从主窗体mainViewModel切换到workshopView
那么只需要再对应的回调函数里

            WorkshopView workshopView = new WorkshopView();
            mainViewModel.PageContent = workshopView;

切换窗体的动画

这种主要是添加用户体验,注意切入窗口和切出的时候动画触发的时机

切入

            WorkshopView workshopView = new WorkshopView();
            mainViewModel.PageContent = workshopView;


            //动画处理
            
            //透明度
            ThicknessAnimation thicknessAnimation = new ThicknessAnimation(
                new Thickness(0,50,0,-50), new Thickness(0, 0, 0, 0),
                new TimeSpan(0,0,0,0,400));
            //位移
            DoubleAnimation doubleAnimation = new DoubleAnimation(0, 1, new TimeSpan(0, 0, 0, 0, 400));

            //绑定对象和属性
            Storyboard.SetTarget(doubleAnimation, workshopView);
            Storyboard.SetTarget(thicknessAnimation, workshopView);
            Storyboard.SetTargetProperty(thicknessAnimation, new PropertyPath("Margin"));
            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));

            //录入动画
            Storyboard storyboard = new Storyboard();
            storyboard.Children.Add(thicknessAnimation);
            storyboard.Children.Add(doubleAnimation);
            storyboard.Begin();

切出回到主窗体

            MonitorView monitorView = new MonitorView();
            mainViewModel.PageContent = monitorView;

            //透明度
            ThicknessAnimation thicknessAnimation = new ThicknessAnimation(
                new Thickness(0, 50, 0, -50), new Thickness(0, 0, 0, 0),
                new TimeSpan(0, 0, 0, 0, 400));

            //动画处理

            //绑定对象和属性

            Storyboard.SetTarget(thicknessAnimation, monitorView);
            Storyboard.SetTargetProperty(thicknessAnimation, new PropertyPath("Margin"));


            //录入动画
            Storyboard storyboard = new Storyboard();
            storyboard.Children.Add(thicknessAnimation);
            storyboard.Begin();

自定义控件的做法

这个也是个复杂的专题,可以单独写一篇
简单写下我的理解,剩下的后面用到再查教程算了
自定义控件和画窗体是差不多的
先画好xaml前端
难点在后端数据和前端xaml的互动
后端设计好需要前后端传递的属性字段,前后端做好绑定
在VS里打打prodp,快速打出属性绑定一条龙语句,非常方便,原来不知道,设置好对应的回调函数,
设置好构造函数,设置好其他希望的事件函数(例如很重要的刷新重绘函数)
在用的xaml文件上写好类型C#的using引用(xmlns巴拉巴拉那堆玩意)
然后就可以愉快的调用你的自定义控件了

页面滚动的效果

把需要滚动的内容填里面
然后顺带把滚动的侧边隐藏了

<ScrollViewer VerticalScrollBarVisibility="Hidden" Grid.Row="1" Margin="10,5"/>

页面内再弹出一个小页面显示

在这里插入图片描述
这种效果是用board遮住,原来的内容,然后再在新的border上整活,就是注意用控件做一个command触发它弹出,关闭,动画效果和本文中那个类似,也是做好动画触发的时机,Visibility="Collapsed"控制好。

<Border Background="#22000000" Grid.RowSpan="2" Name="detail" Visibility="Collapsed">

</Border>

单选侧边栏

这种其实是单选框的变体,重写写了个样式,用border封了个边。

        <Style TargetType="RadioButton" x:Key="NavButtonStyle">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="RadioButton">
                        <Grid Background="Transparent" >
                            <Border Background="{TemplateBinding Background}" Height="30" >
                                <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"/>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>

            <Style.Triggers>
                <Trigger Property="IsChecked" Value="True">
                    <Setter Property="Background" Value="Orange"/>
                    <Setter Property="Foreground" Value="White"/>
                </Trigger>
            </Style.Triggers>
        </Style>

并且这个教程实现了一个单击侧边按钮,可以跳转到指定的内容那个位置
这个的做法是给每一个内容顶部的标题编写了不同的名字,用的是Tag属性

        <StackPanel Margin="0,10" Grid.Row="1">
            <RadioButton Style="{StaticResource NavButtonStyle}" Content="设备清单" Click="RadioButton_Click"  Tag="s1" IsChecked="True"/>
            <RadioButton Style="{StaticResource NavButtonStyle}"  Content="环境监测" Click="RadioButton_Click"  Tag="s2" IsChecked="True"/>
            <RadioButton Style="{StaticResource NavButtonStyle}"  Content="设备监测" Click="RadioButton_Click"  Tag="s3" IsChecked="True"/>
            <RadioButton Style="{StaticResource NavButtonStyle}"  Content="设备4" Click="RadioButton_Click"     Tag="s4" IsChecked="True"/>
            <RadioButton Style="{StaticResource NavButtonStyle}"  Content="设备5" Click="RadioButton_Click"     Tag="s5" IsChecked="True"/>
            <RadioButton Style="{StaticResource NavButtonStyle}"  Content="设备6" Click="RadioButton_Click"     Tag="s6" IsChecked="True"/>
            <RadioButton Style="{StaticResource NavButtonStyle}"  Content="设备7" Click="RadioButton_Click"     Tag="s7" IsChecked="True"/>
            <RadioButton Style="{StaticResource NavButtonStyle}"  Content="设备8" Click="RadioButton_Click"     Tag="s8" IsChecked="True"/>

        </StackPanel>

然后在单选按钮单击的时候触发事件跳转到指定Page的对应的Tag的位置

        private void RadioButton_Click(object sender, RoutedEventArgs e)
        {
            //页面内部滚动导航到指定位置的方法
            //其实就是对每一个需要导航的Grid做了编码
            this.frame.Navigate(
                new Uri(
                    "pack://application:,,,/Wpf_Automatic_Core;component/Views/SettingsPage.xaml#" +
                    (sender as RadioButton).Tag.ToString(), UriKind.RelativeOrAbsolute));
        }

Page的xaml

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>

            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>

            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>

            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>

            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>

            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>

            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>

            <RowDefinition Height="40"/>
            <RowDefinition Height="Auto"/>
            
        </Grid.RowDefinitions>

        <Border BorderBrush="#eee" BorderThickness="0,0,0,1"/>
        <Border BorderBrush="#eee" BorderThickness="0,0,0,1" Grid.Row="2"/>
        <Border BorderBrush="#eee" BorderThickness="0,0,0,1" Grid.Row="4"/>
        <Border BorderBrush="#eee" BorderThickness="0,0,0,1" Grid.Row="6"/>
        <Border BorderBrush="#eee" BorderThickness="0,0,0,1" Grid.Row="8"/>
        <Border BorderBrush="#eee" BorderThickness="0,0,0,1" Grid.Row="10"/>
        <Border BorderBrush="#eee" BorderThickness="0,0,0,1" Grid.Row="12"/>
        <Border BorderBrush="#eee" BorderThickness="0,0,0,1" Grid.Row="14"/>

        <Label Content="设备清单" Name="s1" VerticalContentAlignment="Center"             />
        <Label Content="环境监测" Name="s2" VerticalContentAlignment="Center" Grid.Row="2"/>
        <Label Content="设备监测" Name="s3" VerticalContentAlignment="Center" Grid.Row="4"/>
        <Label Content="设备4"    Name="s4" VerticalContentAlignment="Center" Grid.Row="6"/>
        <Label Content="设备5"    Name="s5" VerticalContentAlignment="Center" Grid.Row="8"/>
        <Label Content="设备6"    Name="s6" VerticalContentAlignment="Center" Grid.Row="10"/>
        <Label Content="设备7"    Name="s7" VerticalContentAlignment="Center" Grid.Row="12"/>
        <Label Content="设备8"    Name="s8" VerticalContentAlignment="Center" Grid.Row="14"/>

        <Grid Height="200" Grid.Row="1" Margin="10,5">
            <StackPanel>
                <Grid Height="30" Background="#09000000" Margin="0,1">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="50"/>
                        
                    </Grid.ColumnDefinitions>

                    <TextBlock Text="控制器#1" VerticalAlignment="Center" Margin="10,0"/>
                    <TextBlock Text="9600,N,8,1,1" Grid.Column="1" VerticalAlignment="Center"/>
                    <TextBlock Text="ModbusRTU" Grid.Column="2" VerticalAlignment="Center"/>
                    <TextBlock Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center">
                        <Hyperlink >点位表</Hyperlink>
                    </TextBlock>

                    
                </Grid>
                <UniformGrid Columns="2">
                    <Grid Height="30" Margin="30,0,0,0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="温度" VerticalAlignment="Center"/>
                        <TextBlock Text="40001" Grid.Column="1" VerticalAlignment="Center"/>
                        <TextBlock Text="" Grid.Column="2" VerticalAlignment="Center"/>
                        <TextBlock Grid.Column="3" VerticalAlignment="Center">
                                <Hyperlink>删除</Hyperlink>
                        </TextBlock>
                    </Grid>

                    <Grid Height="30" Margin="30,0,0,0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="湿度" VerticalAlignment="Center"/>
                        <TextBlock Text="40002" Grid.Column="1" VerticalAlignment="Center"/>
                        <TextBlock Text="%" Grid.Column="2" VerticalAlignment="Center"/>
                        <TextBlock Grid.Column="3" VerticalAlignment="Center">
                                <Hyperlink>删除</Hyperlink>
                        </TextBlock>
                    </Grid>
                </UniformGrid>
            </StackPanel>
        </Grid>
        <Grid Height="200" Grid.Row="3"></Grid>
        <Grid Height="200" Grid.Row="5"></Grid>
        <Grid Height="200" Grid.Row="7"></Grid>
        <Grid Height="200" Grid.Row="9"></Grid>
        <Grid Height="200" Grid.Row="11"></Grid>
        <Grid Height="200" Grid.Row="13"></Grid>
        <Grid Height="200" Grid.Row="15"></Grid>

    </Grid>

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值