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

C# wpf

学习网址:控件的父类们 - WPF中文网 - 从小白到大佬

控件的父类:

由此我们可以得出结论,控件的父类们(准确的说,应该叫父类的父类的父类),至少有如下几个类型:

  • DispatcherObject
  • DependencyObject
  • Visual
  • UIElement
  • FrameworkElement

WPF几乎所有的控件都从上面这五个父类继承,它们的相互继承关系,形成了一棵树。

DispatcherObject类

在UI线程上给你们提供一个中间商Dispatcher(调度员),将Dispatcher放到一个抽象类DispatcherObject,然后我向你保证,我所有的控件都从这个DispatcherObject类继承,这样当你们在后台线程中要访问控件时,就可以从控件中找到那位中间商Dispatcher,由中间商来完成你要对控件的操作访问。

从此,DispatcherObject在WPF的世界中,便登上了至高无上的宝座,成为了几乎所有类型的终极基类。

需要在后台线程中去操作控件,于是Dispatcher调度员提供了Invoke和BeginInvoke两个方法,供我们可以安全的访问UI线程中的控件。

官方解释:

在 WPF 中, DispatcherObject 只能由 Dispatcher 它与之关联的访问。 例如,后台线程无法更新与 Dispatcher UI 线程上关联的内容Button。 为了使后台线程访问该 Content 属性 Button,后台线程必须将工作委托给 Dispatcher 与 UI 线程关联的工作。 这是通过使用 Invoke 或BeginInvoke。 Invoke 是同步的, BeginInvoke 是异步的。 操作将添加到指定DispatcherPriority位置的队列Dispatcher中。

namespace HelloWorld
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
 
            Task.Factory.StartNew(() =>
            {

//Task.Delay(3000):创建一个表示 3 秒延迟的 Task 对象。它不会阻塞当前线程,而是返回一个表示延迟的异步任务。

//.Wait():阻塞当前线程,直到 Task 完成。在这里,Wait() 会等待 Task.Delay(3000) 的 3 秒延迟完成。

                Task.Delay(3000).Wait();
                 //button:前端UI

                //在后端想改变前端数据时使用:
                button.Dispatcher.Invoke(() =>
                {
                    button.Content = "www.wpfsoft.com";
                });
            }); 
        }
    }
}

  • 提供方法以检查 (CheckAccess) 和验证 (VerifyAccess) 某个线程是否有权访问对象(派生于 DispatcherObject)。CheckAccess 与 VerifyAccess 的区别在于 CheckAccess 返回一个布尔值,表示当前线程是否有可以使用的对象,而 VerifyAccess 则在线程无权访问对象的情况下引发异常。

DependencyObject类

控件的属性不再被直接赋值,而是绑定了另一个”变量“,当这个”变量“发生改变时,控件的属性也会跟着改变,这样的属性也被称为依赖属性。

DependencyObject 类表示参与依赖属性系统的对象。属性系统的主要功能是计算属性的值,并提供有关已更改的值的系统通知。 参与属性系统的另一个类 DependencyProperty。 DependencyProperty 允许将依赖属性注册到属性系统,并提供有关每个依赖属性的标识和信息,而 DependencyObject 为基类,使对象能够使用此依赖属性。
INotifyPropertyChanged 类用于通知UI刷新,注重的仅仅是数据更新后的通知。DependencyObject 类用于给UI添加依赖和附加属性,注重数据与UI的关联。如果简单的数据通知,两者都可以实现的。

Visual类

Visual类是WPF框架中第三个父类,主要是为 WPF 中的呈现提供支持,其中包括命中测试、坐标转换和边界框计算。它位于程序集:PresentationCore.dll库文件中,它的命名空间:System.Windows.Media。

Visual 类是派生每个 FrameworkElement 对象的基本抽象。 该类还用作在 WPF 中编写新控件的入口点,在 Win32 应用程序模型中,该类在许多方面可视为窗口句柄 (HWND)。Visual 对象是一个核心 WPF 对象,它的主要作用是提供呈现支持。 用户界面控件如 Button 和 TextBox)派生自 Visual 类,并使用该类来保存它们的呈现数据。 Visual 对象为以下项提供支持:
输出显示:呈现视觉对象的持久、序列化的绘图内容。
转换:针对视觉对象执行转换。
剪裁:为视觉对象提供剪裁区域支持。
命中测试:确定坐标或几何形状是否包含在视觉对象的边界内。
边框计算:确定视觉对象的边框。

所有控件都继承了Visual类,控件在绘制到界面的过程中,涉及到转换、裁剪、边框计算等功能,都是使用了Visual父类的功能。

UIElement类

UIElement类继承了Visual类,在WPF框架中排行老四(第4个基类)。它位于程序集:PresentationCore.dll之中,命名空间:System.Windows。

第一部分 路由事件

UIElement基类定义了大量的路由事件。什么是路由事件?路由事件和xaml的可视化树概念相关,控件的事件被触发后,会沿着这棵树广播,有两个方向,要么往树的根部广播,要么往树的枝叶广播,如果不广播就是直接事件。

所以,路由事件分为冒泡事件和隧道事件,冒泡,是从触发源为出发点,依次传递到父节点,直到最后的根节点。隧道事件是不管谁是触发源,都是从根节点触发,到子节点,直到触发节点。

从空间上来说,冒泡事件和隧道事件是成对出现的。从时间来说,都是先触发隧道事件,然后是冒泡事件。从命名来说,隧道事件都是以Preview开头的事件。

根据命名规则,我们可以大致猜测出一个结果,带Key的基本都是与键盘相关的事件(如按下键位、抬起键位),带Mouse的基本都是与鼠标相关的事件(如左键单击、双击),带Stylus的基本都是与触摸相关的事件,具体用到哪一类型的事件,再详细查阅一下相关说明文档即可。

重点:关于这些事件的回调函数,即以On开头的方法成员,都被声明成了protected virtual,意思是他们都可以被重载,这使得我们在开发业务时更加方便。

第二部分 依赖属性

UIElement基类还定义了大量的依赖属性。前面的章节中,在DependencyObject类中我们简单提到过依赖属性。在这里我们以UIElement基类的Visibility属性为例。

 
public Visibility Visibility { get; set; }
public static readonly DependencyProperty VisibilityProperty;

上面有两个成员,Visibility是普通的属性成员,VisibilityProperty是WPF的依赖属性成员,以Property结尾的字样作为WPF的依赖属性命名规则。而这两个成员合起来,才能被称为一个完整的依赖属性。这个Visibility 属性表示设置或获取控件的可见性。当我们要设置控件的可见性时,只需要如下设置即可。

 
<TextBlock Text="WPF中文网"
Visibility="Visible"
FontSize="48"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>

Visibility实际上是一个枚举,它包含3个值,分别是Visible、Hidden、Collapsed。其含义分别是显示、隐藏、彻底隐藏(不占布局位置)。

Visibility 状态会影响该元素的所有输入处理。 不可见的元素不会参与命中测试,也不会接收输入事件,即使鼠标位于元素可见时所在的边界上也是如此。

但是在这一节中,我们只是探讨UIElement基类提供了哪些方面的属性,并不详细探讨依赖属性,所以下面我们把目光聚焦到UIElement基类的常用属性上。另外由于WPF中几乎所有控件都继承了这个基类,意思就是说所有的控件都有这些属性可以使用。下面我在描述的时候将采用“控件”两字来解释一些技术细节。

Uid属性:获取或设置控件的唯一标识符,像人们的身份证一样。这个值默认是string.Empty。

Visibility属性:获取或设置控件的可见性。默认是Visible。

ClipToBounds属性:如果该值为true,表示进行裁剪,以适配它的父控件。比如有时候我们外面有一个Panel,里面的控件尺寸太大,势必会“撑破”外面的父控件,为了布局美观,只好削足适履。

