当前位置: 首页 > news >正文

WPF自定义控件

控件模板

顾名思义就是在原有的控件上进行模版修改成自己需要的样式

把ProgressBar修改为一个水液面的进度条

<Window x:Class="XH.CustomLesson.MainWindow"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:XH.CustomLesson"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Window.Resources><SolidColorBrush x:Key="ProgressBar.Progress" Color="#FF06B025"/><SolidColorBrush x:Key="ProgressBar.Background" Color="#FFE6E6E6"/><SolidColorBrush x:Key="ProgressBar.Border" Color="#FFBCBCBC"/><Style x:Key="ProgressBarStyle" TargetType="{x:Type ProgressBar}"><Setter Property="Foreground" Value="{StaticResource ProgressBar.Progress}"/><Setter Property="Background" Value="{StaticResource ProgressBar.Background}"/><Setter Property="BorderBrush" Value="{StaticResource ProgressBar.Border}"/><Setter Property="BorderThickness" Value="1"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type ProgressBar}"><Grid x:Name="TemplateRoot"><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualState x:Name="Determinate"/><VisualState x:Name="Indeterminate"><Storyboard RepeatBehavior="Forever"><DoubleAnimationUsingKeyFrames Storyboard.TargetName="Animation" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"><EasingDoubleKeyFrame KeyTime="0" Value="0.25"/><EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.25"/><EasingDoubleKeyFrame KeyTime="0:0:2" Value="0.25"/></DoubleAnimationUsingKeyFrames><PointAnimationUsingKeyFrames Storyboard.TargetName="Animation" Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)"><EasingPointKeyFrame KeyTime="0" Value="-0.5,0.5"/><EasingPointKeyFrame KeyTime="0:0:1" Value="0.5,0.5"/><EasingPointKeyFrame KeyTime="0:0:2" Value="1.5,0.5"/></PointAnimationUsingKeyFrames></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Border Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"CornerRadius="5"/><Rectangle x:Name="PART_Track"/><Grid x:Name="PART_Indicator" ClipToBounds="True" HorizontalAlignment="Left"><Border x:Name="Indicator" Background="Transparent"><Canvas><Canvas.LayoutTransform><RotateTransform Angle="90" /></Canvas.LayoutTransform><Path Data="M0 0A70 70 0 0 0 50 0A70 70 0 0 1 100 0L 100 100 0 100" Fill="Orange"><Path.RenderTransform><TranslateTransform X="-30" x:Name="tt" /></Path.RenderTransform></Path><Path Data="M0 0A70 70 0 0 0 50 0A70 70 0 0 1 100 0L 100 100 0 100" Fill="#9f90"><Path.RenderTransform><TranslateTransform X="0" x:Name="tt_2" /></Path.RenderTransform></Path><Path Data="M0 0A70 70 0 0 0 50 0A70 70 0 0 1 100 0L100 100 0 100" Fill="#9f80"><Path.RenderTransform><TranslateTransform X="-50" x:Name="tt_3" /></Path.RenderTransform></Path></Canvas></Border></Grid></Grid><ControlTemplate.Triggers><Trigger Property="Orientation" Value="Vertical"><Setter Property="LayoutTransform" TargetName="TemplateRoot"><Setter.Value><RotateTransform Angle="-90"/></Setter.Value></Setter></Trigger><Trigger Property="IsIndeterminate" Value="true"><Setter Property="Visibility" TargetName="Indicator" Value="Collapsed"/></Trigger><EventTrigger RoutedEvent="Loaded"><BeginStoryboard><Storyboard><DoubleAnimation RepeatBehavior="Forever" Duration="0:0:1" From="0" To="-50" Storyboard.TargetName="tt" Storyboard.TargetProperty="X"/><DoubleAnimation RepeatBehavior="Forever" BeginTime="0:0:0.3" Duration="0:0:1.3" From="0" To="-50" Storyboard.TargetName="tt_2" Storyboard.TargetProperty="X"/><DoubleAnimation RepeatBehavior="Forever" BeginTime="0:0:0.6" Duration="0:0:1.6" From="-50" To="0" Storyboard.TargetName="tt_3" Storyboard.TargetProperty="X"/></Storyboard></BeginStoryboard></EventTrigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style></Window.Resources><Grid><ProgressBar Style="{DynamicResource ProgressBarStyle}"BorderThickness="0"Height="200" Width="50" Orientation="Vertical" Value="450" Maximum="750" Minimum="0"/></Grid>
</Window>

想要弧度更大,修改对应的path即可:

UserControl 用户控件

案例:日期时间选择器 DatePicker

XAML代码:

