WPF进阶 | 深入 WPF 依赖项属性:理解其强大功能与应用场景
WPF进阶 | 深入 WPF 依赖项属性:理解其强大功能与应用场景
- 前言
- 一、依赖项属性基础概念
- 1.1 什么是依赖项属性
- 1.2 依赖项属性与 CLR 属性的区别
- 1.3 依赖项属性的定义与注册
- 二、依赖项属性的原理深入剖析
- 2.1 依赖项属性系统的工作机制
- 2.2 元数据(Metadata)的作用
- 三、依赖项属性的应用场景
- 3.1 数据绑定
- 3.2 样式与模板
- 3.3 动画
- 3.4 自定义控件开发
- 四、依赖项属性的高级应用
- 4.1 附加属性(Attached Properties)
- 4.2 依赖项属性的继承与重写
- 4.3 依赖项属性在复杂界面布局中的应用
- 五、依赖项属性的性能优化与常见问题处理
- 5.1 性能优化
- 5.2 常见问题处理
- 六、总结
- 结束语
- 优质源码分享
WPF进阶 | 深入 WPF 依赖项属性:理解其强大功能与应用场景
,在 Windows Presentation Foundation(WPF)开发中,依赖项属性是一个核心且强大的特性,它为构建灵活、可扩展的用户界面提供了关键支持。理解并熟练运用依赖项属性,对于开发高效、健壮的 WPF 应用程序至关重要。本文将深入探讨 WPF 依赖项属性,通过丰富的代码示例和对关键概念的详细解释,帮助读者全面掌握这一重要特性及其应用场景。
前言
在数字浪潮汹涌澎湃的时代,程序开发宛如一座神秘而宏伟的魔法城堡,矗立在科技的浩瀚星空中。代码的字符,似那闪烁的星辰,按照特定的轨迹与节奏,组合、交织、碰撞,即将开启一场奇妙且充满无限可能的创造之旅。当空白的文档界面如同深邃的宇宙等待探索,程序员们则化身无畏的星辰开拓者,指尖在键盘上轻舞,准备用智慧与逻辑编织出足以改变世界运行规则的程序画卷,在 0 和 1 的二进制世界里,镌刻下属于人类创新与突破的不朽印记。
在当今数字化时代,桌面应用程序的用户界面(UI)设计至关重要,它直接影响着用户体验与产品的竞争力。而 WPF(Windows Presentation Foundation)作为微软推出的一款强大的 UI 框架,其布局系统更是构建精美界面的核心要素。WPF 布局系统为开发者提供了丰富多样的布局方式,能够轻松应对各种复杂的界面设计需求,无论是简洁明了的工具软件,还是功能繁杂的企业级应用,都能借助其打造出令人惊艳的视觉效果与流畅的交互体验。
WPF从入门到精通专栏,旨在为读者呈现一条从对 WPF(Windows Presentation Foundation)技术懵懂无知到精通掌握的学习路径。首先从基础入手,介绍 WPF 的核心概念,涵盖其独特的架构特点、开发环境搭建流程,详细解读布局系统、常用控件以及事件机制等基础知识,帮助初学者搭建起对 WPF 整体的初步认知框架。随着学习的深入,进阶部分聚焦于数据绑定、样式模板、动画特效等关键知识点,进一步拓展 WPF 开发的能力边界,使开发者能够打造出更为个性化、交互性强的桌面应用界面。高级阶段则涉及自定义控件开发、MVVM 设计模式应用、多线程编程等深层次内容,助力开发者应对复杂的业务需求,构建大型且可维护的应用架构。同时,通过实战项目案例解析,展示如何将所学知识综合运用到实际开发中,从需求分析到功能实现再到优化测试,全方位积累实践经验。此外,还探讨了性能优化、与其他技术集成以及安全机制等拓展性话题,让读者对 WPF 技术在不同维度有更深入理解,最终实现对 WPF 技术的精通掌握,具备独立开发高质量桌面应用的能力。
🛕 点击进入WPF从入门到精通专栏
一、依赖项属性基础概念
1.1 什么是依赖项属性
依赖项属性是一种特殊类型的属性,它的值不仅取决于自身的赋值,还可能依赖于其他因素,如数据绑定、样式设置、动画等。与传统的 CLR 属性不同,依赖项属性通过 WPF 的依赖项属性系统进行管理,这使得它们具有很多独特的功能和优势。
例如,在一个简单的 WPF 按钮中,Button的Background属性就是一个依赖项属性。我们可以通过直接赋值来设置按钮的背景颜色,也可以通过数据绑定将背景颜色与某个数据源的值关联起来,还可以使用样式来统一设置按钮的背景颜色,甚至可以通过动画来动态改变按钮的背景颜色。
1.2 依赖项属性与 CLR 属性的区别
存储方式:CLR 属性的值直接存储在对象的字段中,而依赖项属性的值存储在一个独立的属性存储机制中,称为依赖项对象的属性存储区。这种分离的存储方式使得依赖项属性能够支持更多的功能,如数据绑定、样式设置等。
功能特性:CLR 属性主要用于简单的数据存储和访问,而依赖项属性具有更丰富的功能,包括:
值继承:依赖项属性可以在元素树中进行值继承。例如,在一个包含多个子控件的容器中,如果容器设置了某个依赖项属性的值,其子控件可以自动继承该值,除非子控件显式地设置了不同的值。
数据绑定:依赖项属性天生支持数据绑定,这使得我们可以方便地将界面元素的属性与数据源进行绑定,实现数据的双向同步。
样式设置:依赖项属性可以通过样式进行统一设置和修改,从而实现界面的统一风格和主题切换。
动画支持:依赖项属性可以参与动画,通过改变属性值随时间的变化来创建动态的视觉效果。
1.3 依赖项属性的定义与注册
在 WPF 中,定义一个依赖项属性需要以下几个步骤:
定义依赖项属性字段:首先,需要在类中定义一个静态的DependencyProperty
字段,用于标识这个依赖项属性。例如:
public class MyControl : Control
{public static readonly DependencyProperty MyPropertyProperty =DependencyProperty.Register("MyProperty", typeof(string), typeof(MyControl), new PropertyMetadata("默认值"));
}
在这个例子中,MyPropertyProperty
是一个静态的DependencyProperty
字段,Register
方法用于注册这个依赖项属性。Register
方法的第一个参数是属性的名称(MyProperty
),第二个参数是属性的类型(typeof(string))
,第三个参数是拥有该属性的类的类型(typeof(MyControl))
,第四个参数是属性的元数据,这里使用PropertyMetadata
来设置属性的默认值为 “默认值”。
定义 CLR 属性包装器:为了方便在代码中使用依赖项属性,通常会定义一个 CLR 属性包装器,通过这个包装器来访问和设置依赖项属性的值。例如:
public string MyProperty
{get { return (string)GetValue(MyPropertyProperty); }set { SetValue(MyPropertyProperty, value); }
}
在这个 CLR 属性包装器中,GetValue
方法用于获取依赖项属性的值,SetValue
方法用于设置依赖项属性的值。
二、依赖项属性的原理深入剖析
2.1 依赖项属性系统的工作机制
WPF 的依赖项属性系统是一个复杂而高效的机制,它负责管理依赖项属性的各种行为。当获取或设置一个依赖项属性的值时,依赖项属性系统会按照一定的规则来确定最终的值。这个规则涉及到多个因素,包括:
本地值:如果在代码中直接对依赖项属性进行了赋值,这个值就是本地值。本地值具有最高的优先级,会覆盖其他来源的值。
继承值:如果依赖项属性支持值继承,并且在当前元素的父元素中设置了该属性的值,当前元素会继承这个值,除非它自己设置了本地值。
默认值:在注册依赖项属性时,可以通过PropertyMetadata设置默认值。如果没有其他值来源,依赖项属性会使用默认值。
数据绑定值:如果依赖项属性与某个数据源进行了绑定,数据绑定的值会参与最终值的确定。数据绑定的值的优先级低于本地值,但高于继承值和默认值。
样式和模板值:通过样式和模板设置的依赖项属性值也会影响最终的值。样式和模板值的优先级低于本地值和数据绑定值,但高于继承值和默认值。
例如,假设我们有一个Button
控件,其Background
属性是一个依赖项属性。如果我们在代码中直接设置了Button.Background = Brushes.Red;
,这就是本地值,按钮的背景颜色将是红色。如果没有设置本地值,而按钮的父容器设置了Background
属性,按钮会继承父容器的背景颜色。如果既没有本地值也没有继承值,Button
会使用Background
属性的默认值。如果Button.Background
与某个数据源进行了绑定,并且数据源的值发生了变化,按钮的背景颜色会根据绑定的值进行更新。
2.2 元数据(Metadata)的作用
在注册依赖项属性时,PropertyMetadata
用于定义依赖项属性的元数据,它包含了很多重要的信息,如:
默认值:前面已经提到,通过PropertyMetadata
可以设置依赖项属性的默认值。
属性更改回调:可以定义一个回调方法,当依赖项属性的值发生变化时,会自动调用这个回调方法。例如:
public static readonly DependencyProperty MyPropertyProperty =DependencyProperty.Register("MyProperty", typeof(string), typeof(MyControl),new PropertyMetadata("默认值", OnMyPropertyChanged));private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{MyControl control = (MyControl)d;string oldValue = (string)e.OldValue;string newValue = (string)e.NewValue;// 在这里处理属性值变化的逻辑,例如更新界面显示control.UpdateUI(oldValue, newValue);
}
在这个例子中,OnMyPropertyChanged是属性更改回调方法,当MyProperty属性的值发生变化时,会传入DependencyObject(即拥有该属性的对象)和DependencyPropertyChangedEventArgs(包含旧值和新值等信息),我们可以在这个方法中处理属性值变化的逻辑。
强制值回调:在某些情况下,可能需要在设置依赖项属性值之前对值进行验证或修正,这时可以使用强制值回调。例如:
public static readonly DependencyProperty MyPropertyProperty =DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl),new PropertyMetadata(0, null, CoerceMyProperty));private static object CoerceMyProperty(DependencyObject d, object baseValue)
{int value = (int)baseValue;if (value < 0){value = 0;}else if (value > 100){value = 100;}return value;
}
在这个例子中,CoerceMyProperty
是强制值回调方法,当设置MyProperty
属性的值时,如果值小于 0 或大于 100,会将其修正为 0 或 100。
三、依赖项属性的应用场景
3.1 数据绑定
数据绑定是依赖项属性最常见的应用场景之一。通过数据绑定,我们可以将界面元素的属性与数据源进行关联,实现数据的双向同步。例如,我们有一个包含TextBox和Button的窗口,TextBox用于输入文本,Button用于显示输入的文本:
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="Data Binding Example" Height="350" Width="525"><Window.DataContext><local:MainViewModel/></Window.DataContext><Grid><TextBox Text="{Binding UserInput}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="200"/><Button Content="{Binding UserInput}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,50,0,0"/></Grid>
</Window>
在后台代码中,定义MainViewModel类:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;namespace WpfApp1
{public class MainViewModel : INotifyPropertyChanged{private string _userInput;public string UserInput{get { return _userInput; }set{_userInput = value;OnPropertyChanged();}}public event PropertyChangedEventHandler PropertyChanged;protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}
}
在这个例子中,TextBox
的Text
属性和Button
的Content
属性都绑定到了MainViewModel
的UserInput
属性。当用户在TextBox
中输入文本时,UserInput属性的值会更新,同时Button的Content
也会随之更新,实现了数据的双向同步。
3.2 样式与模板
依赖项属性在样式和模板中起着关键作用。通过样式,我们可以统一设置一组控件的外观和行为;通过模板,我们可以自定义控件的可视化结构。例如,我们可以定义一个按钮的样式,设置按钮的背景颜色、字体大小等依赖项属性:
<Window.Resources><Style x:Key="MyButtonStyle" TargetType="Button"><Setter Property="Background" Value="Blue"/><Setter Property="Foreground" Value="White"/><Setter Property="FontSize" Value="14"/></Style>
</Window.Resources>
<Grid><Button Content="Click Me" Style="{StaticResource MyButtonStyle}"/>
</Grid>
在这个例子中,MyButtonStyle
样式通过Setter
设置了Button
的Background
、Foreground
和FontSize
等依赖项属性,所有应用该样式的按钮都会具有相同的外观。
对于模板,我们可以通过依赖项属性来控制模板中的元素。例如,定义一个自定义的ProgressBar
模板,通过依赖项属性来控制进度条的进度:
<ControlTemplate x:Key="MyProgressBarTemplate" TargetType="ProgressBar"><Grid><Rectangle Fill="Gray" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"/><Rectangle Fill="Green" Width="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ProgressConverter}}" Height="{TemplateBinding Height}"/></Grid>
</ControlTemplate>
在这个模板中,Rectangle
的Width
属性通过TemplateBinding绑定到ProgressBar
的Value
属性(经过ProgressConverter
转换),实现了根据ProgressBar
的进度值来动态改变绿色矩形的宽度,从而显示进度条的进度。
3.3 动画
依赖项属性是实现 WPF 动画的基础。通过动画,我们可以改变依赖项属性的值随时间的变化,创建出各种动态的视觉效果。例如,我们可以创建一个动画,让按钮在点击时逐渐放大:
<Window.Resources><Storyboard x:Key="ButtonGrowStoryboard"><DoubleAnimationStoryboard.TargetName="MyButton"Storyboard.TargetProperty="Width"From="100" To="150" Duration="0:0:0.5"/></Storyboard>
</Window.Resources>
<Grid><Button x:Name="MyButton" Content="Click Me" HorizontalAlignment="Center" VerticalAlignment="Center"><Button.Triggers><EventTrigger RoutedEvent="Button.Click"><BeginStoryboard Storyboard="{StaticResource ButtonGrowStoryboard}"/></EventTrigger></Button.Triggers></Button>
</Grid>
在这个例子中,DoubleAnimation
动画作用于Button
的Width
依赖项属性,从 100 逐渐变化到 150,持续时间为 0.5 秒。当按钮被点击时,触发动画,按钮的宽度会逐渐增加,实现放大效果。
3.4 自定义控件开发
在自定义控件开发中,依赖项属性是必不可少的。通过定义依赖项属性,我们可以为自定义控件提供丰富的功能和可定制性。例如,我们创建一个自定义的NumericUpDown
控件,用于输入和调整数值:
public class NumericUpDown : Control
{public static readonly DependencyProperty ValueProperty =DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown),new PropertyMetadata(0, OnValueChanged));public int Value{get { return (int)GetValue(ValueProperty); }set { SetValue(ValueProperty, value); }}private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){NumericUpDown control = (NumericUpDown)d;int oldValue = (int)e.OldValue;int newValue = (int)e.NewValue;// 在这里处理数值变化的逻辑,例如更新显示control.UpdateDisplay(oldValue, newValue);}
}
在 XAML 中使用这个自定义控件:
<local:NumericUpDown Value="5" HorizontalAlignment="Left" VerticalAlignment="Top"/>
在这个例子中,NumericUpDown
控件定义了一个Value
依赖项属性,用于存储当前的数值。当Value
属性的值发生变化时,会调用OnValueChanged
回调方法,我们可以在这个方法中处理数值变化的逻辑,如更新控件的显示。
四、依赖项属性的高级应用
4.1 附加属性(Attached Properties)
附加属性是一种特殊的依赖项属性,它可以附加到任何依赖项对象上,而不需要在该对象的类中预先定义。附加属性通常用于在不修改现有类的情况下为其添加额外的功能。例如,Grid
的Row
和Column
属性就是附加属性,它们可以附加到Grid的子控件上,用于指定子控件在Grid
中的位置:
<Grid><Button Content="Button 1" Grid.Row="0" Grid.Column="0"/><Button Content="Button 2" Grid.Row="0" Grid.Column="1"/>
</Grid>
在代码中定义附加属性的方式与普通依赖项属性类似,只是注册方法略有不同。例如,定义一个自定义的附加属性MyAttachedProperty
:
public class MyAttachedProperties
{public static readonly DependencyProperty MyAttachedPropertyProperty =DependencyProperty.RegisterAttached("MyAttachedProperty", typeof(string), typeof(MyAttachedProperties),new PropertyMetadata(null));public static void SetMyAttachedProperty(DependencyObject element, string value){element.SetValue(MyAttachedPropertyProperty, value);}public static string GetMyAttachedProperty(DependencyObject element){return (string)element.GetValue(MyAttachedPropertyProperty);}
}
在 XAML 中使用这个附加属性:
<Button Content="My Button" local:MyAttachedProperties.MyAttachedProperty="Some Value"/>
4.2 依赖项属性的继承与重写
依赖项属性支持继承和重写。当一个类继承自另一个类时,它会继承父类的依赖项属性。如果子类需要修改依赖项属性的行为,可以通过重写元数据来实现。例如,假设我们有一个BaseControl
类,定义了一个MyProperty
依赖项属性:
public class BaseControl : Control
{public static readonly DependencyProperty MyPropertyProperty =DependencyProperty.Register("MyProperty", typeof(string), typeof(BaseControl),new PropertyMetadata("Base Value"));public string MyProperty{get { return (string)GetValue(MyPropertyProperty); }set { SetValue(MyPropertyProperty, value); }}
}
假设我们有一个自定义的AgeInput
控件,用于输入年龄,要求年龄必须是大于 0 且小于 150 的整数。可以这样实现:
public class AgeInput : Control
{public static readonly DependencyProperty AgeProperty =DependencyProperty.Register("Age", typeof(int), typeof(AgeInput),new PropertyMetadata(0, OnAgeChanged, CoerceAge));public int Age{get { return (int)GetValue(AgeProperty); }set { SetValue(AgeProperty, value); }}private static void OnAgeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){int oldAge = (int)e.OldValue;int newAge = (int)e.NewValue;// 这里可以添加一些年龄变化时的额外逻辑,比如更新界面提示AgeInput control = (AgeInput)d;control.UpdateAgeDisplay(oldAge, newAge);}private static object CoerceAge(DependencyObject d, object baseValue){int value = (int)baseValue;if (value <= 0){value = 1;// 可以添加提示信息,告知用户输入不符合要求}else if (value >= 150){value = 149;// 可以添加提示信息,告知用户输入不符合要求}return value;}
}
在 XAML 中使用该控件:
<local:AgeInput Age="25" HorizontalAlignment="Left" VerticalAlignment="Top"/>
在这个示例中,CoerceAge
方法作为强制值回调,会在设置Age
属性值时检查输入值是否在合理范围内。如果不在,会将其修正为合理的值,确保了数据的有效性。
4.3 依赖项属性在复杂界面布局中的应用
在构建复杂的用户界面时,依赖项属性的灵活性和强大功能得以充分体现。例如,在一个具有动态布局的多文档界面(MDI)应用中,每个文档窗口的大小、位置等属性都可以定义为依赖项属性。
public class DocumentWindow : Window
{public static readonly DependencyProperty WindowWidthProperty =DependencyProperty.Register("WindowWidth", typeof(double), typeof(DocumentWindow),new PropertyMetadata(400.0));public static readonly DependencyProperty WindowHeightProperty =DependencyProperty.Register("WindowHeight", typeof(double), typeof(DocumentWindow),new PropertyMetadata(300.0));public double WindowWidth{get { return (double)GetValue(WindowWidthProperty); }set { SetValue(WindowWidthProperty, value); }}public double WindowHeight{get { return (double)GetValue(WindowHeightProperty); }set { SetValue(WindowHeightProperty, value); }}// 可以添加更多依赖项属性,如窗口位置等
}
在 XAML 中:
<local:DocumentWindow WindowWidth="500" WindowHeight="400" Title="文档1"/>
通过这种方式,可以方便地在 XAML 中配置每个文档窗口的大小,也可以通过数据绑定或其他方式动态改变这些属性,实现灵活的界面布局。
五、依赖项属性的性能优化与常见问题处理
5.1 性能优化
减少不必要的属性更改通知:依赖项属性的属性更改回调会在属性值变化时被调用,如果频繁触发属性更改通知,可能会影响性能。在代码中,尽量批量处理属性值的变化,而不是每次小幅度更改都触发通知。例如,在更新一个包含多个依赖项属性的自定义控件时,可以先设置一个标志位,在所有属性都更新完成后,再统一触发属性更改通知。
合理使用默认值:依赖项属性的默认值设置对性能也有一定影响。如果默认值设置得合理,可以减少不必要的计算和赋值操作。例如,对于一个在大多数情况下都显示为黑色的文本控件,将Foreground
属性的默认值设置为Brushes.Black
,避免在每个实例创建时都进行额外的初始化操作。
避免过度依赖值继承:虽然依赖项属性的值继承机制很方便,但在大型复杂的元素树中,过度使用值继承可能会导致性能下降。因为值继承需要在元素树中向上或向下查找属性值,这会增加查找的时间开销。尽量在必要的情况下使用值继承,并且注意元素树的层级深度。
5.2 常见问题处理
属性值不更新问题:有时会遇到依赖项属性的值在代码中修改了,但界面上没有及时更新的情况。这可能是因为没有正确触发属性更改通知,或者数据绑定的更新模式设置不正确。确保在属性值变化时,正确调用OnPropertyChanged
方法(如果使用INotifyPropertyChanged
接口),并且检查数据绑定的UpdateSourceTrigger
属性,确保其设置符合需求。
依赖项属性冲突:在复杂的项目中,可能会出现不同的库或模块定义了相同名称的依赖项属性,导致冲突。为了避免这种情况,在定义依赖项属性时,尽量使用唯一的命名空间或前缀。例如,在自定义控件库中,使用库的名称作为依赖项属性名称的前缀,如MyLibrary_MyProperty
。
附加属性的使用误区:在使用附加属性时,容易出现将附加属性添加到不支持的对象上,或者在获取和设置附加属性时出现类型错误。在使用附加属性之前,仔细检查目标对象是否支持该附加属性,并且在代码中进行必要的类型检查和转换。
六、总结
WPF 依赖项属性是 WPF 框架中一个极其强大且核心的特性,它为开发者提供了构建灵活、可扩展用户界面的有力工具。通过本文对依赖项属性的基础概念、原理、应用场景、高级应用以及性能优化和常见问题处理的全面深入探讨,读者应该对依赖项属性有了全面而深入的理解。在实际的 WPF 应用开发中,根据具体的需求,合理、巧妙地运用依赖项属性,可以显著提高代码的质量和可维护性,打造出更加高效、健壮的用户界面。随着 WPF 技术的不断发展和应用场景的日益丰富,依赖项属性的应用也将不断拓展和深化,开发者需要持续关注和学习,以充分发挥其强大功能。
结束语
展望未来,WPF 布局系统依然有着广阔的发展前景。随着硬件技术的不断革新,如高分辨率屏幕、折叠屏设备的日益普及,WPF 布局系统有望进一步强化其自适应能力,为用户带来更加流畅、一致的体验。在应对高分辨率屏幕时,能够更加智能地缩放和布局元素,确保文字清晰可读、图像不失真;对于折叠屏设备,可动态调整布局结构,充分利用多屏空间,实现无缝切换。
性能优化方面,微软及广大开发者社区将持续努力,进一步降低复杂布局的计算开销,提高布局更新的效率,使得 WPF 应用在处理大规模数据、动态界面时依然能够保持高效响应。通过改进算法、优化内存管理等手段,让 WPF 布局系统在性能上更上一层楼。
亲爱的朋友,无论前路如何漫长与崎岖,都请怀揣梦想的火种,因为在生活的广袤星空中,总有一颗属于你的璀璨星辰在熠熠生辉,静候你抵达。
愿你在这纷繁世间,能时常收获微小而确定的幸福,如春日微风轻拂面庞,所有的疲惫与烦恼都能被温柔以待,内心永远充盈着安宁与慰藉。
至此,文章已至尾声,而您的故事仍在续写,不知您对文中所叙有何独特见解?期待您在心中与我对话,开启思想的新交流。
优质源码分享
-
【百篇源码模板】html5各行各业官网模板源码下载
-
【模板源码】html实现酷炫美观的可视化大屏(十种风格示例,附源码)
-
【VUE系列】VUE3实现个人网站模板源码
-
【HTML源码】HTML5小游戏源码
-
【C#实战案例】C# Winform贪吃蛇小游戏源码
💞 关注博主 带你实现畅游前后端
🏰 大屏可视化 带你体验酷炫大屏
💯 神秘个人简介 带你体验不一样得介绍
🎀 酷炫邀请函 带你体验高大上得邀请
① 🉑提供云服务部署(有自己的阿里云);
② 🉑提供前端、后端、应用程序、H5、小程序、公众号等相关业务;
如🈶合作请联系我,期待您的联系。
注:本文撰写于CSDN平台,作者:xcLeigh(所有权归作者所有) ,https://blog.csdn.net/weixin_43151418,如果相关下载没有跳转,请查看这个地址,相关链接没有跳转,皆是抄袭本文,转载请备注本文原地址。
亲,码字不易,动动小手,欢迎 点赞 ➕ 收藏,如 🈶 问题请留言(评论),博主看见后一定及时给您答复,💌💌💌
原文地址:https://blog.csdn.net/weixin_43151418/article/details/145325587(防止抄袭,原文地址不可删除)
相关文章:
WPF进阶 | 深入 WPF 依赖项属性:理解其强大功能与应用场景
WPF进阶 | 深入 WPF 依赖项属性:理解其强大功能与应用场景 前言一、依赖项属性基础概念1.1 什么是依赖项属性1.2 依赖项属性与 CLR 属性的区别1.3 依赖项属性的定义与注册 二、依赖项属性的原理深入剖析2.1 依赖项属性系统的工作机制2.2 元数据(Metadata…...
浅聊MQ之Kafka与RabbitMQ简用
Kafka与RabbitMQ的使用举例 Kafka的使用举例 安装与启动: 从Apache Kafka官网下载Kafka中间件的运行脚本。解压后,通过命令行启动Zookeeper(Kafka的运行依赖于Zookeeper)。启动Kafka的服务器进程。 基本功能实现: 生…...
2.1 JUnit 5 测试发现机制详解
JUnit 5 测试发现机制详解 JUnit 5 的测试发现机制是框架的核心功能之一,负责识别测试类、方法和其他可执行元素,并构建出可执行的测试计划。该机制通过模块化设计支持高度扩展性,允许开发者自定义测试发现规则。以下是其工作原理的详细解析…...
【Elasticsearch】match查询
Elasticsearch 的match查询是全文搜索中最常用和最强大的查询类型之一。它允许用户在指定字段中搜索文本、数字、日期或布尔值,并提供了丰富的功能来控制搜索行为和结果。以下是match查询的详细解析,包括其工作原理、参数配置和使用场景。 1.match查询的…...
【开发心得】CentOS7编译Redis7.4.2打包RPM完整方案
概述 由于最近客户需要解决redis版本升级问题,故而全网寻找安全版本,redis7.4.x版本求而为果,只能自己编译了。 截止发文时间2025-02-12 最新稳定版的redis版本号为7.4.2 Security fixes (CVE-2024-46981) Lua script commands may lead t…...
云计算——AWS Solutions Architect – Associate(saa)6.CloudWatch
Amazon CloudWatch 是一种面向开发运营工程师、开发人员、站点可靠性工程师(SRE)和 IT 经理的监控和可观测性服务。CloudWatch 为我们提供相关数据和切实见解,以监控应用程序、响应系统范围的性能变化、优化资源利用率,并在统一视图中查看运营状况。 Clo…...
面试实战题:手写一个队列和介绍Stream流怎么使用
手写一个队列 思路解析: 队列要有入队和出队操作,还要有查看队列大小,查看队头元素,查看队列是否为空,查看队列是否满了这些功能 package com.example.transational.MyQueue;public class MyQueue<T> {privat…...
Jmeter+Influxdb+Grafana平台监控性能测试过程
一、Jmeter自带插件监控 下载地址:https://jmeter-plugins.org/install/Install/ 安装:下载后文件为jmeter-plugins-manager-1.3.jar,将其放入jmeter安装目录下的lib/ext目录,然后重启jmeter,即可。 启动Jmeter&…...
【现代深度学习技术】深度学习计算 | GPU
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重…...
基于斜坡单元的机器学习模型预测滑坡易发性,考虑条件因素的异质性
1、引用 Chang Z, Catani F, Huang F, et al. Landslide susceptibility prediction using slope unit-based machine learning models considering the heterogeneity of conditioning factors[J]. Journal of Rock Mechanics and Geotechnical Engineering, 2023…...
Node.js调用DeepSeek Api 实现本地智能聊天的简单应用
在人工智能快速发展的今天,如何快速构建一个智能对话应用成为了开发者们普遍关注的话题。本文将为大家介绍一个基于Node.js的命令行聊天应用,它通过调用硅基流动(SiliconFlow)的API接口,实现了与DeepSeek模型的智能对话…...
实战 - 编写一个最简单的 Hello World 内核模块
实战 - 编写一个最简单的 Hello World 内核模块 在嵌入式开发中,编写 Linux 内核模块是设备驱动开发的重要基础。内核模块可以帮助我们在不修改内核源码的情况下扩展内核功能。本篇博客将指导你如何编写并运行一个简单的 Hello World 内核模块,让你快速…...
面向对象程序设计-实验七
6-1 计算捐款总量 这里需要设计一个捐款人类Donator及一个相关函数getMaxName( ),Donator类中包含捐款人的姓名及其捐款额 代码清单: #include <iostream> using namespace std; class Donator { private: string name; float money; //单位&…...
JVM组成
JVM是什么? JVM(Java Virtual Machine):Java程序的运行环境(java二进制字节码的运行环境) 好处: 1.一次编写,到处运行 Java代码是如何做到一次编写,到处运行? 计算机的最底层是计…...
java.lang.NoClassDefFoundError: javax/xml/bind/ValidationException
Java8升级到17之后, 启动报错, :LocalValidatorFactoryBean]: Factory method defaultValidator threw exception; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/ValidationException 报错原因:这个错误通常是由于缺少 javax.xml.bind 相关的依赖引起…...
Electron 实现自定义系统托盘菜单
效果如下: 其实实现自定义托盘菜单的本质上,就是开一个新窗口,下面直接给出核心代码。 // 加载窗口 const loadWindow (example, path) > {if (is.dev && process.env[ELECTRON_RENDERER_URL]) {example.loadURL(process.env[EL…...
HCIA-路由器相关知识和面试问题
二、 路由器 2.1 关于路由器的知识 2.1.1 什么是路由器 路由器是一种网络层互联设备,主要用于连接多个逻辑上分开的网络,实现不同网络之间的数据路由和通信。它能根据网络层地址(如 IP 地址)来转发数据包,在网络中起…...
2.【BUUCTF】bestphp‘s revenge
进入题目页面如下 进行代码审计 <?php // 1. 高亮显示当前PHP文件的源代码,方便开发者查看代码内容,在生产环境中不应使用此函数,可能会导致代码泄露。 highlight_file(__FILE__);// 2. 定义变量 $b ,其值为字符串 implode &…...
wx060基于springboot+vue+uniapp的宿舍报修系统小程序
开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…...
使用 meshgrid函数绘制网格点坐标的原理与代码实现
使用 meshgrid 绘制网格点坐标的原理与代码实现 在 MATLAB 中,meshgrid 是一个常用函数,用于生成二维平面网格点的坐标矩阵。本文将详细介绍如何利用 meshgrid 函数生成的矩阵绘制网格点的坐标,并给出具体的代码实现和原理解析。 实现思路 …...
快速上手Vim的使用
Vim Linux编辑器-vim使用命令行模式下所有选项都可以带数字底行模式可视块模式(ctrlV进入) Linux编辑器-vim使用 Vim有多种模式的编辑器。能帮助我们很快的进行代码的编辑,甚至完成很多其他事情。 默认情况下我们打开vim在命令模式下&#x…...
HCIA项目实践---ACL访问控制列表相关知识和配置过程
十 ACL访问控制列表 1 策略的概念 在网络连通之后, 把所有为了追求控制而实现的技术都叫策略 2 访问控制 在路由器流量流入或者流出的接口上,匹配流量,执行相应的动作。(流量流入或者流出的接口并不是一个固定的概念而是一个相对的…...
机器学习核心算法解析
机器学习核心算法解析 机器学习是人工智能的核心技术之一,它通过从数据中学习模式并做出预测或决策。本文将深入解析机器学习的核心算法,包括监督学习、无监督学习和强化学习,并通过具体案例和代码示例帮助读者理解这些算法的实际应用。 1. …...
Oracle 12c 并发统计信息收集功能:技术解析与实践指南
一、功能背景与核心价值 在Oracle数据库的早期版本中,统计信息收集(如通过DBMS_STATS包)是串行执行的,即一次仅处理一个表或分区。对于大规模数据库或数据仓库环境,这种串行模式可能导致统计信息收集耗时过长…...
Android Studio:EditText常见4种监听方式
1. 文本变化监听(TextWatcher) TextWatcher 主要用于监听 EditText 里的文本变化,它有三个方法: beforeTextChanged(文本变化前)onTextChanged(文本正在变化时)afterTextChanged&a…...
【第2章:神经网络基础与实现——2.3 多层感知机(MLP)的构建与调优技巧】
在当今科技飞速发展的时代,人工智能早已不是一个陌生的词汇,它已经渗透到我们生活的方方面面,从智能语音助手到自动驾驶汽车,从图像识别到自然语言处理。而支撑这一切的核心技术之一,就是神经网络。作为机器学习领域的璀璨明星,神经网络已经在众多任务中取得了令人瞩目的…...
C++ 网络编程
1. socket Socket 是一种用于网络通信的编程接口,它提供了一种类似于文件描述符的接口,允许不同计算机之间的进程进行通信。Socket 可以工作在多种协议上,最常用的是 TCP/IP 和 UDP/IP 协议 1.1 UDP 1.1.1 概念 UDP(用户数据报协…...
SQL-leetcode—1683. 无效的推文
1683. 无效的推文 表:Tweets ----------------------- | Column Name | Type | ----------------------- | tweet_id | int | | content | varchar | ----------------------- 在 SQL 中,tweet_id 是这个表的主键。 content 只包含美式键盘上的字符&am…...
vue前端可视化大屏页面适配方案
参考了其他博主的代码,但发现会有滚动条,并且居中的位置不太对,所以改了一下css,修复了这些问题,直接上代码 <template> <div class"ScaleBoxA"><divclass"ScaleBox"ref"Sca…...
mars3d接入到uniapp的时候ios上所有地图的瓦片都无法加载解决方案
用的是【Mars3d】官网的uniapp的仓库,安卓没有问题,但是ios的不行 相关链接 mars3d-uni-app: uni-app技术栈下的Mars3D项目模板 解决方案:感觉所有图片请求全被拦截了 uniapp的ios内核不允许跨域,需要先把瓦片下载后转base64&…...
Dockfile语法
目录 dockerfile的作用 1. 构建 Docker 映像 2. 提高开发和运维效率 3. 版本控制 4. 提供可移植性和灵活性 使用示例 总结 dockerfile应该放的位置 为什么放在根目录? 例外情况 调用构建 dockerfile的基本结构和常用指令 基本结构和常用指令 示例 Dock…...
Nginx负载均衡
一。Nginx负载均衡的算法以及过程 二。nginx四层负载均衡的配置(四层) 1.vi /etc/nginx/conf.d/lb.conf 比较常见:weight:设置权重,backup:当其他主机全部用不了,这个作为备份 2.systemctl r…...
【C】初阶数据结构5 -- 栈
前面学习了两种最基本的数据结构 -- 顺序表和链表,接下来就可以基于这两种数据结构来实现其他数据结构了。其实,其他的数据结构的物理结构要么是数组,要么就是链表,所以学好顺序表和链表是学好其他数据结构的基础。接下里…...
Linux查找占用的端口,并杀死进程的简单方法
在Linux系统管理中,识别并管理占用特定端口的进程是一项常见且重要的任务。以下是优化过的步骤指南,帮助您高效地完成这一操作,同时提供了一个简洁的命令参考表。 Linux下识别并终止占用端口的进程 1. 探寻端口占用者 使用 lsof命令 lsof…...
为什么Pytorch中实例化模型会直接调用forward方法?
在 PyTorch 中,为何定义一个继承自 nn.Module 的自定义类并实现 forward 方法后,直接调用模型实例时,便会自动调用其 forward 方法?例如使用 output model(x) 这种形式。 因为自定义的神经网络类所继承的 nn.Module 类对 __call_…...
easyexcel快速使用
1.easyexcel EasyExcel是一个基于ava的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel 即通过java完成对excel的读写操作, 上传下载 2.easyexcel写操作 把java类中的对象写入到excel表格中 步骤 1.引入依赖 <depen…...
DeepSeek的出现会对百度有多大影响?
当DeepSeek与ChatGPT等大模型接管搜索入口,我们正见证百年一遇的信息革命。 01 传统搜索已死?AI助手正在重写游戏规则! 当DeepSeek与ChatGPT等大模型接管搜索入口,我们正见证百年一遇的信息革命。 就像汽车淘汰马车、触屏终结按键…...
生成格雷码
以下是Verilog实现格雷码的两种常见方法: 1. 二进制转格雷码(组合逻辑实现) module binary_to_gray #(parameter N 4 // 默认4位位宽 )(input [N-1:0] binary, // 二进制输入output [N-1:0] gray // 格雷码输出 );assign gray binary…...
【STM32】BootLoader和IAP详解
文章目录 0 前言1 基本概念2 BootLoader3 主程序相关配置4 相关理论:芯片启动与中断响应5 特殊情况:Cortex-M0内核的芯片 0 前言 最近在研究一个RT-Thread的项目,遇到很多之前没咋遇见过的STM32相关的知识,想着顺带也整体过一遍。…...
Threadlocal的实现原理
文章目录 ThreadLocal与Thread关系分析Threadlocal 不支持继承性lnheritableThreadLocal 类 ThreadLocal与Thread关系分析 由该图可知, Thread 类中有一个 threadLocals 和一个 inheritableThreadLocals , 它们 都是 ThreadLocalMap 类型 的变量 &#x…...
【Elasticsearch】多字段查询方式汇总
在 Elasticsearch 中,实现多字段查询的常见方式有以下几种,每种方式适用于不同的场景: --- ### 1. **multi_match 查询** - **用途**:在多个字段中执行同一查询,支持多种匹配策略。 - **关键参数**:…...
Unity使用反射进行Protobuf(CS/SC)协议,json格式
protobuf生成的协议,有挺多协议的.利用反射生成dto进行伪协议的响应 和 发送请求 应用场景: 请求(CS)_后端先写完了,前端还搞完时,可使用此请求,可自测 响应(SC)_可自行构建一个响应,对数据进行测试 // 请求 使用物品 CS message ReqUseItem{optional Opcodes MessageID1[def…...
MySQL和SQL server的区别
在当今数据驱动的世界里,数据库技术的选择对于企业和个人开发者来说至关重要。MySQL 和 SQL Server 是两个广泛使用的数据库管理系统(DBMS),它们各自拥有独特的优势和适用场景。本文将深入探讨这两个数据库系统之间的区别…...
SpringMVC请求执行流程源码解析
文章目录 0.SpringMVC九大内置组件1.processRequest方法1.请求先到service方法2.然后不管是get还是post都会跳转到processRequest方法统一处理 2.doService方法3.doDispatch方法1.代码2.checkMultipart 4.核心流程 0.SpringMVC九大内置组件 1.processRequest方法 1.请求先到se…...
LabVIEW与小众设备集成
在LabVIEW开发中,当面临控制如布鲁克OPUS红外光谱仪这类小众专业设备的需求,而厂家虽然提供了配套软件,但由于系统中还需要控制其他设备且不能使用厂商的软件时,必须依赖特定方法通过LabVIEW实现设备的控制。开发过程中࿰…...
docker-compose暴露端口,但其他主机无法访问问题。
问题描述:docker-compose暴露端口,但其他主机无法访问问题。 排障思路: 执行命令:ss -antlp | grep 80,发现端口正常监听0.0.0.0:80(ps:如果是127.0.0.1:80则只能本机访问同区域网段服务器执行…...
【MySQL】 基本查询(上)
欢迎拜访:雾里看山-CSDN博客 本篇主题:【MySQL】 基本查询(上) 发布时间:2025.2.14 隶属专栏:MySQL CRUD : Create(创建), Retrieve(读取),Update(更新),Delete(删除) 目录 Create基…...
python 爬虫教程 0 基础入门 一份较为全面的爬虫python学习方向
文章目录 前言一、Python 爬虫简介二、环境搭建1. 下载 Python2. 安装 Python3. 安装必要的库 三、一个简单的爬虫示例四、应对网站反爬机制五、深入学习方向 前言 以下是一份较为全面的 Python 爬虫教程,涵盖基础知识、环境搭建、简单示例、反爬应对及深入学习方向…...
总结:使用JDK原生HttpsURLConnection,封装HttpsUtil工具类,加载自定义证书验证,忽略ssl证书验证
总结:使用JDK原生HttpsURLConnection,封装HttpsUtil工具类,加载自定义证书验证,忽略ssl证书验证 一HttpsUtil工具类二SSLUtil工具类 一HttpsUtil工具类 package com.example.util;import javax.net.ssl.HttpsURLConnection; impo…...
你认为如何理解“约定大于配置”?
SpringBoot的“约定大于配置”(Convention Over Configuration)是一种核心理念,旨在简化开发过程,减少开发人员在配置上的繁琐工作。以下是对其含义的详细介绍: 一、定义与目的 定义:约定优于配置&#x…...