Clip属性:用于剪裁区域大小的几何图形。需要注意的是,这个属性和上面的ClipToBounds属性是有区别的。ClipToBounds是裁剪控件自身,Clip是裁剪控件里面的内容。比如Image图像控件,我们在显示一张图时,就可以运用Clip进行裁剪后显示,通常在显示用户头像时裁剪成圆形时使用。如下所示

<Image 
  Source="sampleImages\Waterlilies.jpg" 
  Width="200" Height="150" HorizontalAlignment="Left">
  <Image.Clip>
    <EllipseGeometry
      RadiusX="100"
      RadiusY="75"
      Center="100,75"/>
  </Image.Clip>
</Image>
 

SnapsToDevicePixels属性:如果该值为true,表示控件的呈现是否应使用特定于设备的像素设置。意思是开启后可以最大限度的防锯齿效果,默认为false。

IsFocused属性:这是一个只读属性,表示当前控件是否有焦点。

IsEnabled属性:如果该值为true,表示禁用控件,反之启用控件。

IsHitTestVisible属性:获取或设置一个值,该值声明是否可以返回此元素作为其呈现内容的某些部分的点击测试结果。

IsVisible属性:这是一个只读属性,表示当前控件是否显示。

Focusable属性:如果该值为true,表示控件可以得到焦点,大部份内容控件都默认可以获得焦点。

IsKeyboardFocused属性:表示该控件是否具有键盘焦点。

IsMouseOver属性:表示鼠标是否在控件上面。通常在设计控件的样式(Style)时会用到。

IsStylusOver属性:表示触笔指针是否在控件的上方。

IsSealed属性:表示当前类型是否为只读类。

Opacity属性:设置控件的透明度,取值范围是0-1之间的double值。

OpacityMask属性:设置一个画笔,作为控件的蒙板。比如我们给一张图片设置一个掩码,就可以使用ImageBrush这种图片画笔来实现。

AllowDrop属性:表示控件是否允许拖拽操作。

RenderTransform属性:(非常重要)如果要设置控件的移动、缩放、旋转,需要这此属性进行设置。

总结

通过上述的代码分析,我们大致可以得出以下结论,UIElement基类为我们提供了一系列的鼠标、键盘和触摸事件,并提供了一些常用的依赖属性。它可以呈现继承它的所有控件,为控件布局时调整位置和大小,响应用户的输入,引发一系列的路由事件,并继承了IAnimatable动画接口,用于支持动画的某些方面。

FrameworkElement类

它是WPF控件的众多父类中最核心的基类,从这里开始,继承树开始分支,分别是Shape图形类、Control控件类和Panel布局类三个方向。

FrameworkElement类本质上也是提供了一系列属性、方法和事件。同时又扩展 UIElement 并添加了以下功能:

官方文档

1.布局系统定义: FrameworkElement 为中 UIElement定义为虚拟成员的某些方法提供特定的 WPF 框架级实现。 最值得注意的是, FrameworkElement 会密封某些 WPF 核心级布局替代,并改为提供派生类应替代的 WPF 框架级别的等效项。 例如,密封但 FrameworkElementArrangeCore 提供 ArrangeOverride。 这些更改反映了这样一个事实,即在 WPF 框架级别,有一个可以呈现任何 FrameworkElement 派生类的完整布局系统。 在 WPF 核心级别,将构建基于 WPF 的常规布局解决方案的某些成员已就位,但未定义布局系统的实际引擎。
2.逻辑树: 常规 WPF 编程模型通常以元素树的方式表示。 支持将元素树表示为逻辑树,以及支持在标记中定义该树的支持是在 级别实现的 FrameworkElement 。 但请注意, FrameworkElement 故意不定义内容模型,并将该责任留给派生类。
3.对象生存期事件: 了解何时初始化元素 (调用构造函数) 或首次将元素加载到逻辑树中时,这通常很有用。 FrameworkElement 定义多个与对象生存期相关的事件,这些事件为涉及元素的代码隐藏操作(例如添加更多子元素)提供有用的挂钩。
4.支持数据绑定和动态资源引用: 对数据绑定和资源的属性级支持由 DependencyProperty 类实现,并体现在属性系统中,但解析存储为 Expression (数据绑定和动态资源的编程构造) 中存储的成员值的能力由 FrameworkElement实现。
5.风格:FrameworkElement 定义 Style 属性。 但是, FrameworkElement 尚未定义对模板的支持或支持修饰器。 这些功能由控件类(如 和 ContentControl)Control引入。
6.更多动画支持: 某些动画支持已在 WPF 核心级别定义,但 FrameworkElement 通过实现 BeginStoryboard 和相关成员扩展了此支持。

属性分析

1.LayoutTransform 属性:获取或设置在执行布局时应应用于此元素的图形转换。这个属性与UIElement类中的RenderTransform属性有相似之处,所以我们在此将两者进行对比说明一下。两个属性都是Transform类型,而Transform是一个抽象类,这个类可以实现控件在平面中的各种转换,包括

  • 旋转 (System.Windows.Media.RotateTransform)
  • 缩放 (System.Windows.Media.ScaleTransform)、
  • 倾斜 (System.Windows.Media.SkewTransform) 、
  • 平移 (System.Windows.Media.TranslateTransform)。

虽然两个属性都可以达到控件的变换效果,但是两者还是有区别的。LayoutTransform属性是在控件布局之前对控件进行变换,而RenderTransform属性是在布局结束后执行控件的变换,LayoutTransform开销比RenderTransform要大,所以,尽量使用RenderTransform属性去实现控件的变换。(我们会在后面专门探讨控件的变换)

2.Width属性:这是表示控件的宽度。与之相关的还有以下几个属性。

  • ActualWidth:获取此元素的呈现宽度。只读属性。
  • MaxWidth:获取或设置一个控件的最大宽度。
  • MinWidth:获取或设置一个控件的最小宽度。

3.Height属性:这是表示控件的高度,与之相关的还有以下几个属性。

  • ActualHeight:获取此元素的呈现高度。只读属性。
  • MaxHeight:获取或设置一个控件的最大高度。
  • MinHeight:获取或设置一个控件的最小高度。

4.Tag属性:这个属性非常重要,它是object类型,意味着可以保存任意类型的对象值。它就像FrameworkElement类身上的一个小口袋,但确能容纳万物。我们通常会将一些与控件相关的数据临时存放在Tag属性中,当把控件作为参数传递时,小口袋里面的对象也随之传递过去了。

5.Name属性:获取或设置控件的标识名称。在同一个窗体、页、用户控件中,Name标识是唯一的。设置了控件的名称后,我们就可以在后端代码直接以这个标识去引用控件。

6.Margin属性:获取或设置控件的外边距。

Padding属性说明

与Margin相对应的是Padding,表示设置控件的内边距。但是这个属性并不在FrameworkElement中,而在Control类中,从本节第一张图所示,说明只有内容控件才具有Padding,而Shape和Panel是没有Padding属性的。

7.HorizontalAlignment属性:设置控件的水平对齐方式。这个对齐方式是相对于父元素而言的,比如我们有一个Button控件,在外面还包裹了一层Grid控件,那么,设置Button控件的HorizontalAlignment属性,可以将Button控件分别显示在Grid控件的左边、中间、右边三个位置。

8.VerticalAlignment属性:设置控件的垂直对齐方式。与HorizontalAlignment属性类似,只是对方的方向不同,可以设置控件在垂直方向上是居于顶部、中间、还是底部三个位置。

总结:上述两个属性的值都是枚举型,它们都有一个共同的值,那就是stretch,表示是拉伸的方式填充父元素的布局。

9.ToolTip属性:获取或设置用户界面 (UI) 中为此元素显示的工具提示对象。指鼠标移到控件上方时显示的提示内容,它是一个object类型,意味着可以显示任意布局外观。

10.Parent属性:获取此元素的逻辑父元素。它是一个只读属性。