<UserControl x:Class="XH.CustomLesson.Controls.DateTimePicker"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:XH.CustomLesson.Controls"mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="200"><UserControl.Resources><Style TargetType="RepeatButton" x:Key="ButtonUpStyle"><Setter Property="Height" Value="18"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="RepeatButton"><Border Background="Transparent"><Path Data="M838.116 732.779 877.7 693.195 511.979 327.549 146.3 693.195 185.883 732.779 512.003 406.652Z"Fill="#999" Stretch="Uniform" Margin="6"/></Border></ControlTemplate></Setter.Value></Setter></Style><Style TargetType="RepeatButton" x:Key="ButtonDownStyle"><Setter Property="Height" Value="18"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="RepeatButton"><Border Background="Transparent"><Path Data="M185.884 327.55 146.3 367.133 512.021 732.779 877.7 367.133 838.117 327.55 511.997 653.676Z"Fill="#999" Stretch="Uniform" Margin="6"/></Border></ControlTemplate></Setter.Value></Setter></Style><Style TargetType="Button" x:Key="ButtonCancelStyle"><Setter Property="Width" Value="24"/><Setter Property="Height" Value="24"/><Setter Property="HorizontalAlignment" Value="Right"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="Button"><Border Background="#EEE"><Path Data="M557.3 512l329.3-329.4a32 32 0 1 0-45.2-45.2L512 466.7 182.6 137.4a32 32 0 1 0-45.2 45.2L466.7 512 137.4 841.4a31.9 31.9 0 0 0 0 45.2 31.9 31.9 0 0 0 45.2 0L512 557.3l329.4 329.3a31.9 31.9 0 0 0 45.2 0 31.9 31.9 0 0 0 0-45.2z"Fill="#999" Stretch="Uniform" HorizontalAlignment="Center" Margin="5"/></Border></ControlTemplate></Setter.Value></Setter></Style><Style TargetType="Button" x:Key="ButtonAcceptStyle"><Setter Property="Width" Value="24"/><Setter Property="Height" Value="24"/><Setter Property="HorizontalAlignment" Value="Right"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="Button"><Border Background="#EEE"><Path Data="M892.064 261.888a31.936 31.936 0 0 0-45.216 1.472L421.664 717.248l-220.448-185.216a32 32 0 1 0-41.152 48.992l243.648 204.704a31.872 31.872 0 0 0 20.576 7.488 31.808 31.808 0 0 0 23.36-10.112L893.536 307.136a32 32 0 0 0-1.472-45.248z"Fill="#999" Stretch="Uniform" HorizontalAlignment="Center" Margin="5"/></Border></ControlTemplate></Setter.Value></Setter></Style><Style x:Key="CalendarCalendarDayButtonStyle1" TargetType="{x:Type CalendarDayButton}"><Setter Property="MinWidth" Value="10"/><Setter Property="MinHeight" Value="10"/><Setter Property="FontSize" Value="13"/><Setter Property="HorizontalContentAlignment" Value="Center"/><Setter Property="VerticalContentAlignment" Value="Center"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type CalendarDayButton}"><Grid><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualStateGroup.Transitions><VisualTransition GeneratedDuration="0:0:0.1"/></VisualStateGroup.Transitions><VisualState x:Name="Normal"/><VisualState x:Name="MouseOver"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="HighlightBackground" To="0.5" Storyboard.TargetProperty="Opacity"/></Storyboard></VisualState><VisualState x:Name="Pressed"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="HighlightBackground" To="0.5" Storyboard.TargetProperty="Opacity"/></Storyboard></VisualState><VisualState x:Name="Disabled"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="HighlightBackground" To="0" Storyboard.TargetProperty="Opacity"/><DoubleAnimation Duration="0" Storyboard.TargetName="NormalText" To=".35" Storyboard.TargetProperty="Opacity"/></Storyboard></VisualState></VisualStateGroup><VisualStateGroup x:Name="SelectionStates"><VisualStateGroup.Transitions><VisualTransition GeneratedDuration="0"/></VisualStateGroup.Transitions><VisualState x:Name="Unselected"/><VisualState x:Name="Selected"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="SelectedBackground" To=".75" Storyboard.TargetProperty="Opacity"/><ColorAnimation Duration="0" Storyboard.TargetName="NormalText" To="#FFFFFFFF" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"/></Storyboard></VisualState></VisualStateGroup><VisualStateGroup x:Name="CalendarButtonFocusStates"><VisualStateGroup.Transitions><VisualTransition GeneratedDuration="0"/></VisualStateGroup.Transitions><VisualState x:Name="CalendarButtonFocused"><Storyboard><ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="DayButtonFocusVisual" Storyboard.TargetProperty="Visibility"><DiscreteObjectKeyFrame KeyTime="0"><DiscreteObjectKeyFrame.Value><Visibility>Visible</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></VisualState><VisualState x:Name="CalendarButtonUnfocused"><Storyboard><ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="DayButtonFocusVisual" Storyboard.TargetProperty="Visibility"><DiscreteObjectKeyFrame KeyTime="0"><DiscreteObjectKeyFrame.Value><Visibility>Collapsed</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></VisualState></VisualStateGroup><VisualStateGroup x:Name="ActiveStates"><VisualStateGroup.Transitions><VisualTransition GeneratedDuration="0"/></VisualStateGroup.Transitions><VisualState x:Name="Active"/><VisualState x:Name="Inactive"><Storyboard><ColorAnimation Duration="0" Storyboard.TargetName="NormalText" To="#FF777777" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"/></Storyboard></VisualState></VisualStateGroup><VisualStateGroup x:Name="DayStates"><VisualStateGroup.Transitions><VisualTransition GeneratedDuration="0"/></VisualStateGroup.Transitions><VisualState x:Name="RegularDay"/><VisualState x:Name="Today"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="TodayBackground" To="1" Storyboard.TargetProperty="Opacity"/><ColorAnimation Duration="0" Storyboard.TargetName="NormalText" To="#FFFFFFFF" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"/></Storyboard></VisualState></VisualStateGroup><VisualStateGroup x:Name="BlackoutDayStates"><VisualStateGroup.Transitions><VisualTransition GeneratedDuration="0"/></VisualStateGroup.Transitions><VisualState x:Name="NormalDay"/><VisualState x:Name="BlackoutDay"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="Blackout" To=".2" Storyboard.TargetProperty="Opacity"/></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Rectangle x:Name="TodayBackground" Fill="Gray" Opacity="0" RadiusX="1" RadiusY="1"/><Rectangle x:Name="SelectedBackground" Fill="#409EFE" Opacity="0" RadiusX="1" RadiusY="1"/><Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/><Rectangle x:Name="HighlightBackground" Fill="#FFBADDE9" Opacity="0" RadiusX="1" RadiusY="1"/><ContentPresenter x:Name="NormalText" TextElement.Foreground="#FF333333" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="5,1,5,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/><Path x:Name="Blackout" Data="M8.1772461,11.029181 L10.433105,11.029181 L11.700684,12.801641 L12.973633,11.029181 L15.191895,11.029181 L12.844727,13.999395 L15.21875,17.060919 L12.962891,17.060919 L11.673828,15.256231 L10.352539,17.060919 L8.1396484,17.060919 L10.519043,14.042364 z" Fill="#FF000000" HorizontalAlignment="Stretch" Margin="3" Opacity="0" RenderTransformOrigin="0.5,0.5" Stretch="Fill" VerticalAlignment="Stretch"/><Rectangle x:Name="DayButtonFocusVisual" IsHitTestVisible="false" RadiusX="1" RadiusY="1" Stroke="#FF45D6FA" Visibility="Collapsed"/></Grid></ControlTemplate></Setter.Value></Setter></Style><Style x:Key="CalendarCalendarItemStyle1" TargetType="{x:Type CalendarItem}"><Setter Property="Margin" Value="0,3,0,3"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type CalendarItem}"><ControlTemplate.Resources><DataTemplate x:Key="{x:Static CalendarItem.DayTitleTemplateResourceKey}"><TextBlock Foreground="#FF333333" FontFamily="Verdana" FontWeight="Bold" FontSize="9.5" HorizontalAlignment="Center" Margin="0,6,0,6" Text="{Binding}" VerticalAlignment="Center"/></DataTemplate></ControlTemplate.Resources><Grid x:Name="PART_Root"><Grid.Resources><SolidColorBrush x:Key="DisabledColor" Color="#A5FFFFFF"/></Grid.Resources><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualState x:Name="Normal"/><VisualState x:Name="Disabled"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="PART_DisabledVisual" To="1" Storyboard.TargetProperty="Opacity"/></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1"><Border BorderBrush="#FFFFFFFF" BorderThickness="0" CornerRadius="1"><Grid><Grid.Resources><ControlTemplate x:Key="PreviousButtonTemplate" TargetType="{x:Type Button}"><Grid Cursor="Hand"><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualState x:Name="Normal"/><VisualState x:Name="MouseOver"><Storyboard><ColorAnimation Duration="0" Storyboard.TargetName="path" To="#FF73A9D8" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"/></Storyboard></VisualState><VisualState x:Name="Disabled"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="path" To=".5" Storyboard.TargetProperty="(Shape.Fill).(Brush.Opacity)"/></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Grid Background="Transparent"><Path x:Name="path" Data="M671.968176 911.99957c-12.287381 0-24.576482-4.67206-33.951566-14.047144L286.048434 545.984249c-18.751888-18.719204-18.751888-49.12028 0-67.872168L638.016611 126.111222c18.751888-18.751888 49.12028-18.751888 67.872168 0 18.751888 18.719204 18.751888 49.12028 0 67.872168l-318.016611 318.047574L705.888778 830.047574c18.751888 18.751888 18.751888 49.12028 0 67.872168C696.544658 907.32751 684.255557 911.99957 671.968176 911.99957z" Fill="#FF333333" HorizontalAlignment="Center"  VerticalAlignment="Center"Height="10" Width="6" Stretch="Fill" Margin="10,0"/></Grid></Grid></ControlTemplate><ControlTemplate x:Key="NextButtonTemplate" TargetType="{x:Type Button}"><Grid Cursor="Hand"><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualState x:Name="Normal"/><VisualState x:Name="MouseOver"><Storyboard><ColorAnimation Duration="0" Storyboard.TargetName="path" To="#FF73A9D8" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"/></Storyboard></VisualState><VisualState x:Name="Disabled"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="path" To=".5" Storyboard.TargetProperty="(Shape.Fill).(Brush.Opacity)"/></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Grid Background="Transparent"><Path x:Name="path" Data="M761.055557 532.128047c0.512619-0.992555 1.343475-1.823411 1.792447-2.848649 8.800538-18.304636 5.919204-40.703346-9.664077-55.424808L399.935923 139.743798c-19.264507-18.208305-49.631179-17.344765-67.872168 1.888778-18.208305 19.264507-17.375729 49.631179 1.888778 67.872168l316.960409 299.839269L335.199677 813.631716c-19.071845 18.399247-19.648112 48.767639-1.247144 67.872168 9.407768 9.791372 21.984142 14.688778 34.560516 14.688778 12.000108 0 24.000215-4.479398 33.311652-13.439914l350.048434-337.375729c0.672598-0.672598 0.927187-1.599785 1.599785-2.303346 0.512619-0.479935 1.056202-0.832576 1.567101-1.343475C757.759656 538.879828 759.199462 535.391265 761.055557 532.128047z" Fill="#FF333333" HorizontalAlignment="Right" VerticalAlignment="Center" Height="10" Stretch="Fill" Width="6" Margin="10,0"/></Grid></Grid></ControlTemplate><ControlTemplate x:Key="HeaderButtonTemplate" TargetType="{x:Type Button}"><Grid Cursor="Hand" Background="Transparent"><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualState x:Name="Normal"/><VisualState x:Name="MouseOver"><Storyboard><ColorAnimation Duration="0" Storyboard.TargetName="buttonContent" To="#FF73A9D8" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)"/></Storyboard></VisualState><VisualState x:Name="Disabled"><Storyboard><DoubleAnimation Duration="0" Storyboard.TargetName="buttonContent" To=".5" Storyboard.TargetProperty="Opacity"/></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><ContentPresenter x:Name="buttonContent" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" TextElement.Foreground="#FF333333"HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1,9" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/></Grid></ControlTemplate></Grid.Resources><Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="auto"/><ColumnDefinition Width="auto"/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><Button x:Name="PART_HeaderButton" Grid.Column="0" Focusable="False" FontWeight="Bold" FontSize="14" HorizontalAlignment="Left" VerticalContentAlignment="Center"Grid.Row="0" Template="{StaticResource HeaderButtonTemplate}" VerticalAlignment="Center" Margin="10,5"/><Button x:Name="PART_PreviousButton" Grid.Column="1" Focusable="False" HorizontalAlignment="Center" Template="{StaticResource PreviousButtonTemplate}" Margin="0,5"/><Button x:Name="PART_NextButton" Grid.Column="2" Focusable="False" HorizontalAlignment="Right" Template="{StaticResource NextButtonTemplate}" Margin="0,5"/><Grid x:Name="PART_MonthView" Grid.ColumnSpan="3" HorizontalAlignment="Center" Margin="6,-1,6,6" Grid.Row="1" Visibility="Visible"><Grid.ColumnDefinitions><ColumnDefinition Width="30"/><ColumnDefinition Width="30"/><ColumnDefinition Width="30"/><ColumnDefinition Width="30"/><ColumnDefinition Width="30"/><ColumnDefinition Width="30"/><ColumnDefinition Width="30"/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="30"/><RowDefinition Height="30"/><RowDefinition Height="30"/><RowDefinition Height="30"/><RowDefinition Height="30"/><RowDefinition Height="30"/></Grid.RowDefinitions></Grid><Grid x:Name="PART_YearView" Grid.ColumnSpan="3" HorizontalAlignment="Center" Margin="6,-3,7,6" Grid.Row="1" Visibility="Hidden"><Grid.ColumnDefinitions><ColumnDefinition Width="50"/><ColumnDefinition Width="50"/><ColumnDefinition Width="50"/><ColumnDefinition Width="50"/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height="50"/><RowDefinition Height="50"/><RowDefinition Height="50"/></Grid.RowDefinitions></Grid></Grid></Border></Border><Rectangle x:Name="PART_DisabledVisual" Fill="{StaticResource DisabledColor}" Opacity="0" RadiusX="2" RadiusY="2" Stroke="{StaticResource DisabledColor}" Stretch="Fill" StrokeThickness="1" Visibility="Collapsed"/></Grid><ControlTemplate.Triggers><Trigger Property="IsEnabled" Value="False"><Setter Property="Visibility" TargetName="PART_DisabledVisual" Value="Visible"/></Trigger><DataTrigger Binding="{Binding DisplayMode, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Calendar}}}" Value="Year"><Setter Property="Visibility" TargetName="PART_MonthView" Value="Hidden"/><Setter Property="Visibility" TargetName="PART_YearView" Value="Visible"/></DataTrigger><DataTrigger Binding="{Binding DisplayMode, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Calendar}}}" Value="Decade"><Setter Property="Visibility" TargetName="PART_MonthView" Value="Hidden"/><Setter Property="Visibility" TargetName="PART_YearView" Value="Visible"/></DataTrigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style></UserControl.Resources><Grid><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition Width="30" /></Grid.ColumnDefinitions><TextBox Grid.Column="0" IsReadOnly="True" Name="textBox" VerticalContentAlignment="Center"Text="{Binding CurrentDateTime,RelativeSource={RelativeSource AncestorType=UserControl},StringFormat={}{0:yyyy-MM-dd HH:mm:ss}}"/><ToggleButton Grid.Column="1" x:Name="toggleButton" Background="AliceBlue"><ToggleButton.Content><local:DateTimePickerIcon /></ToggleButton.Content></ToggleButton><!--AllowsTransparency:控件包含透明内容--><Popup StaysOpen="False" IsOpen="{Binding ElementName=toggleButton,Path=IsChecked}" PlacementTarget="{Binding ElementName=textBox}" AllowsTransparency="True"HorizontalOffset="0" Name="popup"><Border Background="#F7F9FA" Width="auto" Height="auto" Margin="3"><Border.Effect><DropShadowEffect BlurRadius="10" Color="Gray" ShadowDepth="0" Opacity="0.3" /></Border.Effect><Grid><Grid.RowDefinitions><RowDefinition Height="auto"/><RowDefinition Height="auto"/></Grid.RowDefinitions><Calendar x:Name="calendar" BorderThickness="0"Background="Transparent"CalendarItemStyle="{StaticResource CalendarCalendarItemStyle1}" CalendarDayButtonStyle="{StaticResource CalendarCalendarDayButtonStyle1}"/><Grid Grid.Row="1" Margin="10,5,10,10"><Grid.RowDefinitions><RowDefinition/><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="auto"/><ColumnDefinition/><ColumnDefinition Width="auto"/><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><RepeatButton Content="△" Style="{StaticResource ButtonUpStyle}" Click="BtnHourUp_Click"/><RepeatButton Content="△" Style="{StaticResource ButtonUpStyle}" Grid.Column="2" Click="BtnMinuteUp_Click"/><RepeatButton Content="△" Style="{StaticResource ButtonUpStyle}" Grid.Column="4" Click="BtnSecondUp_Click"/><RepeatButton Content="▽" Style="{StaticResource ButtonDownStyle}" Grid.Row="2" Click="BtnHourDown_Click"/><RepeatButton Content="▽" Style="{StaticResource ButtonDownStyle}" Grid.Row="2" Grid.Column="2" Click="BtnMinuteDown_Click"/><RepeatButton Content="▽" Style="{StaticResource ButtonDownStyle}" Grid.Row="2" Grid.Column="4" Click="BtnSecondDown_Click"/><TextBox Grid.Row="1" Name="tb_hour" TextChanged="tb_hour_TextChanged" Text="{Binding HourInt,RelativeSource={RelativeSource AncestorType=UserControl}}" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="24" Margin="3"/><TextBlock Text=":" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="3"/><TextBox Grid.Row="1" Grid.Column="2" Name="tb_minute" TextChanged="tb_minute_TextChanged" Text="{Binding MinuteInt,RelativeSource={RelativeSource AncestorType=UserControl}}" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="24" Margin="3"/><TextBlock Text=":" Grid.Row="1" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="3"/><TextBox Grid.Row="1" Grid.Column="4" Name="tb_second" TextChanged="tb_second_TextChanged"  Text="{Binding SecondInt,RelativeSource={RelativeSource AncestorType=UserControl}}"VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="24" Margin="3"/><Button Content="×" Style="{StaticResource ButtonCancelStyle}" Click="Button_Click_1" BorderThickness="0" Grid.Row="1" Grid.Column="5" /><Button Content="√" Style="{StaticResource ButtonAcceptStyle}" BorderThickness="0" Grid.Row="1" Grid.Column="6" Click="Button_Click"/></Grid></Grid></Border></Popup></Grid>
</UserControl>

