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类本质上也是提供了一系列属性、方法和事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值