接下来,我们将介绍几个比较重要的属性,这些属性是WPF框架中非常核心的知识概念.

WPF样式(Style)

11.Style属性:获取或设置此元素呈现时所使用的样式。与Style相关的还有一个属性,叫FocusVisualStyle,顾名思义,控件在获得焦点时的样式。

WPF资源(ResourceDictionary)

什么是资源?资源,也就是资源字典,也就是ResourceDictionary类,它提供一个哈希表/字典实现,其中包含组件所使用的 WPF 资源以及 WPF 应用程序的其他元素。我们可以把WPF的控件、窗体、Application应用所用到的一切资源都放在其中,将多个ResourceDictionary元素合并起来形成一个ResourceDictionary元素(ResourceDictionary也是一个隐式集合)。所以FrameworkElement类设计一个资源属性。

12.Resources 属性:获取或设置本地定义的资源字典。关于Resources资源我们会专门拿一章节来探讨)

WPF的数据上下文(DataContext)

假定我们有一个View窗体,窗体有一个TextBox控件;又假如我们还有一个ViewModel实体,这个实体中有一个叫Name的属性。如果我们要将TextBox控件的Text属性和ViewModel实体的Name属性成功的建立绑定关系,必备的条件是什么?

首先,由于View窗体继承于FrameworkElement类,所以每个窗体(或控件)都有一个叫DataContext的数据上下文属性。所以必备的条件是:ViewModel实体必须先赋值给View窗体的DataContext,ViewModel的Name属性才能绑定到TextBox控件的Text属性。换言之,领导之间要先搭好桥,下属和下属才好配合工作。这就是DataContext的概念和用途。

13.DataContext属性:获取或设置元素参与数据绑定时的数据上下文。

14.ContextMenu属性:设置与获取控件的上下文菜单 ,就是鼠标在控件上右键时弹出来的菜单。

15.Cursor属性:获取或设置在鼠标指针位于此元素上时显示的光标。

事件分析

FrameworkElement类提供了12个事件,一般比较常用的是:Initialized、Loaded、Unloaded、SizeChanged等事件。

1.FindName(String):表示查找某个元素。比如我们在窗体中要查找某个控件。

2.FindResource(Object):查找某个资源。如果在调用对象上找不到该资源,则接下来搜索逻辑树中的父元素,然后搜索应用程序、主题,最后搜索系统资源。实在找不到就抛出异常。

3.TryFindResource(Object):尝试去找某个资源。建议使用这个方法。

4.RegisterName (string , object );注册控件的名称到父控件上。

5.SetBinding(DependencyProperty, BindingBase)和SetBinding(DependencyProperty, String),这两个成员都和绑定相关,我们将在后面做专题介绍。

布局控件概述

控件名称布局方式
Grid网格,根据自定义行和列来设置控件的布局
StackPanel栈式面板,包含的元素在竖直或水平方向排成一条直线
WrapPanel自动折行面板,包含的元素在排满一行后,自动换行
DockPanel泊靠式面板,内部的元素可以选择泊靠方向
UniformGrid网格,UniformGrid就是Grid的简化版,每个单元格的大小相同。
Canvas画布,内部元素根据像素为单位绝对坐标进行定位
Border装饰的控件,此控件用于绘制边框及背景,在Border中只能有一个子控件

Panel基类

Panel其实是一个抽象类,不可以实例化,WPF所有的布局控件都从Panel继承而来

它有一个Background属性,意味着所有的布局控件都可以设置背景颜色。另外,它还有一个Children属性,这是一个集合属性,也就是说,所有的布局控件都可以添加多个子元素。这一点从它继承的IAddChild接口也能得到印证。

Panel提供了GetZIndex和SetZIndex方法成员,分别表示获取某个元素的ZIndex顺序和设置某个元素的ZIndex顺序。

什么是ZIndex?这是Panel提供的一个附加属性。假如一个单行单列的Grid布局控件中有两个Button,正常情况下,这两个Button都会以撑满Grid的方式呈现在Grid中,那么,到底哪一个Button在上面,哪一个Button在下面呢?就看这两个Button的Panel.ZIndex附加属性的值,值越大越在上面,而值较小的那个Button将被上面的Button遮盖,从而在视觉上,用户只能看到一个Button。

附加属性

附加属性的一个用途是允许子元素存储实际上由父元素定义的属性的唯一值。 此功能的一项应用是让子元素通知父级它们希望如何在用户界面 (UI) 中呈现,这对应用程序布局非常有用。
<Grid >
<Button Content="WPF中文网1" Panel.ZIndex="1" Margin="20 40 60 80" Padding="50" />
<Button Content="WPF中文网2" Panel.ZIndex="0" Margin="20 40 60 80" Padding="50" />
</Grid>

WPF 提供了一套全面的派生 Panel 实现,可实现许多复杂的布局。这里有一个非常非常需要注意的事项,那就是Panel的Background属性。有时候我们希望在布局控件上实现鼠标点击事件的获取,请记得一定要给Background属性设置一个颜色值,如果不希望有具体的颜色,那就设置成Transparent 。不然,您会踩坑的!因为布局控件的Background属性没有值时,是不能引发鼠标相关事件的

只要继承于UIElement的类(或控件),都可以添加到Panel或Panel子类的Children中,从而在前端呈现出来

一个Panel 的呈现就是测量和排列子控件,然后在屏幕上绘制它们。所以在布局的过程中会经过一系列的计算,那么子控件越多,执行的计算次数就越多,则性能就会变差。如果不需要进行复杂的布局,则尽量少用复杂布局控件(如 Grid和自定义复杂的Panel);如果能简单布局实现就尽量使用构造相对简单的布局(如 Canvas、UniformGrid等),这种布局可带来更好的性能。 如果有可能,我们应尽量避免调用 UpdateLayout方法。

布局系统为Panel中的每个子控件完成两个处理过程:测量处理过程(Measure)和排列处理过程(Arrange)。每个子 Panel 均提供自己的 MeasureOverride 和 ArrangeOverride 方法,以实现自己特定的布局行为。

Grid控件(网格布局)

Grid有两个非常关键的属性ColumnDefinitions和RowDefinitions,分别表示列的数量集合和行的数量集合。ColumnDefinitions集合中的元素类型是ColumnDefinition类,RowDefinitions集合中元素类型是RowDefinition类。默认的Gridr控件没有定义行数和列数,也就是说,Grid默认情况下,行数和列数都等于1,那么它就只有一个单元格。

//一行两列

<Grid >
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>

    </Grid.ColumnDefinitions>
    <Button Grid.Column="0" Content="WPF中文网1" Panel.ZIndex="1" Margin="20" Padding="50" />
    <Button Grid.Column="1" Content="WPF中文网2" Panel.ZIndex="0" Margin="20" Padding="50" />
</Grid>

//两行一列

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>

        </Grid.RowDefinitions>
        <Button Grid.Row="0" Content="WPF中文网1" Panel.ZIndex="1" Margin="20" Padding="50" />
        <Button Grid.Row="1" Content="WPF中文网2" Panel.ZIndex="0" Margin="20" Padding="50" />
    </Grid>

跨列排列:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Button Grid.Row="0" Grid.Column="0" Content="WPF中文网1" Panel.ZIndex="1" Margin="20" Grid.ColumnSpan="2"/>//跨2列
    <Button Grid.Row="1" Grid.Column="0" Content="WPF中文网3" Panel.ZIndex="1" Margin="20" />
    <Button Grid.Row="1" Grid.Column="1" Content="WPF中文网4" Panel.ZIndex="0" Margin="20" />
</Grid>

固定列宽:

我们只需要设置第一行ColumnDefinition的Width属性,让其宽度固定为120像素,那么第二列的宽度等于Grid的宽度减去120像素,其内部的Button宽度也随之自适应。这就是WPF布局自适应的好处。

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="120"/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Button Grid.Row="0" Grid.Column="0" Content="WPF中文网1" Panel.ZIndex="1" Margin="20" />
    <Button Grid.Row="0" Grid.Column="1" Content="WPF中文网2" Panel.ZIndex="0" Margin="20" />
    <Button Grid.Row="1" Grid.Column="0" Content="WPF中文网3" Panel.ZIndex="1" Margin="20" />
    <Button Grid.Row="1" Grid.Column="1" Content="WPF中文网4" Panel.ZIndex="0" Margin="20" />
</Grid>

调整行高和列宽

Grid控件的行高和列宽的设置十分丰富,了解它们的用法,有助于设计出更出色的布局。

名称说明
绝对设置尺寸使用设备无关单位准确地设置尺寸,就是给一个实际的数字,但通常将此值指定为整数(像素)。如:<ColumnDefinition Width="100"></ColumnDefinition>
自动设置尺寸值为Auto,实际作用就是取实际控件所需的最小值,每行和每列的尺寸刚好满足需要,这是最有用的尺寸设置方式。如:<ColumnDefinition Width="Auto"></ColumnDefinition>
按比例设置设置尺寸按比例将空间分割到一组行和列中。这是对所有行和列的标准设置。通常值为*或N*,实际作用就是取尽可能大的值,当某一列或行被定义为*则是尽可能大,当出现多列或行被定义为*则是代表几者之间按比例方设置尺寸。如:<ColumnDefinition Width="*"></ColumnDefinition>

指定权重,即第2列的宽度是第1列的两倍

<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="2*"></RowDefinition>

Grid显示网格线

<Grid ShowGridLines="True" Margin="5">

</Grid>

Border 是一个常用的控件,用于在界面上绘制一个矩形边框,通常用于装饰或分组其他控件。Border 控件可以包含一个子元素,并在该子元素周围绘制边框。

<Grid Margin="5">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="120"/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Border Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" Grid.ColumnSpan="2" BorderBrush="Gray" BorderThickness="1"/>
    <Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" BorderBrush="Gray" BorderThickness="0 0 0 1"/>
    <Border Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" BorderBrush="Gray" BorderThickness="0 0 1 0"/>
    <Button Grid.Row="0" Grid.Column="0" Content="WPF中文网1" Panel.ZIndex="1" Margin="20" />
    <Button Grid.Row="0" Grid.Column="1" Content="WPF中文网2" Panel.ZIndex="0" Margin="20" />
    <Button Grid.Row="1" Grid.Column="0" Content="WPF中文网3" Panel.ZIndex="1" Margin="20" />
    <Button Grid.Row="1" Grid.Column="1" Content="WPF中文网4" Panel.ZIndex="0" Margin="20" />
</Grid>

我们在Grid内部增加了3个Border,第一个Border用来显示外边框,第二个Border显示中间的横线,第三个Border显示中间的竖线,这时所用的知识点几乎都是Grid的跨行和跨列属性,另外还有边框颜色刷子BorderBrush和边框厚度BorderThickness。

*其他布局(待学)

Control基类

通常用于展示程序的数据或获取用户输入的数据,我们可以将这一类型的控件称为内容控件或数据控Control类虽然可以实例化,但是在界面上是不会有任何显示的。只有那些继承了Control的子类(控件)才会在界面上显示,Control类提供了一个控件模板(ControlTemplate),而几乎所有的子类都对这个ControlTemplate进行了各自的实现。

Control的Template定义了控件的外观,Control类的Template属性是ControlTemplate类型的。

<Window x:Class="HelloWorld.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:HelloWorld"
        mc:Ignorable="d"
        Title="HelloWorld - www.wpfsoft.com" Height="350" Width="500">
    <Control Margin="10">
        <Control.Template>
            <ControlTemplate TargetType="Control">
                <Border Background="LightBlue">
                    <TextBlock Text="WPF中文网" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Border>
            </ControlTemplate>
        </Control.Template>
    </Control>
</Window>

事件

在这一小节里,您只要能明白Template的概念就行了。除了这个属性,Control类还提供了两个事件,它们分别是PreviewMouseDoubleClick和MouseDoubleClick。

事件名称说明
PreviewMouseDoubleClick表示鼠标双击或多次单击时触发的事件
MouseDoubleClick表示鼠标双击或多次单击时触发的事件

以Preview开头的事件叫隧道事件或预览事件,而MouseDoubleClick没有以Preview开头,所以它叫冒泡事件。

*其他(待学)

数据绑定

数据绑定是在应用 UI 与其显示的数据之间建立连接的过程。 如果绑定具有正确的设置,并且数据提供适当的通知,则在数据更改其值时,绑定到该数据的元素会自动反映更改。 数据绑定还意味着,如果元素中数据的外部表示形式发生更改,则基础数据可以自动进行更新以反映更改。

这就是数据绑定!

图的左边是一个DependencyObject对象,表明它是一个依赖对象。那么,WPF控件是不是一个DependencyObject对象?是的,因为WPF所有的控件都继承了DependencyObject基类。

图的右边是一个普通的对象,所以这里标注成object类型。右边的对象表示绑定的数据源——也就是一个ViewModel。

DataContext数据上下文

DataContext是FrameworkElement基类的一个属性。其含义:获取或设置元素参与数据绑定时的数据上下文。通常情况下,我们把它设计成一个class——也就是所谓的ViewModel。

View负责数据的输入与输出;ViewModel负责业务逻辑;Model则表示程序中具体要处理的数据。所以,Model将作为属性存在于ViewModel中,而Model最终是要显示在Ul界面(View)上的,怎么办呢?将ViewModel赋值给View的DataContext(数据上下文)属性,View就可以引用ViewModel中的那些Model了。

总结:Model在ViewModel中,ViewModel在View的DataContext中,View引用Model。

WPF所有的控件(包括Window窗体)都有DataContext属性,因为它们都继承于FrameworkElement基类。

通常一个Window窗体中有很多控件,我们只需要给Window的DataContext赋值一个ViewModel,窗体中其它的控件的DataContext会共享Window的DataContext。

Model类

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
 
}

ViewModel类

public class MainViewModel
{
    public Person Person { get; set; }
 
    public MainViewModel()
    {
        Person = new Person
        {
            Name = "张三",
            Age = 50,
            Address = "居无定所",
        };
    }
}

DataContext属性赋值

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
 
        this.DataContext = new MainViewModel();
    }        
}

我们给MainWindow主窗体的DataContext赋值了一个叫MainViewModel的视图模型。而MainViewModel中有一个叫Person的属性,它就代表了程序运行中要处理的数据实体。

现在MainWindow的DataContext(数据上下文)有了一个对象后,我们怎么将这个Person属性显示到前端呢,这需要使用Binding——数据绑定。

Binding(绑定)

Binding类架起了控件和ViewModel之间的桥梁,它就像一个媒婆,指示了哪个控件的哪个属性与哪个ViewModel类的哪个属性建立绑定关系。提供对绑定定义的高级访问,该绑定连接绑定目标对象(通常为 WPF 元素)的属性和任何数据源(例如数据库、XML 文件,或包含数据的任何对象)。

第一种数据源

也就是ViewModel中的Model。在写法上直接如下所示:

Text="{Binding Person.Name}"

这里实例化了一个Binding对象,后面紧跟的Person.Name表示一个Path路径,指的是当前的DataContext中那个ViewModel对象的Person.Name,注意看,Binding的有一个带参数的构造函数:public Binding(string path);实际上,就是将Person.Name路径传给了path形参。

第二种数据源

指明某个具体的数据源对象及对象的属性。这种绑定方式要用了Binding类的Source属性和Path属性。通常写法如下:

Text="{Binding Source={StaticResource RedBrush},Path=Color}"