图标XAML:

<UserControl x:Class="XH.CustomLesson.Controls.DateTimePickerIcon"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:XH.CustomLesson.Controls"mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"><Viewbox><Grid><Path Data="M47.93344 167.1936h-0.98816v248.83712h933.248V355.31264c0.04096-1.00352 0.29696-1.9456 0.29696-2.95936V177.00864c0-1.01376-0.256-1.95584-0.29696-2.95936v-6.85568h-0.6912c-4.80256-33.50016-33.3312-59.3408-68.16256-59.3408H116.096c-34.82624 0.00512-63.36 25.84064-68.16256 59.3408z" Fill="#F38181" /><Path Data="M979.5072 856.8064h0.98816V404.9152H47.24224v60.71296c-0.04096 1.00352-0.29696 1.9456-0.29696 2.95424v378.40384c0 1.01376 0.256 1.95584 0.29696 2.95424v6.85568h0.6912c4.80256 33.50016 33.3312 59.3408 68.16256 59.3408h795.24352c34.83136 0.00512 63.36512-25.8304 68.16768-59.33056z" Fill="#E6E4E2" /><Path Data="M489.54368 646.2208c-4.83328 5.80608-9.02144 9.98912-19.98336 19.65568-6.12352 5.80608-12.5696 11.60704-18.688 17.40288-19.65568 18.37056-23.20896 22.89152-27.71456 38.03136h77.6704v43.19232H365.4656v-18.37056c0-25.13408 6.44096-44.14976 23.5264-62.848 11.92448-13.2096 25.7792-24.81152 38.99904-37.05856 19.01568-17.40288 22.88128-22.23616 22.88128-37.70368v-16.75776c0-4.51584 0-20.95104-17.40288-20.62848-11.60704 0-15.79008 6.76352-17.40288 11.60192-0.64512 1.93536-0.96768 4.51072-0.96768 9.344v31.90784h-47.69792v-29.32736c0-17.0752 0.96768-32.22528 14.50496-45.11744 9.02144-8.704 24.81664-16.75776 52.85376-16.75776 26.42944 0 41.25184 8.05888 50.2784 15.47264 2.2528 1.93024 9.02144 7.7312 12.5696 16.4352 2.89792 7.0912 3.8656 14.8224 3.8656 30.61248-0.00512 19.33312 0.64 34.79552-11.9296 50.91328zM654.87872 742.90688c-3.2256 5.16096-8.05888 9.02656-9.67168 10.31168-18.688 15.47264-42.86464 15.15008-50.2784 15.15008-25.45152 0-40.92928-8.05888-49.3056-15.15008-6.44608-5.4784-10.31168-11.60192-13.21984-19.33312-3.8656-11.27936-3.8656-22.56384-3.8656-34.16064v-103.45984c0-4.19328 0-8.704 0.32768-12.89216 0.31744-5.15072 1.28512-19.33312 11.60192-31.2576 8.704-10.63936 23.84896-19.01568 53.17632-19.01568 23.20896 0 53.17632 5.4784 63.16544 29.97248 2.90816 6.76352 3.87584 12.24192 3.87584 26.42944v15.79008h-47.05792v-11.92448c0-4.51584 0.64512-19.66592-16.75776-19.66592-19.33824 0-19.01568 16.11776-19.01568 21.59616v42.21952c6.44608-6.44608 14.50496-14.8224 34.80576-14.8224 27.71456 0 41.57952 13.85472 46.09024 24.81152 2.2528 5.80608 3.2256 9.67168 3.2256 20.95104v37.38624c-0.00512 12.89728 0.32256 25.78432-7.09632 37.06368z m-41.5744-65.41824c0-4.83328 1.6128-23.53152-17.72032-23.53152-4.83328 0-8.38656 0.65024-11.92448 3.54816-6.44608 5.4784-6.12864 13.85472-6.12864 21.26848v27.71456c0 5.80608-1.28512 21.91872 18.37056 21.91872 6.12352 0 9.02656-1.6128 11.60704-3.54816 5.79584-4.83328 6.12352-12.89216 6.12352-27.39712-0.00512-6.43584-0.00512-13.2096-0.32768-19.97312z" Fill="#5B5144" /><Path Data="M455.91552 325.95456V239.50848l-18.54464 86.44608h-25.52832l-18.55488-86.44608v86.44608h-25.35424V205.81376h38.79936l17.87392 88.14592 17.86368-88.14592h39.31136v120.1408h-25.86624zM550.05696 325.95456l-4.08064-27.40224h-22.29248l-4.25472 27.40224H491.008l24.33536-120.1408h38.79936l24.32512 120.1408h-28.41088z m-14.97088-101.08416l-8.16128 53.43744h16.16384l-8.00256-53.43744zM629.56032 283.75552v42.19904h-28.42112v-42.19904l-28.59008-77.93664h28.59008l14.62784 53.0944 14.63808-53.0944h29.10208l-29.94688 77.93664z" Fill="#FFFFFF" /></Grid></Viewbox>
</UserControl>

效果:

C#逻辑代码:

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;namespace XH.CustomLesson.Controls
{/// <summary>/// DateTimePicker.xaml 的交互逻辑/// </summary>public partial class DateTimePicker : UserControl, INotifyPropertyChanged{public event PropertyChangedEventHandler? PropertyChanged;public event EventHandler<DateTime> SeletedChanged;private int hourInt = DateTime.Now.Hour;public int HourInt{get { return hourInt; }set{hourInt = value;PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("HourInt"));}}private int minuteInt = DateTime.Now.Minute;public int MinuteInt{get { return minuteInt; }set{minuteInt = value;PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MinuteInt"));}}private int secondInt = DateTime.Now.Second;public int SecondInt{get { return secondInt; }set{secondInt = value;PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SecondInt"));}}public DateTime CurrentDateTime{get { return (DateTime)GetValue(CurrentDateTimeProperty); }set{SetValue(CurrentDateTimeProperty, value);}}// Using a DependencyProperty as the backing store for CurrentDateTime.  This enables animation, styling, binding, etc...public static readonly DependencyProperty CurrentDateTimeProperty =DependencyProperty.Register("CurrentDateTime", typeof(DateTime), typeof(DateTimePicker), new PropertyMetadata(DateTime.Now,new PropertyChangedCallback(OnCurentDateTimeChanged)));private static void OnCurentDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){(d as DateTimePicker).Refresh();}private void Refresh(){this.calendar.SelectedDate = this.CurrentDateTime; this.calendar.DisplayDate = this.CurrentDateTime; // 确保日历显示正确的月份HourInt = this.CurrentDateTime.Hour;MinuteInt = this.CurrentDateTime.Minute;SecondInt = this.CurrentDateTime.Second;}public DateTimePicker(){InitializeComponent();}private void Button_Click(object sender, RoutedEventArgs e){// 把日历和时间合并int year = calendar.SelectedDate.Value.Year;int month = calendar.SelectedDate.Value.Month;int day = calendar.SelectedDate.Value.Day;int.TryParse(this.tb_hour.Text.Trim(), out int hour);int.TryParse(this.tb_minute.Text.Trim(), out int minute);int.TryParse(this.tb_second.Text.Trim(), out int second);CurrentDateTime = new DateTime(year, month, day, hour, minute, second);this.popup.IsOpen = false;SeletedChanged?.Invoke(this, CurrentDateTime);}private void BtnHourUp_Click(object sender, RoutedEventArgs e){var hour_str = string.IsNullOrEmpty(this.tb_hour.Text) ? "0" : this.tb_hour.Text;HourInt = int.Parse(hour_str);HourInt++;HourInt %= 24;//this.tb_hour.Text = hourInt.ToString();}private void BtnHourDown_Click(object sender, RoutedEventArgs e){var hour_str = string.IsNullOrEmpty(this.tb_hour.Text) ? "0" : this.tb_hour.Text;HourInt = int.Parse(hour_str);HourInt--;HourInt = (HourInt + 24) % 24;}private void BtnMinuteDown_Click(object sender, RoutedEventArgs e){var minute_str = string.IsNullOrEmpty(this.tb_minute.Text) ? "0" : this.tb_minute.Text;MinuteInt = int.Parse(minute_str);MinuteInt--;MinuteInt = (MinuteInt + 60) % 60;}private void BtnMinuteUp_Click(object sender, RoutedEventArgs e){var minute_str = string.IsNullOrEmpty(this.tb_minute.Text) ? "0" : this.tb_minute.Text;MinuteInt = int.Parse(minute_str);MinuteInt++;MinuteInt %= 60;}private void BtnSecondUp_Click(object sender, RoutedEventArgs e){var second_str = string.IsNullOrEmpty(this.tb_second.Text) ? "0" : this.tb_second.Text;SecondInt = int.Parse(second_str);SecondInt++;SecondInt %= 60;}private void BtnSecondDown_Click(object sender, RoutedEventArgs e){var second_str = string.IsNullOrEmpty(this.tb_second.Text) ? "0" : this.tb_second.Text;SecondInt = int.Parse(second_str);SecondInt--;SecondInt = (SecondInt + 60) % 60;}private void tb_hour_TextChanged(object sender, TextChangedEventArgs e){HourInt = int.Parse(tb_hour.Text);if (HourInt >= 24 || HourInt < 0)HourInt = 0;}private void tb_minute_TextChanged(object sender, TextChangedEventArgs e){MinuteInt = int.Parse(tb_minute.Text);if (MinuteInt >= 60 || MinuteInt < 0)MinuteInt = 0;}private void tb_second_TextChanged(object sender, TextChangedEventArgs e){SecondInt = int.Parse(tb_second.Text);if (SecondInt >= 60 || SecondInt < 0)SecondInt = 0;}private void Button_Click_1(object sender, RoutedEventArgs e){this.popup.IsOpen = false;}}
}

使用自定义控件代码:

<c:DateTimePicker HorizontalAlignment="Center"SeletedChanged="DateTimePicker_SeletedChanged" VerticalAlignment="Top"Width="200" CurrentDateTime="{Binding Current,RelativeSource={RelativeSource AncestorType=Window}}" />

CustomControl 自定义控件

案例:自定义数值控件

XAML代码:

<ResourceDictionaryxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:c="clr-namespace:XH.CustomLesson.Controls"xmlns:local="clr-namespace:XH.CustomLesson"><Style TargetType="{x:Type c:NumericBox}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type c:NumericBox}"><Border Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"CornerRadius="5"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition Width="30"/></Grid.ColumnDefinitions><TextBox Name="PART_Value" VerticalAlignment="Center" Margin="3,5" BorderThickness="0"Foreground="{TemplateBinding Foreground}"/><UniformGrid Rows="2" Grid.Column="1"><RepeatButton Content="+" Background="Transparent" BorderThickness="1,0,0,0" Name="PART_IncreaseButton"BorderBrush="#DDD"/><RepeatButton Content="-" Background="Transparent" BorderThickness="1,1,0,0" Name="PART_DecreaseButton"BorderBrush="#DDD"/></UniformGrid></Grid></Border></ControlTemplate></Setter.Value></Setter></Style></ResourceDictionary>

C#逻辑代码:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;namespace XH.CustomLesson.Controls
{/// <summary>/// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。////// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根/// 元素中://////     xmlns:MyNamespace="clr-namespace:XH.CustomLesson.Controls"///////// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根/// 元素中://////     xmlns:MyNamespace="clr-namespace:XH.CustomLesson.Controls;assembly=XH.CustomLesson.Controls"////// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,/// 并重新生成以避免编译错误://////     在解决方案资源管理器中右击目标项目,然后依次单击///     “添加引用”->“项目”->[浏览查找并选择此项目]///////// 步骤 2)/// 继续操作并在 XAML 文件中使用控件。//////     <MyNamespace:NumericBox/>////// </summary>/// [TemplatePart(Name = "PART_Vlaue", Type = typeof(TextBox))]public class NumericBox : Control{TextBox txtValue = new TextBox();public int Value{get { return (int)GetValue(ValueProperty); }set { SetValue(ValueProperty, value); }}// Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...public static readonly DependencyProperty ValueProperty =DependencyProperty.Register("Value",typeof(int),typeof(NumericBox),new PropertyMetadata(0, new PropertyChangedCallback(OnValueChanged)));private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var nb = (d as NumericBox);if (nb.txtValue == null) return;if (nb.Value > 30)nb.txtValue.Foreground = Brushes.Red;else if(nb.Value >0 && nb.Value < 30)nb.txtValue.Foreground = Brushes.Black;else if (nb.Value < 0)nb.txtValue.Foreground = Brushes.Orange;}static NumericBox(){DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericBox), new FrameworkPropertyMetadata(typeof(NumericBox)));}// 应用模板public override void OnApplyTemplate(){base.OnApplyTemplate();// 获取模板中的事件txtValue = base.GetTemplateChild("PART_Value") as TextBox;var btnIncrease = base.GetTemplateChild("PART_IncreaseButton") as RepeatButton;var btnDecrease = base.GetTemplateChild("PART_DecreaseButton") as RepeatButton;if (txtValue != null){// 建立对象中的Value属性和模板中的TextBox控件的Text属性的绑定Binding binding = new Binding("Value");binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;binding.RelativeSource = new RelativeSource() { AncestorType = typeof(NumericBox), Mode = RelativeSourceMode.FindAncestor };txtValue.SetBinding(TextBox.TextProperty, binding);}if (btnIncrease != null)btnIncrease.Click += BtnIncrease_Click;if (btnDecrease != null)btnDecrease.Click += BtnDecrease_Click;}private void BtnDecrease_Click(object sender, RoutedEventArgs e){this.Value--;}private void BtnIncrease_Click(object sender, RoutedEventArgs e){this.Value++;}}
}

使用部分代码:

<c:NumericBox VerticalAlignment="Bottom" Width="200" BorderBrush="#ddd"BorderThickness="1" Margin="20"/>

UserControl与CustomControl区别

  1. 自定义控件:注重控件对象的功能,必须遵守WPF的控件规则
    • 完全自己实现一个控件 继承现有控件进行功能扩展,并且添加新功能 WPF的控件要求
    • 后台代码(控制逻辑)和Generic.Xaml(样式 模板)进行组合
    • 支持模板重写
    • 继承Control
  1. 用户控件:注重复合控件组合使用,非常灵活,可以根据控件开发人员自己的意愿进行功能处理
    • 多个现有控件的集合,组成一个可复用的控件组
    • XAML和后台代码组成 绑定非常紧密
    • 不支持模板重写、样式
    • 继承UserControl

案例

工业仪表

XAML代码:

<UserControl x:Class="XH.CustomLesson.Controls.Instrument"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:XH.CustomLesson.Controls"mc:Ignorable="d" d:DesignHeight="400" d:DesignWidth="400"><Grid><Border Name="border" Background="#FF030A28"><Border.Effect><DropShadowEffect BlurRadius="20" Opacity="0.5"  ShadowDepth="0" Direction="0" Color="#FF3CAFFF"/></Border.Effect><Grid><Path Stroke="#333CAFFF" StrokeThickness="10" Name="circle" RenderTransformOrigin="0.5,0.5"><Path.RenderTransform><RotateTransform Angle="-45"/></Path.RenderTransform></Path><Canvas x:Name="canvasPlate" RenderTransformOrigin="0.5,0.5" Margin="0"><Canvas.RenderTransform><RotateTransform Angle="-45"/></Canvas.RenderTransform></Canvas><Path Data="" Name="plateBorder" Stroke="#FF3CAFFF" StrokeThickness="3" RenderTransformOrigin="0.5,0.5"Width="{Binding ElementName=border,Path=Width}"Height="{Binding ElementName=border,Path=Height}"><Path.RenderTransform><RotateTransform Angle="-45"/></Path.RenderTransform></Path><Path Data="M200 205,360 200,200 195,195 200 200 205" Fill="Red" RenderTransformOrigin="0.5,0.5" Name="pointer"><Path.RenderTransform><RotateTransform Angle="135" x:Name="rtPointer"/></Path.RenderTransform></Path><Border Width="60" Height="60" CornerRadius="30" Background="#FF030A28"><Border.Effect><DropShadowEffect BlurRadius="20" Opacity="0.3" ShadowDepth="0" Direction="0" Color="#FF3CAFFF"/></Border.Effect><StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"><TextBlock Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"><Run Text="{Binding Value,RelativeSource={RelativeSource AncestorType=UserControl}}"FontSize="20"/><Run Text="m³/H" FontSize="8"/></TextBlock><TextBlock Text="NATURAL GAS" Foreground="#FF8CBEF0" VerticalAlignment="Center" HorizontalAlignment="Center"FontSize="6"/></StackPanel></Border></Grid></Border></Grid>
</UserControl>

C#代码:

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;namespace XH.CustomLesson.Controls
{/// <summary>/// Instrument.xaml 的交互逻辑/// </summary>public partial class Instrument : UserControl{// 当前值 public double Value{get { return (double)GetValue(ValueProperty); }set { SetValue(ValueProperty, value); }}public static readonly DependencyProperty ValueProperty =DependencyProperty.Register("Value", typeof(double), typeof(Instrument),new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));// 最小刻度public double Minimum{get { return (double)GetValue(MinimumProperty); }set { SetValue(MinimumProperty, value); }}public static readonly DependencyProperty MinimumProperty =DependencyProperty.Register("Minimum", typeof(double), typeof(Instrument),new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));// 最大刻度public double Maximum{get { return (double)GetValue(MaximumProperty); }set { SetValue(MaximumProperty, value); }}public static readonly DependencyProperty MaximumProperty =DependencyProperty.Register("Maximum", typeof(double), typeof(Instrument),new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));间隔//public double Interval//{//    get { return (double)GetValue(IntervalProperty); }//    set { SetValue(IntervalProperty, value); }//}//public static readonly DependencyProperty IntervalProperty =//    DependencyProperty.Register("Interval", typeof(double), typeof(Instrument), new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));// 大刻度的个数public int ScaleCount{get { return (int)GetValue(ScaleCountProperty); }set { SetValue(ScaleCountProperty, value); }}public static readonly DependencyProperty ScaleCountProperty =DependencyProperty.Register("ScaleCount", typeof(int), typeof(Instrument),new PropertyMetadata(default(int), new PropertyChangedCallback(OnPropertyChanged)));// 刻度的厚度public double ScaleThickness{get { return (double)GetValue(ScaleThicknessProperty); }set { SetValue(ScaleThicknessProperty, value); }}public static readonly DependencyProperty ScaleThicknessProperty =DependencyProperty.Register("ScaleThickness", typeof(double), typeof(Instrument),new PropertyMetadata(default(double), new PropertyChangedCallback(OnPropertyChanged)));// 刻度的颜色public Brush ScaleBrush{get { return (Brush)GetValue(ScaleBrushProperty); }set { SetValue(ScaleBrushProperty, value); }}public static readonly DependencyProperty ScaleBrushProperty =DependencyProperty.Register("ScaleBrush", typeof(Brush), typeof(Instrument),new PropertyMetadata(default(Brush), new PropertyChangedCallback(OnPropertyChanged)));// 指针的颜色public Brush PointerBrush{get { return (Brush)GetValue(PointerBrushProperty); }set { SetValue(PointerBrushProperty, value); }}public static readonly DependencyProperty PointerBrushProperty =DependencyProperty.Register("PointerBrush", typeof(Brush), typeof(Instrument),new PropertyMetadata(default(Brush), new PropertyChangedCallback(OnPropertyChanged)));// 刻度字体大小 public new double FontSize{get { return (double)GetValue(FontSizeProperty); }set { SetValue(FontSizeProperty, value); }}public static new readonly DependencyProperty FontSizeProperty =DependencyProperty.Register("FontSize", typeof(double), typeof(Instrument),new PropertyMetadata(9.0, new PropertyChangedCallback(OnPropertyChanged)));public Instrument(){InitializeComponent();SetCurrentValue(MinimumProperty, 0d);SetCurrentValue(MaximumProperty, 100d);//SetCurrentValue(IntervalProperty, 10d);SizeChanged += (se, ev) => { Refresh(); };}static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)=> (d as Instrument).Refresh();private void Refresh(){// 圆this.border.Width = Math.Min(RenderSize.Width, RenderSize.Height);this.border.Height = Math.Min(RenderSize.Width, RenderSize.Height);this.border.CornerRadius = new CornerRadius(this.border.Width / 2);// 半径double radius = this.border.Width / 2;this.canvasPlate.Children.Clear();if (ScaleCount <= 0 || radius <= 0) return;// 画边string borderPathData = $"M4,{radius}A{radius - 4} {radius - 4} 0 1 1 {radius} {this.border.Height - 4}";// 将字符串转换成Geometryvar converter = TypeDescriptor.GetConverter(typeof(Geometry));//this.plateBorder.Data = (Geometry)converter.ConvertFrom(borderPathData);this.plateBorder.Data = PathGeometry.Parse(borderPathData);// 计算刻度double label = this.Minimum;double interval = 0;double step = 270.0 / (this.Maximum - this.Minimum);// 计算小刻度for (int i = 0; i < this.Maximum - this.Minimum; i++){//添加刻度线Line lineScale = new Line();// 角度需要转换弧度lineScale.X1 = radius - (radius - 13) * Math.Cos(step * i * Math.PI / 180);lineScale.Y1 = radius - (radius - 13) * Math.Sin(step * i * Math.PI / 180);lineScale.X2 = radius - (radius - 8) * Math.Cos(step * i * Math.PI / 180);lineScale.Y2 = radius - (radius - 8) * Math.Sin(step * i * Math.PI / 180);lineScale.Stroke = this.ScaleBrush;lineScale.StrokeThickness = this.ScaleThickness;this.canvasPlate.Children.Add(lineScale);}// 计算大刻度do{//添加刻度线Line lineScale = new Line();lineScale.X1 = radius - (radius - 20) * Math.Cos(interval * step * Math.PI / 180);lineScale.Y1 = radius - (radius - 20) * Math.Sin(interval * step * Math.PI / 180);lineScale.X2 = radius - (radius - 8) * Math.Cos(interval * step * Math.PI / 180);lineScale.Y2 = radius - (radius - 8) * Math.Sin(interval * step * Math.PI / 180);lineScale.Stroke = this.ScaleBrush;lineScale.StrokeThickness = this.ScaleThickness;this.canvasPlate.Children.Add(lineScale);TextBlock txtScale = new TextBlock();txtScale.Text = label.ToString("0");txtScale.Width = 34;txtScale.TextAlignment = TextAlignment.Center;txtScale.Foreground = new SolidColorBrush(Colors.White);txtScale.RenderTransform = new RotateTransform() { Angle = 45, CenterX = 17, CenterY = 8 };txtScale.FontSize = this.FontSize;Canvas.SetLeft(txtScale, radius - (radius - 34) * Math.Cos(interval * step * Math.PI / 180) - 17);Canvas.SetTop(txtScale, radius - (radius - 34) * Math.Sin(interval * step * Math.PI / 180) - 8);this.canvasPlate.Children.Add(txtScale);interval += (this.Maximum - this.Minimum) / this.ScaleCount;label += (this.Maximum - this.Minimum) / this.ScaleCount;} while (interval <= this.Maximum - this.Minimum);// 修改指针string sData = "M{0} {1},{2} {0},{0} {3},{3} {0},{0} {1}";sData = string.Format(sData, radius, radius + 2, this.border.Width - radius / 10, radius - 4);converter = TypeDescriptor.GetConverter(typeof(Geometry));this.pointer.Data = (Geometry)converter.ConvertFrom(sData);this.pointer.Fill = this.PointerBrush;//DoubleAnimation da = new DoubleAnimation((Value - Minimum) * step + 135, new Duration(TimeSpan.FromMilliseconds(200)));//this.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da);this.rtPointer.Angle = (Value - Minimum) * step + 135;// 修改圆  M100 200 A100 100 0 1 1 200 300// 厚度double thickness = radius / 2;this.circle.StrokeThickness = thickness;double startX = radius - thickness / 2;double startY = radius;double endX = radius - (radius - thickness / 2) * Math.Cos((Value - Minimum) * step * Math.PI / 180);double endY = radius - (radius - thickness / 2) * Math.Sin((Value - Minimum) * step * Math.PI / 180);int isLarge = 1;if ((Value - Minimum) * step < 180)isLarge = 0;sData = $"M{startX},{startY}A{radius / 2} {radius / 2} 0 1 1 {endX} {endY}";sData = $"M{thickness / 2},{radius}A{radius - thickness / 2} {radius - thickness / 2} 0 {isLarge} 1 {endX} {endY}";//sData = string.Format(sData, radius * 0.5, radius, radius * 1.5);this.circle.Data = (Geometry)converter.ConvertFrom(sData);this.circle.Visibility = Visibility.Visible;if (this.border.Width < 200)this.circle.Visibility = Visibility.Collapsed;}}
}

使用代码:

<c:Instrument Height="200" Width="200" Maximum="100" Value="25" Minimum="0"ScaleCount="10" ScaleThickness="0.5" ScaleBrush="White"PointerBrush="Red" FontSize="9"/>

效果展示:

各种常见开关

自定义控件:代码:

<Style TargetType="{x:Type c:Switch}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type c:Switch}"><Grid><Border Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}" CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"Visibility="Collapsed" Name="dropdown" Margin="-23"><Border.Background><RadialGradientBrush><GradientStop Color="Transparent" Offset="1"/><GradientStop Color="#5500D787" Offset="0.7"/><GradientStop Color="Transparent" Offset="0.59"/></RadialGradientBrush></Border.Background></Border><Border Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"BorderBrush="DarkGreen" BorderThickness="5"CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"Background="Gray" Name="bor"><Border Background="#FF00C88C" Margin="2" Name="bor1"Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}" CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"/></Border></Grid><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Trigger.EnterActions><BeginStoryboard><Storyboard ><ColorAnimation To="White" Duration="0:0:0.5"Storyboard.TargetName="bor1"Storyboard.TargetProperty="Background.Color"/><ColorAnimation To="#FF32FAC8" Duration="0:0:0.5"Storyboard.TargetName="bor"Storyboard.TargetProperty="BorderBrush.Color"/><ObjectAnimationUsingKeyFrames Storyboard.TargetName="dropdown"Storyboard.TargetProperty="Visibility"><DiscreteObjectKeyFrame KeyTime="0:0:0.3"><DiscreteObjectKeyFrame.Value><Visibility>Visible</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></BeginStoryboard></Trigger.EnterActions><Trigger.ExitActions><BeginStoryboard><Storyboard ><ColorAnimation Storyboard.TargetName="bor1"Storyboard.TargetProperty="Background.Color"/><ColorAnimation Storyboard.TargetName="bor"Storyboard.TargetProperty="BorderBrush.Color"/><ObjectAnimationUsingKeyFrames Storyboard.TargetName="dropdown"Storyboard.TargetProperty="Visibility"><DiscreteObjectKeyFrame KeyTime="0:0:0.3"><DiscreteObjectKeyFrame.Value><Visibility>Collapsed</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></BeginStoryboard></Trigger.ExitActions></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>

C#代码:

public class Switch :ToggleButton 
{static Switch(){DefaultStyleKeyProperty.OverrideMetadata(typeof(Switch), new FrameworkPropertyMetadata(typeof(Switch)));}
}

使用场景:

<UniformGrid Rows="1" HorizontalAlignment="Center"><c:Switch Height="60" IsChecked="False" Margin="0 0 20 0" /><c:Switch Height="60" IsChecked="True" Margin="0 0 20 0"/><c:Switch Height="60" IsChecked="False" Style="{StaticResource RotarySwitchStyle}" Margin="0 0 20 0"/><c:Switch Height="60" IsChecked="True" Style="{StaticResource RotarySwitchStyle}" Margin="0 0 20 0"/><c:Switch Height="60" IsChecked="False" Style="{StaticResource ButtonSwitchStyle}" Margin="0 0 20 0"/><c:Switch Height="60" IsChecked="True" Style="{StaticResource ButtonSwitchStyle}" Margin="0 0 20 0"/><ToggleButton Height="60" Style="{StaticResource Button2SwitchStyle}" Margin="0 0 20 0"/>
</UniformGrid>

其他按钮自定义样式:其实都是ToggleButton的自定义模板

<Style TargetType="c:Switch" x:Key="RotarySwitchStyle"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="c:Switch"><Grid><Border Background="#FF3C3C3C" Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"/><Border BorderBrush="Black" BorderThickness="1" Margin="8"Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"CornerRadius="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}"/><Border Width="12" CornerRadius="6" Background="#FF3C3C3C"RenderTransformOrigin="0.5,0.5"><Border.Effect><DropShadowEffect BlurRadius="14" Color="Black" Opacity="0.9" Direction="0"ShadowDepth="0"/></Border.Effect><Border.RenderTransform><RotateTransform Angle="-30" x:Name="rt"/></Border.RenderTransform><Grid><Grid.RowDefinitions><RowDefinition Height="1*"/><RowDefinition/></Grid.RowDefinitions><Border Background="White" Margin="3,3" CornerRadius="4"/></Grid></Border></Grid><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Trigger.EnterActions><BeginStoryboard><Storyboard><DoubleAnimation To="30" Duration="0:0:0.2"Storyboard.TargetName="rt"Storyboard.TargetProperty="Angle"/></Storyboard></BeginStoryboard></Trigger.EnterActions><Trigger.ExitActions><BeginStoryboard><Storyboard><DoubleAnimation Duration="0:0:0.2"Storyboard.TargetName="rt"Storyboard.TargetProperty="Angle"/></Storyboard></BeginStoryboard></Trigger.ExitActions></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style><Style TargetType="c:Switch" x:Key="ButtonSwitchStyle"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="c:Switch"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Border x:Name="borWidth"/><Border Width="{Binding ElementName=borWidth,Path=ActualWidth}"Height="{Binding ElementName=borWidth,Path=ActualHeight}"Grid.ColumnSpan="2"Background="#FF3C3C3C" CornerRadius="3"><Grid><Border Background="#FFA24F3F" Margin="6"/><Grid Margin="6,18,6,6" Name="grid"><Border><Border.Background><LinearGradientBrush StartPoint="0,0" EndPoint="0,1" x:Name="lgb"><GradientStop Color="#FF4B4B4B" Offset="0"/><GradientStop Color="#FF863424" Offset="0.7"/></LinearGradientBrush></Border.Background></Border><Border><Border.OpacityMask><LinearGradientBrush StartPoint="0,0" EndPoint="0,1"><GradientStop Color="Black" Offset="1" x:Name="gs1"/><GradientStop Color="Transparent" Offset="0" x:Name="gs2"/></LinearGradientBrush></Border.OpacityMask><Grid TextBlock.FontSize="16" Margin="0,3"><TextBlock Text="I" VerticalAlignment="Top" HorizontalAlignment="Center" Foreground="White"/><TextBlock Text="O" VerticalAlignment="Bottom" HorizontalAlignment="Center" Foreground="White"/></Grid></Border></Grid></Grid></Border></Grid><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Trigger.EnterActions><BeginStoryboard><Storyboard><ThicknessAnimation To="6,6,6,18"Duration="0:0:0.2"Storyboard.TargetName="grid"Storyboard.TargetProperty="Margin"/><DoubleAnimation To="0" Duration="0:0:0.2"Storyboard.TargetName="gs1"Storyboard.TargetProperty="Offset"/><DoubleAnimation To="1" Duration="0:0:0.2"Storyboard.TargetName="gs2"Storyboard.TargetProperty="Offset"/><PointAnimation To="0,1" Duration="0:0:0.2"Storyboard.TargetName="lgb"Storyboard.TargetProperty="StartPoint"/><PointAnimation To="0,0" Duration="0:0:0.2"Storyboard.TargetName="lgb"Storyboard.TargetProperty="EndPoint"/></Storyboard></BeginStoryboard></Trigger.EnterActions><Trigger.ExitActions><BeginStoryboard><Storyboard><ThicknessAnimation Duration="0:0:0.2"Storyboard.TargetName="grid"Storyboard.TargetProperty="Margin"/><DoubleAnimation Duration="0:0:0.2"Storyboard.TargetName="gs1"Storyboard.TargetProperty="Offset"/><DoubleAnimation Duration="0:0:0.2"Storyboard.TargetName="gs2"Storyboard.TargetProperty="Offset"/><PointAnimation Duration="0:0:0.2"Storyboard.TargetName="lgb"Storyboard.TargetProperty="StartPoint"/><PointAnimation Duration="0:0:0.2"Storyboard.TargetName="lgb"Storyboard.TargetProperty="EndPoint"/></Storyboard></BeginStoryboard></Trigger.ExitActions></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style><Style TargetType="ToggleButton" x:Key="Button2SwitchStyle"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="ToggleButton"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Border x:Name="borWidth"/><Border Width="{Binding ElementName=borWidth,Path=ActualWidth}"Height="{Binding ElementName=borWidth,Path=ActualHeight}"Grid.ColumnSpan="2"Background="#FF3C3C3C" CornerRadius="3"><Grid><Border Background="#FFA24F3F" Margin="6"/><Grid Margin="6,18,6,6" Name="grid"><Border><Border.Background><LinearGradientBrush StartPoint="0,0" EndPoint="0,1" x:Name="lgb"><GradientStop Color="#FF4B4B4B" Offset="0"/><GradientStop Color="#FF863424" Offset="0.7"/></LinearGradientBrush></Border.Background></Border><Border><Border.OpacityMask><LinearGradientBrush StartPoint="0,0" EndPoint="0,1"><GradientStop Color="Black" Offset="1" x:Name="gs1"/><GradientStop Color="Transparent" Offset="0" x:Name="gs2"/></LinearGradientBrush></Border.OpacityMask><Grid TextBlock.FontSize="16" Margin="0,3"><TextBlock Text="I" VerticalAlignment="Top" HorizontalAlignment="Center" Foreground="White"/><TextBlock Text="O" VerticalAlignment="Bottom" HorizontalAlignment="Center" Foreground="White"/></Grid></Border></Grid></Grid></Border></Grid><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Trigger.EnterActions><BeginStoryboard><Storyboard><ThicknessAnimation To="6,6,6,18"Duration="0:0:0.2"Storyboard.TargetName="grid"Storyboard.TargetProperty="Margin"/><DoubleAnimation To="0" Duration="0:0:0.2"Storyboard.TargetName="gs1"Storyboard.TargetProperty="Offset"/><DoubleAnimation To="1" Duration="0:0:0.2"Storyboard.TargetName="gs2"Storyboard.TargetProperty="Offset"/><PointAnimation To="0,1" Duration="0:0:0.2"Storyboard.TargetName="lgb"Storyboard.TargetProperty="StartPoint"/><PointAnimation To="0,0" Duration="0:0:0.2"Storyboard.TargetName="lgb"Storyboard.TargetProperty="EndPoint"/></Storyboard></BeginStoryboard></Trigger.EnterActions><Trigger.ExitActions><BeginStoryboard><Storyboard><ThicknessAnimation Duration="0:0:0.2"Storyboard.TargetName="grid"Storyboard.TargetProperty="Margin"/><DoubleAnimation Duration="0:0:0.2"Storyboard.TargetName="gs1"Storyboard.TargetProperty="Offset"/><DoubleAnimation Duration="0:0:0.2"Storyboard.TargetName="gs2"Storyboard.TargetProperty="Offset"/><PointAnimation Duration="0:0:0.2"Storyboard.TargetName="lgb"Storyboard.TargetProperty="StartPoint"/><PointAnimation Duration="0:0:0.2"Storyboard.TargetName="lgb"Storyboard.TargetProperty="EndPoint"/></Storyboard></BeginStoryboard></Trigger.ExitActions></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>