在这里,Source属性表示数据源对象,它是一个静态资源对象,Path=Color表示要绑定这个静态资源对象的Color属性。我们已经提前在资源里定义好了这个资源对象。资源对象的实例名叫RedBrush,它确实也有一个叫Color的属性。

<Window.Resources>
    <SolidColorBrush x:Key="RedBrush" Color="Red"/>
</Window.Resources>

这样绑定的效果如下图所示。

看起来Color=Red,实则是一个代表颜色的16进制字符串。

第三种数据源

利用ElementName属性指明另一个控件作为数据源,这里仍然要用到Path来指定另一个控件的某个属性路径。

<StackPanel x:Name="panel" VerticalAlignment="Center" Margin="100,0">
    <TextBlock Margin="5">
        <Run Text="Source示例:"/>
        <Run Text="{Binding Source={StaticResource RedBrush},Path=Color}"/>
    </TextBlock>
    <TextBlock Margin="5">
        <Run Text="ElementName示例:"/>
        <Run Text="{Binding ElementName=panel,Path=Margin}"/>
    </TextBlock>
</StackPanel>

通过Binding类的ElementName去指定当前XAML中的另一个StackPanel控件,并绑定其Margin属性,这样,TextBlock就显示了StackPanel控件的Margin属性值。

第四种数据源

利用RelativeSource属性绑定一个相对的数据源。这种绑定方式也经常使用,且实用价值很高,作为开发者,一定要掌握它的用法。

<StackPanel x:Name="panel" VerticalAlignment="Center" Margin="80,0">
    <TextBlock Margin="5">
        <Run Text="Source示例:"/>
        <Run Text="{Binding Source={StaticResource RedBrush},Path=Color}"/>
    </TextBlock>
    <TextBlock Margin="5">
        <Run Text="ElementName示例:"/>
        <Run Text="{Binding ElementName=panel,Path=Margin}"/>
    </TextBlock>
    <TextBlock Margin="5">
        <Run Text="RelativeSource示例:"/>
        <Run Text="{Binding RelativeSource={RelativeSource Mode=Self},Path=Foreground}"/>
        <Run Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=StackPanel},Path=Margin}"/>
    </TextBlock>    
</StackPanel>

RelativeSource类有3个重要的属性,它们分别是Mode、AncestorType和AncestorLevel。

Mode:表示寻找相对数据源的模式,一共有4种模式

模式说明
PreviousData允许在当前显示的数据项列表中绑定上一个数据项(不是包含数据项的控件)。
TemplatedParent引用应用了模板的元素,其中此模板中存在数据绑定元素。
Self引用正在其上设置绑定的元素,并允许你将该元素的一个属性绑定到同一元素的其他属性上。
FindAncestor引用数据绑定元素的父链中的上级。 这可用于绑定到特定类型的上级或其子类。

在上面的例子中,我们演示了Self(自身控件)和FindAncestor(找上级控件)两种模式。

AncestorType:当Mode=FindAncestor时,这时就要指示要找的这个上级是什么类型,AncestorType用来表示上级的类型。

AncestorLevel:获取或设置要查找的上级级别。 使用 1 指示最靠近绑定目标元素的项。

Text="{Binding RelativeSource={RelativeSource Mode=Self},Path=Foreground}"

表示将自己的前景色显示到Text属性上。

Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=StackPanel},Path=Margin}"

表示从当前控件开始找上级,一个类型为StackPanel的控件,并把这个StackPanel控件的Margin显示到当前控件的Text属性上。

Binding的绑定模式

当一个实体的属性绑定到控件的属性之后,还需要指明这两者之间的绑定关系。这个就是Binding类的Mode属性,Mode属性是一个枚举类型。它有如下几个情况。

枚举值说明
TwoWay双向绑定,即导致更改源属性或目标属性时自动更新另一方。
OneWay单向绑定,在更改绑定源(源)时更新绑定目标(目标)。
OneTime一次绑定,在应用程序启动或数据上下文更改时,更新绑定目标。
OneWayToSource在目标属性更改时,更新源属性。
Default默认绑定,文本框的默认绑定是双向的,而其他大多数属性默认为单向绑定。

这里面常用的是OneWay和TwoWay。如果是TwoWay(双向绑定),意味着前端控件的属性改变时,后端的Model也跟着改变,反之亦然。就拿前端改变去影响后端的Model值来说,这里会多出来一个概念——改变时机。

其实就是如果前端的值发生改变,后端的值在什么时候跟着改变。它由Binding类的UpdateSourceTrigger属性的值决定 。这个属性也是一个枚举类型。

枚举值说明
Default采用控件各自的UpdateSourceTrigger默认值。
PropertyChanged每当绑定目标属性发生更改时,都会更新绑定源。
LostFocus每当绑定目标元素失去焦点时,都会更新绑定源。
Explicit仅在调用 System.Windows.Data.BindingExpression.UpdateSource 方法时更新绑定源。

TextBox.Text 属性的默认值为 LostFocus,我们经常会把TextBox的UpdateSourceTrigger改成PropertyChanged,即文本框在输入内容时,实时的更新后端的Model属性值。

前端属性值发生改变后,由UpdateSourceTrigger决定什么时候更新后端的Model属性值,但是,后端那些Model的属性值发生改变后,前端什么时候跟着改变?需不需要做特殊的处理?

答案是需要!如果Model中的那些属性没有实现属性通知,就算前后端成功的建立了绑定关系,后端Model属性值改变时,前端的显示是没有变化的,如果要实时跟着变化,则需要掌握WPF的INotifyPropertyChanged接口以及属性通知的相关知识点。

INotifyPropertyChanged接口

通知客户端属性值已更改。

public interface INotifyPropertyChanged
{
    event PropertyChangedEventHandler PropertyChanged;
}

这个接口只有一个PropertyChanged事件,该事件专门用来触发属性更改通知。通常情况下,我们会单独编写一个服务类(例如ObservableObject),以实现INotifyPropertyChanged接口的业务。这样做的好处是,将来的ViewModel、Model都可以继承这个ObservableObject,从而调用属性通知接口。

一、实现INotifyPropertyChanged接口

public class ObservableObject : INotifyPropertyChanged
{public event PropertyChangedEventHandler PropertyChanged;public void RaisePropertyChanged([CallerMemberName] string propertyName = ""){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}
}

使用了CallerMemberName特性后,就不必再传入属性名字符串。

接下来,我们来编写一个ViewModel和一个Model,让它们都继承这个属性通知基类。

Person实体

public class Person : ObservableObject
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value;RaisePropertyChanged(); }
    }
 
    private int age;
    public int Age
    {
        get { return age; }
        set { age = value; RaisePropertyChanged(); }
    }
 
    private string address;
    public string Address
    {
        get { return address; }
        set { address = value; RaisePropertyChanged(); }
    }
}

MainViewModel实体

public class MainViewModel : ObservableObject
{
    private Person person;
    public Person Person
    {
        get { return person; }
        set { person = value; RaisePropertyChanged(); }
    }
 
    public MainViewModel()
    {
        person = new Person
        {
            Name = "张三",
            Age = 50,
            Address = "居无定所",
        };
    }
}

 <StackPanel Orientation="Horizontal">
            <TextBlock Text="姓名:" Margin="5"/>
            <TextBox Text="{Binding Person.Name,UpdateSourceTrigger=PropertyChanged}" Width="200" Height="25"/>
        </StackPanel>

除了INotifyPropertyChanged接口可以实现属性通知,还有一个接口也可以实现属性通知,它就是INotifyCollectionChanged。它的作用是:当添加和删除项或清除整个列表时,向侦听器通知动态更改。也就是说,它是专门来解决集合的元素数量发生变化时的通知问题的。我们在下一节来演示它的用法。

ObservableCollection泛型集合

表示一个动态数据集合,它可在添加、删除项目或刷新整个列表时提供通知。

 <ListView ItemsSource="{Binding Persons}" SelectedItem="{Binding Person}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="姓名" DisplayMemberBinding="{Binding Name}" Width="60"/>
                    <GridViewColumn Header="年龄" DisplayMemberBinding="{Binding Age}" Width="auto"/>
                    <GridViewColumn Header="地址" DisplayMemberBinding="{Binding Address}" Width="auto"/>
                </GridView>
            </ListView.View>
        </ListView>

 public class MainViewModel : ObservableObject
    {
        private Person person;
        public Person Person
        {
            get { return person; }
            set { person = value; RaisePropertyChanged(); }
        }
 
        public ObservableCollection<Person> Persons { get; set; } = new ObservableCollection<Person>();
        public MainViewModel()
        {
        }
    }

ValidationRule验证规则

ValidationRule是一个抽象类,提供创建自定义规则的一个方式,旨在检查用户输入的有效性。所以,我们要验证前端输入的各项数据的有效性时,需要自己定义各自的验证规则。

在数据绑定时,Binding类有一个ValidationRules属性,这个属性专门用来存放开发者自定义的验证规则。

例如,我们假定用户名的长度必须在1-10个字符之间,且用户的年龄在1-100之前,那么就可以围绕这两个条件自定义两个不同的验证规则,它们定义如下:

用户名验证规则

public class NameValidationRule : ValidationRule
{public override ValidationResult Validate(object value, CultureInfo cultureInfo){if (value != null && value.ToString().Length > 1 && value.ToString().Length <= 10){return new ValidationResult(true, "通过");}return new ValidationResult(false, "用户名长度1-10个字符");}
}

年龄验证规则

public class AgeValidationRule : ValidationRule
{public override ValidationResult Validate(object value, CultureInfo cultureInfo){double myValue = 0;if (double.TryParse(value.ToString(), out myValue)){if (myValue >= 1 && myValue <= 100){return new ValidationResult(true, null);}}return new ValidationResult(false, "请输入 1 至 100的年龄");}
}

在XAML前端代码中,TextBox输入框分别绑定了用户名和年龄,它们在绑定时如何调用验证规则呢?

<StackPanel Orientation="Horizontal">
    <TextBlock Text="姓名:" Margin="5"/>
    <TextBox Width="145" Height="25">
        <TextBox.Text>
            <Binding Path="Person.Name" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <local:NameValidationRule ValidatesOnTargetUpdated="True" />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
        <Validation.ErrorTemplate>
            <ControlTemplate>
                <DockPanel>
                    <Grid DockPanel.Dock="Right" Width="auto" Height="auto" VerticalAlignment="Center" Margin="3 0 0 0">
                        <TextBlock Width="auto" Height="auto" Foreground="Red"
                                 Text="{Binding ElementName=AdornedElementPlaceholder, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"/>
                    </Grid>
                    <Border BorderBrush="Red" BorderThickness="0" CornerRadius="2">
                        <AdornedElementPlaceholder x:Name="AdornedElementPlaceholder"/>
                    </Border>
                </DockPanel>
            </ControlTemplate>
        </Validation.ErrorTemplate>
    </TextBox>
</StackPanel>

ValidationRule会把验证结果保存在AdornedElementPlaceholder的AdornedElement属性中,所以,需要利用绑定的方法去绑定下面这个路径。

相关文章:

C# wpf

学习网址&#xff1a;控件的父类们 - WPF中文网 - 从小白到大佬 控件的父类&#xff1a; 由此我们可以得出结论&#xff0c;控件的父类们(准确的说&#xff0c;应该叫父类的父类的父类)&#xff0c;至少有如下几个类型&#xff1a; DispatcherObjectDependencyObjectVisualU…...

十一、引用与拷贝函数(References the Copy-Constructor)

十一、引用与拷贝函数&#xff08;References & the Copy-Constructor&#xff09; 11.1 指针回顾&#xff08;Review of pointers&#xff09; 指针可以保存一个地址。 当你定义一个指针时&#xff0c;必须指定它所指向变量的类型&#xff0c;并且应该初始化它。 示例&a…...

数据结构之顺序表

目录 1.线性表 1.1 线性表的定义&#xff1a;零个或多个数据元素的有限序列。 1.2深度解析 1.3 线性表的抽象数据类型 2.顺序表 2.1 顺序表的定义和存储方式 2.2静态顺序表 2.2.1 静态顺序表的使用 2.2.3 为什么我们要使用typedef呢&#xff1f; 2.2.4 为什么我们要使…...

【计算机视觉】三种图像质量评价指标详解:PSNR、SSIM与SAM

图像质量评价指标详解&#xff1a;PSNR、SSIM与SAM 文章目录 图像质量评价指标详解&#xff1a;PSNR、SSIM与SAM1. 峰值信噪比(PSNR)1.1 数学定义1.2 特点与局限性 2. 结构相似性指数(SSIM)2.1 数学定义2.2 特点与应用 3. 光谱角度映射器(SAM)3.1 数学定义3.2 特点与应用 4. Py…...

轻舟系列FPGA加速卡:大模型分布式训练中的高效协同者

在超大规模模型&#xff08;如千亿级参数&#xff09;的分布式训练中&#xff0c;计算、存储与通信的协同优化是突破性能瓶颈的关键。绿算技术公司的轻舟系列FPGA加速卡凭借其低延迟、高能效和可编程特性&#xff0c;能够成为分布式训练架构中的异构加速节点。其在训练集群中的…...

C++20 小语法

这个提案允许在static_assert和if constexpr中从整形转换为布尔类型。 以下表格就可以表示所有内容。 对于严格的C 编译器来说&#xff0c;以前在这种情境下int无法向下转换为bool&#xff0c;需要手动强制转换&#xff0c; C23 这一情况得到了改善。 对于严格的C编译器来说&a…...

LM393比较器的比较翻转电压不对

问个问题&#xff0c;用的LM393比较器&#xff0c;3.3V供电&#xff0c;比较器输出上拉到3.3V&#xff0c; V给的基准2.8V&#xff0c;V-电压从1V升到2.3V&#xff0c;比较器就输出0V了&#xff0c;按理论超过2.8V才翻转到0V的 根据问题描述和电路分析&#xff0c;比较器LM393…...

解决 shadui组件库Popover 点击后会消失

react用了shadui组件库 <Popover><PopoverTrigger><div className"text-operation-item" onClick{props.callback}><img src{props.imgSrc} width{20} height{20} /></div></PopoverTrigger><PopoverContent className"…...

国联股份卫多多与北京慧闻科技(集团)签署战略合作协议

4月27日&#xff0c;北京慧闻科技&#xff08;集团&#xff09;有限公司&#xff08;以下简称“慧闻科技”&#xff09;销售总监王兴卓一行到访国联股份卫多多&#xff0c;同卫多多/纸多多副总裁、产发部总经理段任飞&#xff0c;卫多多机器人产业链总经理桂林展开深入交流&…...

从数据到决策:如何使用Python进行自动驾驶数据分析

从数据到决策:如何使用Python进行自动驾驶数据分析 大家好,我是Echo_Wish,今天来和大家聊一聊在自动驾驶领域中,如何通过Python进行数据分析。随着自动驾驶技术的不断发展,数据分析在这一领域的作用越来越重要。从传感器数据的处理到模型的训练和优化,Python在自动驾驶数…...

IIS服务器提示ERR_HTTP2 PROTOCOL ERROR解决方案

今天我的淘宝店来了一个客户&#xff0c;说小程序苹果访问没问题&#xff0c;安卓系统访问出现ERR HTTP2 PROTOCAL ERROR的错误见下图 方法供大家闭坑步骤&#xff1a;通过注册表修改(高级) 打开注册表编辑器 (regedit) 导航到&#xff1a; HKEY_LOCAL_MACHINE\SYSTEM\Current…...

Django的异步任务队列管理_Celery