显示效果:

相关文章:

WPF自定义控件

控件模板 顾名思义就是在原有的控件上进行模版修改成自己需要的样式 把ProgressBar修改为一个水液面的进度条 <Window x:Class"XH.CustomLesson.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://s…...

Java中的全局异常处理器 -- GlobalExceptionHandler

开发记录&#xff1a;全局异常处理器笔记 import lombok.extern.slf4j.Slf4j; import org.mybatis.spring.MyBatisSystemException; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.RedisConnectionFailureException; im…...

R语言文本挖掘-万字详细解析tm包

tm包&#xff08;Text Mining Package&#xff09;是R语言中用于文本挖掘的强大工具包&#xff0c;它提供了一系列的功能来处理和分析文本数据。偶然看到这个包&#xff0c;我们一起看看其中的基本功能&#xff1a; 数据载入&#xff1a;tm包支持从多种数据源载入文本数据&…...

JWT中的Token

1.JWT是什么&#xff1f; jwt&#xff08;json web token的缩写&#xff09;是一个开放标准&#xff08;rfc7519&#xff09;&#xff0c;它定义了一种紧凑的、自包含的方式&#xff0c;用于在各方之间以json对象安全地传输信息&#xff0c;此信息可以验证和信任&#xff0c;因…...

苹果在iOS 18.1中向第三方开发者开放iPhone的NFC芯片

苹果公司今天宣布&#xff0c;开发者很快就能首次在自己的应用程序中提供 NFC 交易功能&#xff0c;而目前这主要是Apple Pay独有的功能。从今年晚些时候的 iOS 18.1 开始&#xff0c;开发者将可以使用新的 API 提供独立于 Apple Pay 和 Apple Wallet 的应用内非接触式交易。 这…...

系统开发之禁止卸载应用名单

本文目的主要是记录自己系统&#xff08;Android7.1系统&#xff09;开发实现代码&#xff0c;以便后期通用的功能可以直接使用&#xff0c;不需要再去通过搜索然后筛选再验证的繁琐流程&#xff0c;大大减小自己的开发时间。 我实现思路是在系统内新增自己的数据库用来记录禁止…...

wait 和 notify

目录 wait() 方法 notify() 方法 notifyAll() 方法 nofity 和 notifyAll wait 和 notify wait 和 sleep 的区别 wait 和 join 的区别 由于线程之间是抢占式执行的&#xff0c;因此&#xff0c;线程之间执行的先后顺序难以预知&#xff0c;但是&#xff0c;在实际开发中&…...

docker 启动 mongo,redis,nacos.

docker run --name mymongodb -e MONGO_INITDB_ROOT_USERNAMEadmin -e MONGO_INITDB_ROOT_PASSWORDXiaoyusadsad -p 27017:27017 -v /path/to/mongo-data:/data/db -d mongodb/mongodb-community-server:4.4.18-ubuntu2004-v 的目录必须是绝对目录 目录必须 chmod 777 /path/…...

Docker Swarm 搭建

Docker Swarm 搭建 1. 环境介绍 操作系统Centos 7Centos 7Centos 7内核版本Linux 3.10.0-957.el7.x86_64Linux 3.10.0-957.el7.x86_64Linux 3.10.0-957.el7.x86_64主机名称swarm-managerswarm-worker1swarm-worker2IP192.168.1.100192.168.1.200192.168.1.250Docker Domain20…...

浅述TSINGSEE青犀EasyCVR视频汇聚平台与海康安防平台的区别对比

在我们的很多项目中都遇到过用户的咨询&#xff1a;TSINGSEE青犀EasyCVR视频汇聚平台与海康平台的区别在哪里&#xff1f;确实&#xff0c;在安防视频监控领域&#xff0c;EasyCVR视频汇聚平台与海康威视平台是两个备受关注的选择。它们各自具有独特的功能和优势&#xff0c;适…...

设计模式系列:策略模式的设计与实践

一、背景 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一系列的算法&#xff0c;并将每一个算法封装起来&#xff0c;使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。 二、结构 策略模式主要包含三个角色&…...

数据挖掘之数据预处理

数据预处理是数据挖掘中的一个关键步骤&#xff0c;它的主要目的是对原始数据进行清洗、转换和格式化&#xff0c;以确保其质量和一致性&#xff0c;从而为后续的数据挖掘任务&#xff08;如分类、回归、聚类等&#xff09;提供可靠的数据基础。数据预处理一般包括以下几个主要…...

RocketMQ核心知识点整理,值得收藏!

1. 基本概念 Topic: 消息类别的集合&#xff0c;如订单消息发送到order_topic。标签&#xff08;Tag&#xff09;: 同一Topic下区分不同消息的标志&#xff0c;实现精细化消息管理。ConsumeGroup: 消息消费组&#xff0c;可订阅多个Topic&#xff0c;一个Topic可被多个消费组订…...

微信小程序骨架屏

骨架屏是常用的一种优化方案&#xff0c;针对于页面还未加载完时给用户的一种反馈方式。如果自己要写骨架屏有点复杂因为页面的元素过多且不稳定&#xff0c;这边直接使用微信开发工具生成骨架屏。也不只有微信开发工具有像常用的抖音开发工具&#xff0c;字节开发工具都有对应…...

Window下node安装以及配置

在 Windows 下安装 Node.js 非常简单&#xff0c;你可以通过官方提供的安装程序或者使用多版本管理工具&#xff08;如 NVM-Win&#xff09;来进行安装。下面是两种方法的具体步骤&#xff1a; 1. 安装 Node.js程序 步骤如下&#xff1a; 访问官方网站&#xff1a; 访问 Node…...

校园疫情防控系统--论文pf

TOC springboot432校园疫情防控系统--论文pf 课题的来源 2019年在我国武汉爆发了一场规模非常庞大、传播速度十分迅速、对人体危害及其严重的新冠肺炎疫情。引发此次急性感染性新冠肺炎疫情的冠状病毒传播性较强&#xff0c;其传播主要是通过呼吸道飞沫和密切接触这两个途径…...

在Debian 9上使用Apt安装Java的方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 介绍 Java 和 JVM&#xff08;Java 虚拟机&#xff09;是许多软件的必备组件&#xff0c;包括 Tomcat、Jetty、Glassfish、Cassandra 和…...

人工智能在网络安全中的三大支柱

人工智能 (AI) 席卷了网络安全行业&#xff0c;各种供应商都在努力将 AI 融入其解决方案中。但 AI 与安全之间的关系不仅仅在于实现 AI 功能&#xff0c;还在于攻击者和防御者如何利用该技术改变现代威胁形势。它还涉及如何开发、更新和保护这些 AI 模型。如今&#xff0c;网络…...

rk3568mpp终端学习笔记

RK3568Terminal封装MppGraph 通过脚本取和设置音量/zigsun/bin/linux/bin.debug.Linux.rk3568/get_record_voice_value.sh /zigsun/bin/linux/bin.debug.Linux.rk3568/set_record_voice_value.sh class RK3568Terminal : public IAVLinkManager, p…...

【C++继承】赋值兼容转换作用域派生类的默认成员函数

1.继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类(或子类)。继承呈现了面向对象程序设计的层次结构&#xf…...

HTML5+JavaScript绘制彩虹和云朵

HTML5JavaScript绘制彩虹和云朵 彩虹&#xff0c;简称虹&#xff0c;是气象中的一种光学现象&#xff0c;当太阳光照射到半空中的水滴&#xff0c;光线被折射及反射&#xff0c;在天空上形成拱形的七彩光谱&#xff0c;由外圈至内圈呈红、橙、黄、绿、蓝、靛、紫七种颜色。事实…...

MySQL——单表查询(二)按条件查询(2)带 IN 关键字的查询

IN 关键字用于判断某个字段的值是否在指定集合中&#xff0c;如果字段的值在集合中&#xff0c;则满足条件&#xff0c;该字段所在的记录将被查询出来。其语法格式如下所示&#xff1a; SELECT *|字段名 1,字段名 2,… FROM 表名 WHERE 字段名 [NOT〕IN(元素 1,元素 2,…) 在上…...

【mysql】mysql 用户管理---创建、权限管理等等

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…...

本地服务器物理机中redis设置、取消密码

1.服务器物理机上redis的操作【服务器中操作】 &#xff08;1&#xff09;首先先看一下当前运行中的redis实例&#xff1a; [rootiZuf67k70ucx14s6zcv54dZ var]# ps aux | grep redis-server因为我这里有两个实例在运行&#xff0c;即物理机上的redis和docker中的redis&…...

关于xilinx的FFTIP的使用和仿真

工具&#xff1a;vivado2018.3&#xff0c;modelsim10.6d 场景&#xff1a;在进行数据进行频谱分析的时候&#xff0c;使用FPGA来完成FFT的计算可以加快数据的计算速度。 下面使用仿真完成DDS产生的数据的FFT以及IFFT。原始数据使用DDSIP产生&#xff0c;通过IP产生的波形数据…...