1 基本原理 Celery 是一个异步任务队列&#xff0c;能够将耗时操作&#xff08;如发邮件、处理图片、网络爬虫等&#xff09;从 Django 主线程中分离出来&#xff0c;由后台的 worker 处理&#xff0c;避免阻塞请求。Celery 作为独立运行的后台进程&#xff08;Worker&#xf…...

Ubuntu18.04安装IntelliJ IDEA2025步骤

1.下载linux版本的idea 复制下面链接到虚拟机浏览器 下载 IntelliJ IDEA 下载好后&#xff0c;你的文件里会多一个文件&#xff0c;如下图 2.解压并运行Idea 2.1在/usr/local/路径下新建安装目录IDEA&#xff1a; 打开终端输入以下命令&#xff1a; sudo mkdir -p /usr/loc…...

LLM - Large Language Model

回顾2024&#xff1a;与LLM又相伴一年的经历与思考 - 知乎万字长文入门大语言模型&#xff08;LLM&#xff09; - 知乎“大模型本质就是两个文件&#xff01;”特斯拉前AI总监爆火LLM科普&#xff0c;时长1小时&#xff0c;面向普通大众 - 知乎大模型本质及趋势剖析&#xff0c…...

解决Ubuntu20.04重启出现显卡驱动异常的问题(操作记录)

一、问题情况 电脑异常断电&#xff0c;重启后&#xff0c;显示界面异常&#xff0c;显卡驱动已丢失。 二、操作流程 1、查看安装显卡驱动 ls /usr/src | grep nvidia 记住该驱动&#xff0c;我的是nvidia-550.127.05 2、安装dkms&#xff08;如果没有&#xff09; sudo …...

23.开关电源干扰控制的EMC改善措施

开关电源干扰控制的EMC改善措施 1. 开关电源的EMI干扰机理2. 钳位抑制EMI3. 阻容吸收抑制EMI4. 波形整形抑制EMI 1. 开关电源的EMI干扰机理 2. 钳位抑制EMI 只能抑制Ts阶段。 3. 阻容吸收抑制EMI 4. 波形整形抑制EMI...

新能源汽车声纹监测技术的发展趋势是什么?

新能源汽车声纹监测技术有以下发展趋势&#xff1a; 智能化与自动化程度不断提高 故障自动诊断与预警&#xff1a;未来声纹监测系统将能够更加准确地自动识别和分析新能源汽车各部件的声纹特征变化&#xff0c;不仅能检测出故障&#xff0c;还能对故障的发展趋势进行预测&…...

如何获取按关键字搜索京东商品详情(代码示例)

在电商领域&#xff0c;获取京东商品的详细信息对于市场分析、选品上架、库存管理和价格策略制定等方面至关重要。京东作为国内知名的电商平台&#xff0c;提供了丰富的商品资源。通过 Python 爬虫技术&#xff0c;我们可以高效地获取京东商品的详细信息&#xff0c;包括商品名…...

C#中构造器及属性的加载顺序

一.基本原则: 先加载静态构造函数和静态字段,后加载普通构造函数和普通字段;先加载基类再加载子类; 二.具体的加载顺序: 父类静态字段--->父类静态构造函数--->子类静态字段--->子类静态构造函数--->父类实例字段---> 父类实例构造函数--->子类实例字段-…...

vue项目中如何使用markdown编辑器

在开发中,编辑markdown和回显markdown都是常见的需求。在vue(2.x和3.x都可以)中可以使用mavon-editor这个第三方依赖包。示例很简单易懂。 安装 npm install mavon-editor 注册 在main.js中注册这个组件 import Vue from vue import mavonEditor from mavon-editor impor…...

Python爬虫(9)Python数据存储实战:基于pymysql的MySQL数据库操作详解

目录 一、背景与核心价值二、pymysql核心操作详解2.1 环境准备2.2 数据库连接与基础操作2.3 事务处理与错误回滚2.4 高级功能&#xff1a;批量插入与性能优化 三、pymysql进阶技巧3.1 连接池管理&#xff08;推荐使用DBUtils&#xff09;3.2 SQL注入防御3.3 与ORM框架对比 四、…...

WPF之Button控件详解

文章目录 1. 引言2. Button控件基础Button类定义 3. Button控件的核心属性3.1 Content属性3.2 IsDefault属性3.3 IsCancel属性3.4 其他常用属性 4. 按钮样式与模板自定义4.1 简单样式设置4.2 使用Style对象4.3 触发器使用4.4 使用ControlTemplate完全自定义4.5 按钮视觉状态 5.…...

如何查看电脑电池使用情况

第一步打开cmd&#xff1a; 在键盘上按下winr 或者在搜索框中输入cmd 点击命令提示符 进入命令框 第二步输入命令&#xff1a; powercfg/batteryreport 出现如下情况 第三部找到对应电池报告进行查看&#xff1a; 在对应路径下找到电池报告 点击battery-report.html 到此…...

软考-软件设计师中级备考 6、数据结构 图

1. 有向图 有向图是由顶点集合 V 和有向边集合 E 组成的图结构。在有向图中&#xff0c;边是有方向的&#xff0c;即从一个顶点指向另一个顶点&#xff0c;通常用有序对 (u, v) 表示&#xff0c;其中 u 是边的起始顶点&#xff0c;v 是边的终止顶点。例如&#xff0c;在一个表…...

Label Studio 软件介绍及安装使用说明

背景说明 在做AI项目建模的时候&#xff0c;往往需要数据标注工作&#xff0c;比较常用的数据标注软件是Labeling或者Labelme,这两个都是离线的单独标注软件&#xff0c;使用起来是比较方便的&#xff0c;也是入门级学者比较适合的软件&#xff0c;然而有时候我们数据标注的数据…...

Azure 数字孪生是什么?

“Azure 数字孪生”是一项平台即服务 (PaaS) 产品/服务&#xff0c;它能够创建基于整个环境的数字模型的孪生图&#xff0c;这些图可能是建筑物、工厂、农场、能源网络、铁路、体育场馆&#xff0c;甚至整个城市。 这些数字模型可用于获取洞察力&#xff0c;以推动产品改进、运…...

界面控件DevExpress WPF v25.1预览 - AI功能增强(语义搜索)

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…...

【神经网络与深度学习】五折交叉验证(5-Fold Cross-Validation)

引言 五折交叉验证&#xff08;5-Fold Cross-Validation&#xff09;是一种广泛应用于机器学习模型性能评估的技术&#xff0c;通过多次实验确保模型的评估结果更加稳定、可靠&#xff0c;同时最大限度地利用有限的数据资源。它将数据分成若干子集&#xff0c;交替作为训练集和…...

Linux权限概念讲解

1. 用户类型 1.1 用户分类 在Linux里面用户分为两类&#xff0c;一种是超级用户&#xff08;root&#xff09;&#xff0c;一种是普通用户。 超级用户只有一个&#xff0c;而普通用户可以有很多个。 如果我们在root用户状态下想要变成普通用户&#xff0c;我们可以使用命令…...

网络安全零基础培训 L1-8 PHP基础语法

文章目录 1 认识PHP1.1 PHP简介1.2 主要的特点1.3 跨平台性1.4 与数据库的良好集成1.5 开源和社区支持1.6 应用场景1.6.1 网站开发1.6.2 内容的管理程序1.6.3 Web应用程序开发1.6.4 为什么学习了解PHP 2 PHP的基础语法2.1 创建第一个PHP程序2.2 如何写注释2.3 PHP的变量2.4 PHP…...

鸿蒙 长列表加载性能优化

长列表加载性能优化 针对长列表加载这一场景&#xff0c;对列表渲染时间、页面滑动帧率、应用内存占用等方面带来优化&#xff0c;提升性能和用户体验的手段有如下 4 种&#xff1a; 懒加载&#xff1a;提供列表数据按需加载能力&#xff0c;解决一次性加载长列表数据耗时长、…...

第十二届蓝桥杯 2021 C/C++组 卡片

目录 题目&#xff1a; 题目描述&#xff1a; 题目链接&#xff1a; 思路&#xff1a; 思路详解&#xff1a; 代码&#xff1a; 代码详解&#xff1a; 题目&#xff1a; 题目描述&#xff1a; 题目链接&#xff1a; 卡片 - 蓝桥云课 思路&#xff1a; 思路详解&#…...

vscode 使用gitcode团队管理项目

1、下载安装vscode https://code.visualstudio.com/Download 2、安装git 3、在vscode中安装GitLens插件 4、打开终端 点击会显示当前更改的项目 5、提交更改的文件&#xff0c;会提示输入用户名、密码&#xff0c;这里的密码即是令牌&#xff0c;令牌在第一次创建的时候显…...

uniapp+vue3+ts 使用canvas实现安卓端、ios端及微信小程序端二维码生成及下载

加粗样式uniapp多端生成带二维码海报并保存至相册的实现 在微信小程序开发中&#xff0c;我们常常会遇到生成带有二维码的海报并保存到手机相册的需求&#xff0c;比如分享活动海报、产品宣传海报等。今天就来和大家分享一下如何通过代码实现这一功能。 准备工作 在开始之前&am…...

vue mixin混入与hook

mixin混入是 ‌选项式 API‌&#xff0c;在vue3-Composition API <script setup> 中无法直接使用&#xff0c;需通过 setup() 函数转换 vue2、vue3选项式API: // mixins/mixin.js export const mixin {methods: {courseType(courseLevel) {const levelMap {1: 初级,…...

《Masked Autoencoders Are Scalable Vision Learners》---CV版的BERT

目录 一、与之前阅读文章的关系&#xff1f; 二、标题&#xff1a;带掩码的自auto编码器是一个可拓展的视觉学习器 三、摘要 四、核心图 五、结果图 六、不同mask比例对比图 七、“Introduction” (He 等, 2021, p. 1) 引言 八、“Related Work” (He 等, 2021, p. 3)相…...

(云计算HCIP)HCIP全笔记(十三)本篇介绍虚拟化技术,内容包含:虚拟化资源、虚拟化过程、I/O虚拟化、虚拟化架构KVM和Xen介绍、主流虚拟化技术介绍

1. 虚拟化资源 1.1 虚拟化对象 CPU虚拟化&#xff1a; 目标是使虚拟机上的指令能被正常执行&#xff0c;且效率接近物理机 内存虚拟化&#xff1a; 目标是能做好虚拟机内存空间之 间的隔离&#xff0c;使每个虚拟机都认为自己拥有了整个内存地址&#xff0c;且效率页能接近物理…...

C++核心编程:类与对象全面解析

C核心编程&#xff1a;类与对象全面解析 大家好&#xff01;今天我要和大家深入探讨C面向对象编程中最核心的概念&#xff1a;类与对象。&#x1f468;‍&#x1f4bb; 这是我们迈向高级C开发的第一步&#xff0c;掌握好这部分内容&#xff0c;对未来学习更高级的设计模式和框…...

Linux基础命令和文件系统结构:从入门到实践

目录 1. 引言 2. Linux文件系统结构概述 2.1 根目录 ​编辑 2.2 常见目录介绍&#xff1a; 1. /home&#xff1a;用户的家目录 2. /etc&#xff1a;存放配置文件的目录 3. /var&#xff1a;可变数据 4. /bin 和 /sbin&#xff1a;常见命令和系统管理工具 5. /tmp&…...

「Mac畅玩AIGC与多模态05」部署篇03 - 在 Mac 上部署本地向量化模型(Embedding Models)

一、概述 本篇介绍如何在 macOS 环境下,为 Dify 平台部署本地向量化模型(Embedding Models),支持知识库文档向量化、语义检索与智能体上下文增强。向量化模型是实现知识库问答与 RAG(检索增强生成)应用的基础组件。 二、部署流程 1. 环境准备 确认 Docker Desktop 正常…...

Java-Optional类

介绍 Optional是 Java 8 引入的一个类&#xff0c;用于解决空指针异常问题。它本质上是一个容器类&#xff0c;可以包含或不包含一个非空值。 示例 创建Optional对象 Optional.of(T value)&#xff1a;创建一个包含非空值的Optional对象。如传入null值&#xff0c;会抛出Nu…...

Android 热点开发调试总结

Android 热点开发调试总结 文章目录 Android 热点开发调试总结一、前言二、热点开发1、开关和默认配置wifi和热点配置信息保存的位置&#xff1a; 2、主要流程3、相关日志4、相关广播5、demo示例 三、其他1、Android 热点开发调试小结2、其他热点相关知识小结&#xff08;1&…...

【“星瑞” O6 评测】 — llm CPU部署对比高通骁龙CPU

前言 随着大模型应用场景的不断拓展&#xff0c;arm cpu 凭借其独特优势在大模型推理领域的重要性日益凸显。它在性能、功耗、架构适配等多方面发挥关键作用&#xff0c;推动大模型在不同场景落地 1. CPU对比 星睿 O6 CPU 采用 Armv9 架构&#xff0c;集成了 Armv9 CPU 核心…...

快乐数(双指针解法)

题目链接202. 快乐数 - 力扣&#xff08;LeetCode&#xff09; 题目拆解 1 取一个正整数每一位的平方和为&#xff0c;如果为1那么直接可以判定为快乐数&#xff0c;如果不为1&#xff0c;就重复这个过程&#xff0c;直到出现1 2 实际上&#xff0c;这道题只有两种情况&#xf…...

【Vue3-Bug】中路由加载页面直接显示空白

Vue3中路由加载页面直接显示空白 没有子路由 路由定义不能重复&#xff0c;请自己查看数据在main.js(或者)mina.ts入口文件中&#xff0c;需要将router的注入到vue中的执行放在&#xff0c;vue挂在元素之前 // 顺序不能变 app.use(router) app.mount(#app)在App.vue中 // 在…...

线性代数——行列式⭐

目录 一、行列式的定义⭐ 1-1、三阶行列式练习 1-2、下面介绍下三角行列式、上三角行列式、对角行列式 ​编辑 二、行列式的性质 2-1、性质1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6 ​编辑 2-2、性质7 2- 3、拉普拉斯定理、克莱姆法则 三…...

flume----初步安装与配置

目录标题 **flume的简单介绍**⭐flume的**核心组件**⭐**核心特点** **安装部署**1&#xff09;**解压安装包**2&#xff09;**修改名字** **&#xff08;配置文件时&#xff0c;更方便&#xff09;****3&#xff09;⭐⭐配置文件**4&#xff09;**兼容Hadoop**5&#xff09;**…...

vscode源代码管理Tab-文件右侧标志(M、A 等)的含义

Git 常用标志(M、A 等)的含义 在 VSCode 的源代码管理&#xff08;Source Control&#xff09;标签页中&#xff0c;文件右侧显示的 Monaco 装饰徽章&#xff08;Badge&#xff09;&#xff08;如 M、A 等&#xff09;&#xff0c;本质上是对 Git 文件状态标志 的可视化呈现。…...

【力扣刷题实战】丢失的数字

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 力扣题目&#xff1a;丢失的数字 题目描述 解题思路 问题理解 算法选择 具体思路 解题要点 完整代码&#xff08;C&#xff09; 兄弟们共勉 &#xff01;&#xff01;&#xff01; 每篇前言 博客主页&#xff1a;小…...

具身智能机器人的应用场景及最新进展

具身智能机器人正通过“感知-学习-决策-行动”的闭环能力&#xff0c;重塑全球各行业的生产与服务模式。以下是其在当今世界的典型应用场景及最新进展&#xff1a; 一、工业制造&#xff1a;柔性生产与智能运维 高精度装配与检测 特斯拉Optimus通过双目视觉与惯性测量单元&…...