ant design pro 如何去保存颜色

上图 就是实现这样的效果 后端是这样的&#xff0c;这个颜色肯定是存到字符串里的 这是第一步 import mongoose, { Schema, Document } from mongoose;interface IDiscountCard extends Document {title: string;subtitle: string;image: string;shopUrl: string;bgColor: s…...

【Hadoop】建立圈内组件的宏观认识

01存储02计算03调度04其他05回忆 众多组件们构建了大规模分布式计算和存储平台。本文介绍Hadoop生态圈中各个组件的主要功能和作用&#xff0c;辅助学者理解每个组件的定位和用途&#xff0c;从而建立对圈内组件的宏观认识。梳理清楚HDFS、MapReduce、YARN、Hive、HBase、Spark…...

C++:命名空间与输入输出

目录 前言 一、命名空间 1.1 namespace的价值 1.2 namespace的定义 1.3 命名空间的使用 二、C输入&输出 前言 C是一种面向对象的计算机程序设计语言&#xff0c;‌它扩展了C语言的功能&#xff0c;‌并引入了面向对象编程的概念&#xff0c;‌如类、‌继承和多态等&a…...

Azure DevOps Server 数据库日志已满,TF30042: The database is full

Contents 1. 问题描述2. 处理方式 2.1 系统备份2.2 收缩日志2.3 恢复模式2.4 日志增长无法控制 1. 问题描述 Azure DevOps Server 作为微软的软件开发管理平台产品&#xff0c;理所当然地使用了微软的数据库软件SQL Server。 在一个大型的开发团队中&#xff0c;Azure DevOps S…...

[C#]OpenCvSharp 实现Bitmap和Mat的格式相互转换

//转为 bitmap方法一&#xff1a; Bitmap map OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat); process_pictureBox.Image map; //转为 bitmap方法二&#xff1a; Bitmap map new Bitmap(mat.ToMemoryStream()); process_pictureBox.Image map; //Image img 转为…...

【区块链+金融服务】基于区块链的供应链金融系统 | FISCO BCOS应用案例

传统供应链金融存在着信息不对称、信任问题和繁琐流程等弊端。为了解决这些问题&#xff0c;京北方搭建了基于区块链 的供应链金融系统&#xff0c;提供了更高效、透明、安全和可信的交易环境。 系 统 采 用 FISCO BCOS 为 底 层 链&#xff0c; 技 术 栈 使 用 Java 语 言 进…...

AI语言大模型商业价值深度解析

点击蓝字 关注我 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;特别是深度学习算法的进步&#xff0c;AI语言大模型在自然语言处理领域的表现日益突出。国内外多种语言大模型如&#xff1a;OpenAi 的 ChatGpt&#xff0c;阿里通义千问&#xff0c;百度文心…...

理解DDD领域驱动设计思想

一、引言 在软件开发的广袤领域中&#xff0c;领域驱动设计&#xff08;Domain-Driven Design&#xff0c;简称 DDD&#xff09;犹如一颗璀璨的明星&#xff0c;备受瞩目。对于期望运用 DDD 开展项目的研发人员而言&#xff0c;明晰 DDD 的本质是实现其有效应用的基石。需注意…...

音频剪辑软件哪个好用?五大音频剪辑软件分享

如果你正打算在家自学视频制作&#xff0c;那么恭喜你&#xff0c;你已经踏上了一段充满魔法与惊喜的旅程&#xff01;不过&#xff0c;别忘了&#xff0c;视频的灵魂不仅仅在于画面&#xff0c;更在于那直击心灵的音效。 想象一下&#xff0c;一个精心剪辑的片段&#xff0c;…...

12.2 使用prometheus-sdk向pushgateway打点

本节重点介绍 : 使用golang sdk打prometheus4种指标&#xff0c;推送到pushgateway gauge、counter、histogram、summary的初始化4种类似的设置值的方法推送到pushgateway的方法 prometheus配置采集pushgateway&#xff0c;grafana上配大盘 golang-sdk 项目地址 https://git…...

HTTPS 详解

HTTPS 是以安全为目标的 HTTP 通道&#xff0c;它在 HTTP 中加入 SSL 层以提高数据传输的安全性。HTTP 被用于在 Web 浏览器和网站服务器之间传递信息&#xff0c;但以明文形式发送内容&#xff0c;不提供任何方式的数据加密&#xff0c;如果攻击者截取了 Web 浏览器和网站服务…...

Microsoft Edge 使用方法与秘诀概览

目录 ​编辑引言 Microsoft Edge 功能与技巧概览 掌握这些设置技巧&#xff0c;让 Edge 浏览器的体验更干净 1. 使用阅读视图 2. 开启广告过滤 3. 管理扩展 4. 个性化新标签页 5. 使用网页截图 6. 清理浏览器缓存 7. 管理启动设置 8. 自定义地址栏建议 9. 使用内置笔…...

【视频】onvif、RTP、RTCP、SDP、RTSP、gb21818区别

ONVIF (Open Network Video Interface Forum): ONVIF是一个全球性的开放网络视频接口论坛&#xff0c;致力于发展基于IP网络的物联网设备的标准化。它提供了一个通用的标准接口&#xff0c;使不同厂商生产的网络视频产品能够互相兼容。 RTP (Real-time Transport Protocol): R…...

8-4 循环神经网络

对于 (8.4.2)中的函数 f f f&#xff0c;隐变量模型不是近似值。 毕竟 h t h_{t} ht​是可以仅仅存储到目前为止观察到的所有数据&#xff0c; 然而这样的操作可能会使计算和存储的代价都变得昂贵。 回想一下&#xff0c;我们在前面讨论过的具有隐藏单元的隐藏层。 值得注意的…...

Linux系统编程 --- 多线程

线程&#xff1a;是进程内的一个执行分支&#xff0c;线程的执行粒度&#xff0c;要比进程要细。 一、线程的概念 1、Linux中线程该如何理解 地址空间就是进程的资源窗口。 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1…...

Grafana中的rate与irate以及histogram

用法 rate rate函数用于计算一个时间序列在给定时间范围内的平均速率。它对每个数据点进行线性插值来计算速率&#xff0c;因此对于平滑和稳定的数据来说&#xff0c;rate是一个不错的选择。语法如下&#xff1a; rate(metric_name[time_range])metric_name: 指标名称。time…...

什么是网络安全态势感知

态势感知是一种基于环境的、动态、整体地洞悉安全风险的能力&#xff0c;是以安全大数据为基础&#xff0c;从全局视角提升对安全威胁的发现识别、理解分析、响应处置能力的一种方式、最终是为了决策与行动&#xff0c;是安全能力的落地 态势感知的重要性 随着网络与信息技术的…...

php 在app中唤起微信app进行支付,并处理回调通知

<?phpnamespace app\api\controller;use think\facade\Db; use think\facade\Log;class Wxzf {...

高效同步与处理:ADTF流服务在自动驾驶数采中的应用

目录 一、ADTF 流服务 1、流服务源&#xff08;Streaming Source&#xff09; 2、流服务汇&#xff08;Streaming Sink&#xff09; 二、数据链路 1、数据管道&#xff08;Data Pipe&#xff09; 2、子流&#xff08;Substreams&#xff09; 3、触发管道&#xff08;Tri…...

【Arduino】ATmega328PB 连接 LSM6DS3 姿态传感器,并读数据(不确定 ESP 系列是否可行,但大概率是可行的)

总览 1.初始化 ATmega328PB&#xff0c;默认大家已经完成了 328 的配置准备工作&#xff0c;已经直接能够向里面写入程序 2.接线&#xff0c;然后验证 mega328 的 I2C 设备接口能否扫描到 LSM6DS3 3.编写代码&#xff0c;上传&#xff0c;查看串口数据。完成。 一、初始化 AT…...

live2d + edge-tts 优雅的实现数字人讲话 ~

震惊&#xff01;live2d数字人竟开口说话 ~ 之前有想做数字人相关项目&#xff0c;查了一些方案。看了一些三方大厂的商用方案&#xff0c;口型有点尴尬&#xff0c;而且很多是采用视频流的方案&#xff0c;对流量的消耗很大。后来了解了live2d 技术&#xff0c;常在博客网页上…...

二进制安装php

下载php二进制包&#xff1a; 官网地址&#xff1a;https://www.php.net/releases/ PHP: Releaseshttps://www.php.net/releases/在里边可以选择自己要下载的包进行下载&#xff1b; 下载完成后进行解压&#xff1a; tar xvzf php-7.3.12.tar.gz 解压后 进入目录进行预编…...

旧版Pycharm支持的python版本记录

版权声明&#xff1a;本文为博主原创文章&#xff0c;如需转载请贴上原博文链接&#xff1a;旧版Pycharm支持的python版本记录-CSDN博客 前言&#xff1a;近期由于打算研究GitHub上一个开源量化交易平台开发框架&#xff0c;但是该框架是基于python3.10的版本开发&#xff0c;所…...

java实现七牛云内容审核功能,文本、图片和视频的内容审核(鉴黄、鉴暴恐、敏感人物)

目录 1、七牛云内容审核介绍 2、查看内容审核官方文档 2.1、文本内容审核 2.1.1、文本内容审核的请求示例 2.1.2、文本内容审核的返回示例 2.2、图片内容审核 2.2.1、请求参数 2.2.2、返回参数 2.3、视频内容审核 3、代码实现 3.1、前期代码准备 3.2、文本内容审核…...

C++面试基础系列-struct

系列文章目录 文章目录 系列文章目录C面试基础系列-struct1.C中struct2.C中struct2.1.同名函数2.2.typedef定义结构体别名2.3.继承 3.总结3.1.C和C中的Struct区别 4.struct字节对齐5.struct与const 关于作者 C面试基础系列-struct 1.C中struct struct里面只能放数据类型&#…...